Commits

Éric Araujo committed ead97b2

* Fix datetime format to comply with W3CDTF

  • Participants
  • Parent commits df4bfe8

Comments (0)

Files changed (3)

 
 *.pyc
 *.egg
+dynamodb_mapper.egg-info
 
 build
 dist
 
 coverage.xml
 .coverage
+nosetests.xml
+.noseids
 
 # Eclipse project files
 .project

File dynamodb_mapper/model.py

         # datetime instances are stored as UTC in the DB itself.
         # (that way, they become sortable)
         # datetime objects without tzinfo are not supported.
-        return value.astimezone(utc_tz).strftime("%Y-%m-%dT%H:%M:%S.%f%z")
+        s = value.astimezone(utc_tz).strftime("%Y-%m-%dT%H:%M:%S.%f%z")
+        # there is not strftime code to output the timezone with the ':' that
+        # is mandated by the W3CDTF format, so here's an ugly hack
+        s = s[:-2] + ':' + s[-2:]
+        return s
 
     if value or value == 0:
         return value
         # Parse TZ-aware isoformat
 
         # strptime doesn't support timezone parsing (%z flag), so we're forcing
-        # the strings in the database to be UTC (+0000) for now.
+        # the strings in the database to be UTC (+00:00) for now.
         # TODO Handle arbitrary timezones (with manual parsing).
         return datetime.datetime.strptime(
-            value, "%Y-%m-%dT%H:%M:%S.%f+0000").replace(tzinfo=utc_tz)
+            value, "%Y-%m-%dT%H:%M:%S.%f+00:00").replace(tzinfo=utc_tz)
 
     return schema_type(value)
 
             if isinstance(value, (set, frozenset)):
                 out[name] = list(value)
             elif isinstance(value, datetime.datetime):
-                # Using strftime instead of the default str() representation
-                # because it outputs the zone as +HH:MM instead of +HHMM
-                out[name] = value.astimezone(utc_tz).strftime("%Y-%m-%dT%H:%M:%S.%f%z")
+                # Using strftime instead of str or isoformat to get the right
+                # separator ('T') and time offset notation (with ':')
+                out[name] = value.astimezone(utc_tz).isoformat()
             else:
                 out[name] = value
         return out

File dynamodb_mapper/tests/test_model.py

     }
 
 
-
 class TestConnectionBorg(unittest.TestCase):
     def setUp(self):
         ConnectionBorg()._connections.clear()
         self.assertEquals(10, _python_to_dynamodb(10))
         self.assertEquals(10.0, _python_to_dynamodb(10.0))
 
-
     def test_dynamodb_to_python_number(self):
         self.assertEquals(0, _dynamodb_to_python(int, 0))
         self.assertEquals(0.0, _dynamodb_to_python(float, 0.0))
     def test_dynamodb_to_python_datetime(self):
         self.assertEquals(
             datetime.datetime(2012, 05, 31, 12, 0, 0, tzinfo=utc_tz),
-            _dynamodb_to_python(datetime.datetime, "2012-05-31T12:00:00.000000+0000"))
+            _dynamodb_to_python(datetime.datetime,
+                                "2012-05-31T12:00:00.000000+00:00"))
 
     def test_dynamodb_to_python_datetime_notz(self):
         # Timezone info is mandatory
 
     def test_python_to_dynamodb_datetime(self):
         self.assertEquals(
-            "2012-05-31T12:00:00.000000+0000",
+            "2012-05-31T12:00:00.000000+00:00",
             _python_to_dynamodb(datetime.datetime(2012, 05, 31, 12, 0, 0, tzinfo=utc_tz)))
 
     def test_python_to_dynamodb_datetime_notz(self):
     def test_get_by_hash_key_magic_types(self, m_get_table):
         m_table = m_get_table.return_value
         d = datetime.datetime(2012, 5, 31, 12, 0, 0, tzinfo=utc_tz)
-        d_text = "2012-05-31T12:00:00.000000+0000"
+        d_text = "2012-05-31T12:00:00.000000+00:00"
         m_table.get_item.return_value = {"datetime": d_text}
 
         Patch.get(d)
     def test_get_by_composite_key_magic_types(self, m_get_table):
         m_table = m_get_table.return_value
         d = datetime.datetime(2012, 5, 31, 12, 0, 0, tzinfo=utc_tz)
-        d_text = "2012-05-31T12:00:00.000000+0000"
+        d_text = "2012-05-31T12:00:00.000000+00:00"
         players = ["duke", "doomguy", "blackowicz"]
         players_text = json.dumps(players)
         m_table.get_item.return_value = {
         # The first call (id=3) will be rejected.
         error = DynamoDBResponseError(
             None, None, {"__type": "ConditionalCheckFailedException"})
+
         def err(*args, **kw):
             # Clear the error then fail
             m_item_instance.put.side_effect = None