Skip to content

Commit

Permalink
add Time primitive.
Browse files Browse the repository at this point in the history
  • Loading branch information
plq committed Oct 25, 2011
1 parent 01ac1ac commit 8492795
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 16 deletions.
70 changes: 54 additions & 16 deletions src/rpclib/model/primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,13 @@
import math
import pytz
import decimal
import datetime

import rpclib.const.xml_ns
import cPickle as pickle

from collections import deque

from datetime import date
from datetime import datetime
from datetime import timedelta

from lxml import etree
from pytz import FixedOffset

Expand All @@ -51,6 +48,7 @@
_utc_re = re.compile(_datetime_pattern + 'Z')
_offset_re = re.compile(_datetime_pattern + _offset_pattern)
_date_re = re.compile(_date_pattern)
_time_re = re.compile(_time_pattern)
_duration_re = re.compile(
r'(?P<sign>-?)'
r'P'
Expand Down Expand Up @@ -340,8 +338,40 @@ class UnsignedInteger8(Integer):
__type_name__ = 'unsignedByte'
__length__ = 8

class Time(SimpleModel):
"""Just that, Time. No time zone support.
Native type is :class:`datetime.time`.
"""

__type_name__ = 'time'

@classmethod
@nillable_string
def to_string(cls, value):
"""Returns ISO formatted dates."""

return value.isoformat()

@classmethod
@nillable_string
def from_string(cls, string):
"""Expects ISO formatted dates."""

match = _time_re.match(string)
if match is None:
raise ValidationError(string)

fields = match.groupdict(0)

return datetime.time(int(fields['hr']), int(fields['min']),
int(fields['sec']), int(fields.get("sec_frac", '.')[1:]))

class Date(SimpleModel):
"""Just that, Date. It also supports time zones."""
"""Just that, Date. It also supports time zones.
Native type is :class:`datetime.date`.
"""

__type_name__ = 'date'

Expand All @@ -363,10 +393,12 @@ def from_string(cls, string):

fields = match.groupdict(0)

return date(fields['year'], fields['month'], fields['day'])
return datetime.date(fields['year'], fields['month'], fields['day'])

class DateTime(SimpleModel):
"""A compact way to represent dates and times together. Supports time zones.
Native type is :class:`datetime.datetime`.
"""
__type_name__ = 'dateTime'

Expand All @@ -377,15 +409,21 @@ def to_string(cls, value):

@staticmethod
def parse(date_match, tz=None):
fields = date_match.groupdict(0)
year, month, day, hour, min, sec = [int(fields[x]) for x in
("year", "month", "day", "hr", "min", "sec")]

# use of decimal module here (rather than float) might be better
# here, if willing to require python 2.4 or higher
microsec = int(float(fields.get("sec_frac", 0)) * 10 ** 6)
fields = date_match.groupdict()

year = int(fields.get('year'))
month = int(fields.get('month'))
day = int(fields.get('day'))
hour = int(fields.get('hr'))
min = int(fields.get('min'))
sec = int(fields.get('sec'))
microsec = fields.get("sec_frac")
if microsec is None:
microsec = 0
else:
microsec = int(microsec[1:])

return datetime(year,month,day, hour,min,sec, microsec, tz)
return datetime.datetime(year,month,day, hour,min,sec, microsec, tz)

@classmethod
@nillable_string
Expand All @@ -409,7 +447,7 @@ def from_string(cls, string):

# this object tries to follow ISO 8601 standard.
class Duration(SimpleModel):
"""This is how the native datetime.timedelta objects are serialized."""
"""Native type is :class:`datetime.timedelta`."""

__type_name__ = 'duration'

Expand All @@ -430,7 +468,7 @@ def from_string(cls, string):
seconds = i
microseconds = int(1e6 * f)

delta = timedelta(days=days, hours=hours, minutes=minutes,
delta = datetime.timedelta(days=days, hours=hours, minutes=minutes,
seconds=seconds, microseconds=microseconds)

if duration['sign'] == "-":
Expand Down
5 changes: 5 additions & 0 deletions src/rpclib/model/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
from rpclib.model import binary
from rpclib.model import complex


_type_map = {
sqlalchemy.Text: primitive.String,
sqlalchemy.String: primitive.String,
Expand All @@ -63,7 +64,11 @@
sqlalchemy.LargeBinary: binary.ByteArray,
sqlalchemy.Boolean: primitive.Boolean,
sqlalchemy.DateTime: primitive.DateTime,
sqlalchemy.Date: primitive.Date,
sqlalchemy.Time: primitive.Time,

sqlalchemy.orm.relation: complex.Array,

UUID: primitive.String
}

Expand Down
11 changes: 11 additions & 0 deletions src/rpclib/test/model/test_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
from lxml import etree

from rpclib.model.complex import Array
from rpclib.model.primitive import Date
from rpclib.model.primitive import Time
from rpclib.model.primitive import Boolean
from rpclib.model.primitive import DateTime
from rpclib.model.primitive import Duration
Expand Down Expand Up @@ -56,6 +58,15 @@ def test_datetime(self):
dt = DateTime.from_xml(element)
self.assertEquals(n, dt)

def test_time(self):
n = datetime.time(1,2,3,4)

ret = Time.to_string(n)
self.assertEquals(ret, n.isoformat())

dt = Time.from_string(ret)
self.assertEquals(n, dt)

def test_duration_xml_duration(self):
dur = datetime.timedelta(days=5 + 30 + 365, hours=1, minutes=1,
seconds=12, microseconds=8e5)
Expand Down

0 comments on commit 8492795

Please sign in to comment.