Skip to content

Commit

Permalink
Merge branch 'DateTime'
Browse files Browse the repository at this point in the history
Fixes: #161.
  • Loading branch information
phdru committed Dec 12, 2020
2 parents 3635f44 + e7b379f commit a591c0b
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 55 deletions.
3 changes: 3 additions & 0 deletions devscripts/requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
--install-option=-O2

# DateTime from Zope
DateTime

FormEncode >= 1.1.1, != 1.3.0; python_version >= '2.7' and python_version < '3.0'
FormEncode >= 1.3.1; python_version >= '3.4'
PyDispatcher >= 2.0.4
5 changes: 5 additions & 0 deletions docs/News.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ Features
json.dumps/loads. A subclass of StringCol. Requires ``VARCHAR``/``TEXT``
columns at backends, doesn't work with ``JSON`` columns.

* Extend/fix support for ``DateTime`` from ``Zope``.

* Drop support for very old version of ``mxDateTime``
without ``mx.`` namespace.

CI
--

Expand Down
160 changes: 130 additions & 30 deletions sqlobject/col.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,36 +44,40 @@
datetime_available = True

try:
from mx import DateTime
from mx import DateTime as mxDateTime
except ImportError:
try:
# old version of mxDateTime,
# or Zope's Version if we're running with Zope
import DateTime
except ImportError:
mxdatetime_available = False
else:
mxdatetime_available = True
mxdatetime_available = False
else:
mxdatetime_available = True

try:
# DateTime from Zope
import DateTime as zopeDateTime
except ImportError:
zope_datetime_available = False
else:
zope_datetime_available = True

DATETIME_IMPLEMENTATION = "datetime"
MXDATETIME_IMPLEMENTATION = "mxDateTime"
ZOPE_DATETIME_IMPLEMENTATION = "zopeDateTime"

if mxdatetime_available:
if hasattr(DateTime, "Time"):
DateTimeType = type(DateTime.now())
TimeType = type(DateTime.Time())
else: # Zope
DateTimeType = type(DateTime.DateTime())
TimeType = type(DateTime.DateTime.Time(DateTime.DateTime()))
if mxdatetime_available and hasattr(mxDateTime, "Time"):
mxDateTimeType = type(mxDateTime.now())
mxTimeType = type(mxDateTime.Time())

if zope_datetime_available:
zopeDateTimeType = type(zopeDateTime.DateTime())

__all__ = ["datetime_available", "mxdatetime_available",
"default_datetime_implementation", "DATETIME_IMPLEMENTATION"]

if mxdatetime_available:
__all__.append("MXDATETIME_IMPLEMENTATION")

if zope_datetime_available:
__all__.append("ZOPE_DATETIME_IMPLEMENTATION")

default_datetime_implementation = DATETIME_IMPLEMENTATION

if not PY2:
Expand Down Expand Up @@ -1256,7 +1260,7 @@ def to_python(self, value, state):
datetime.time, sqlbuilder.SQLExpression)):
return value
if mxdatetime_available:
if isinstance(value, DateTimeType):
if isinstance(value, mxDateTimeType):
# convert mxDateTime instance to datetime
if (self.format.find("%H") >= 0) or \
(self.format.find("%T")) >= 0:
Expand All @@ -1266,13 +1270,23 @@ def to_python(self, value, state):
int(value.second))
else:
return datetime.date(value.year, value.month, value.day)
elif isinstance(value, TimeType):
elif isinstance(value, mxTimeType):
# convert mxTime instance to time
if self.format.find("%d") >= 0:
return datetime.timedelta(seconds=value.seconds)
else:
return datetime.time(value.hour, value.minute,
int(value.second))
if zope_datetime_available:
if isinstance(value, zopeDateTimeType):
# convert zopeDateTime instance to datetime
if (self.format.find("%H") >= 0) or \
(self.format.find("%T")) >= 0:
return datetime.datetime(
value.year(), value.month(), value.day(),
value.hour(), value.minute(), int(value.second()))
else:
return datetime.date(value.year, value.month, value.day)
try:
if self.format.find(".%f") >= 0:
if '.' in value:
Expand Down Expand Up @@ -1314,23 +1328,30 @@ def to_python(self, value, state):
if value is None:
return None
if isinstance(value,
(DateTimeType, TimeType, sqlbuilder.SQLExpression)):
(mxDateTimeType, mxTimeType,
sqlbuilder.SQLExpression)):
return value
if isinstance(value, datetime.datetime):
return DateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute,
value.second)
return mxDateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute,
value.second)
elif isinstance(value, datetime.date):
return DateTime.Date(value.year, value.month, value.day)
return mxDateTime.Date(value.year, value.month, value.day)
elif isinstance(value, datetime.time):
return DateTime.Time(value.hour, value.minute, value.second)
return mxDateTime.Time(value.hour, value.minute, value.second)
elif isinstance(value, datetime.timedelta):
if value.days:
raise validators.Invalid(
"the value for the TimeCol '%s' must has days=0, "
"it has days=%d" % (self.name, value.days),
value, state)
return DateTime.Time(seconds=value.seconds)
return mxDateTime.Time(seconds=value.seconds)
if zope_datetime_available:
if isinstance(value, zopeDateTimeType):
# convert zopeDateTime instance to mxdatetime
return mxDateTime.DateTime(
value.year(), value.month(), value.day(),
value.hour(), value.minute(), int(value.second()))
try:
if self.format.find(".%f") >= 0:
if '.' in value:
Expand All @@ -1346,9 +1367,9 @@ def to_python(self, value, state):
else:
value += '.0'
value = datetime.datetime.strptime(value, self.format)
return DateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute,
value.second)
return mxDateTime.DateTime(value.year, value.month, value.day,
value.hour, value.minute,
value.second)
except Exception:
raise validators.Invalid(
"expected a date/time string of the '%s' format "
Expand All @@ -1360,7 +1381,8 @@ def from_python(self, value, state):
if value is None:
return None
if isinstance(value,
(DateTimeType, TimeType, sqlbuilder.SQLExpression)):
(mxDateTimeType, mxTimeType,
sqlbuilder.SQLExpression)):
return value
if hasattr(value, "strftime"):
return value.strftime(self.format)
Expand All @@ -1370,6 +1392,76 @@ def from_python(self, value, state):
self.name, type(value), value), value, state)


if zope_datetime_available:
class ZopeDateTimeValidator(validators.DateValidator):
def to_python(self, value, state):
if value is None:
return None
if isinstance(value,
(zopeDateTimeType, sqlbuilder.SQLExpression)):
return value
if isinstance(value, datetime.datetime):
return zopeDateTime.DateTime(
value.year, value.month, value.day,
value.hour, value.minute, value.second)
elif isinstance(value, datetime.date):
return zopeDateTime.DateTime(
value.year, value.month, value.day)
elif isinstance(value, datetime.time):
return zopeDateTime.DateTime(
value.hour, value.minute, value.second)
elif isinstance(value, datetime.timedelta):
if value.days:
raise validators.Invalid(
"the value for the TimeCol '%s' must has days=0, "
"it has days=%d" % (self.name, value.days),
value, state)
return zopeDateTime.DateTime(seconds=value.seconds)
if mxdatetime_available:
if isinstance(value, mxDateTimeType):
# convert mxDateTime instance to zopeDateTime
return zopeDateTime.DateTime(
value.year, value.month, value.day,
value.hour, value.minute, value.second)
try:
if self.format.find(".%f") >= 0:
if '.' in value:
_value = value.split('.')
microseconds = _value[-1]
_l = len(microseconds)
if _l < 6:
_value[-1] = microseconds + '0' * (6 - _l)
elif _l > 6:
_value[-1] = microseconds[:6]
if _l != 6:
value = '.'.join(_value)
else:
value += '.0'
value = datetime.datetime.strptime(value, self.format)
return zopeDateTime.DateTime(
value.year, value.month, value.day,
value.hour, value.minute, value.second)
except Exception:
raise validators.Invalid(
"expected a date/time string of the '%s' format "
"in the DateTimeCol '%s', got %s %r instead" % (
self.format, self.name, type(value), value),
value, state)

def from_python(self, value, state):
if value is None:
return None
if isinstance(value,
(zopeDateTimeType, sqlbuilder.SQLExpression)):
return value
if hasattr(value, "strftime"):
return value.strftime(self.format)
raise validators.Invalid(
"expected a zopeDateTime in the DateTimeCol '%s', "
"got %s %r instead" % (
self.name, type(value), value), value, state)


class SODateTimeCol(SOCol):
datetimeFormat = '%Y-%m-%d %H:%M:%S.%f'

Expand All @@ -1385,6 +1477,8 @@ def createValidators(self):
validatorClass = DateTimeValidator
elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
validatorClass = MXDateTimeValidator
elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION:
validatorClass = ZopeDateTimeValidator
if default_datetime_implementation:
_validators.insert(0, validatorClass(name=self.name,
format=self.datetimeFormat))
Expand Down Expand Up @@ -1426,7 +1520,9 @@ def now():
if default_datetime_implementation == DATETIME_IMPLEMENTATION:
return datetime.datetime.now()
elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
return DateTime.now()
return mxDateTime.now()
elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION:
return zopeDateTime.DateTimr()
else:
assert 0, ("No datetime implementation available "
"(DATETIME_IMPLEMENTATION=%r)"
Expand Down Expand Up @@ -1467,6 +1563,8 @@ def createValidators(self):
validatorClass = DateValidator
elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
validatorClass = MXDateTimeValidator
elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION:
validatorClass = ZopeDateTimeValidator
if default_datetime_implementation:
_validators.insert(0, validatorClass(name=self.name,
format=self.dateFormat))
Expand Down Expand Up @@ -1537,6 +1635,8 @@ def createValidators(self):
validatorClass = TimeValidator
elif default_datetime_implementation == MXDATETIME_IMPLEMENTATION:
validatorClass = MXDateTimeValidator
elif default_datetime_implementation == ZOPE_DATETIME_IMPLEMENTATION:
validatorClass = ZopeDateTimeValidator
if default_datetime_implementation:
_validators.insert(0, validatorClass(name=self.name,
format=self.timeFormat))
Expand Down
47 changes: 30 additions & 17 deletions sqlobject/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@


try:
from mx.DateTime import DateTimeType, DateTimeDeltaType
from mx.DateTime import DateTimeType as mxDateTimeType, \
DateTimeDeltaType as mxDateTimeDeltaType
except ImportError:
try:
from DateTime import DateTimeType, DateTimeDeltaType
except ImportError:
DateTimeType = None
DateTimeDeltaType = None
mxDateTimeType = None
mxDateTimeDeltaType = None

try:
from DateTime import DateTime as zopeDateTime
except ImportError:
zopeDateTimeType = None
else:
zopeDateTimeType = type(zopeDateTime())

try:
import Sybase
Expand Down Expand Up @@ -144,17 +149,6 @@ def FloatConverter(value, db):

registerConverter(float, FloatConverter)

if DateTimeType:
def mxDateTimeConverter(value, db):
return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S")

registerConverter(DateTimeType, mxDateTimeConverter)

def mxTimeConverter(value, db):
return "'%s'" % value.strftime("%H:%M:%S")

registerConverter(DateTimeDeltaType, mxTimeConverter)


def NoneConverter(value, db):
return "NULL"
Expand Down Expand Up @@ -209,6 +203,25 @@ def TimeConverterMS(value, db):
registerConverter(datetime.time, TimeConverterMS)


if mxDateTimeType:
def mxDateTimeConverter(value, db):
return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S")

registerConverter(mxDateTimeType, mxDateTimeConverter)

def mxTimeConverter(value, db):
return "'%s'" % value.strftime("%H:%M:%S")

registerConverter(mxDateTimeDeltaType, mxTimeConverter)


if zopeDateTimeType:
def zopeDateTimeConverter(value, db):
return "'%s'" % value.strftime("%Y-%m-%d %H:%M:%S")

registerConverter(zopeDateTimeType, zopeDateTimeConverter)


def DecimalConverter(value, db):
return value.to_eng_string()

Expand Down

0 comments on commit a591c0b

Please sign in to comment.