[openstack-dev] [nova] Timestamp formats in the REST API
Doug Hellmann
doug.hellmann at dreamhost.com
Tue Apr 29 14:39:07 UTC 2014
On Tue, Apr 29, 2014 at 9:48 AM, Mark McLoughlin <markmc at redhat.com> wrote:
> Hey
>
> In this patch:
>
> https://review.openstack.org/83681
>
> by Ghanshyam Mann, we encountered an unusual situation where a timestamp
> in the returned XML looked like this:
>
> 2014-04-08 09:00:14.399708+00:00
>
> What appeared to be unusual was that the timestamp had both sub-second
> time resolution and timezone information. It was felt that this wasn't a
> valid timestamp format and then some debate about how to 'fix' it:
>
> https://review.openstack.org/87563
>
> Anyway, this lead me down a bit of a rabbit hole, so I'm going to
> attempt to document some findings.
>
> Firstly, some definitions:
>
> - Python's datetime module talk about datetime objects being 'naive'
> or 'aware'
>
> https://docs.python.org/2.7/library/datetime.html
>
> "A datetime object d is aware if d.tzinfo is not None and
> d.tzinfo.utcoffset(d) does not return None. If d.tzinfo is None,
> or if d.tzinfo is not None but d.tzinfo.utcoffset(d) returns
> None, d is naive."
>
> (Most people will have encountered this already, but I'm including
> it for completeness)
>
> - The ISO8601 time and date format specifies timestamps like this:
>
> 2014-04-29T11:37:00Z
>
> with many variations. One distinguishing aspect of the ISO8601
> format is the 'T' separating date and time. RFC3339 is very closely
> related and serves as easily accessible documentation of the format:
>
> http://www.ietf.org/rfc/rfc3339.txt
>
> - The Python iso8601 library allows parsing this time format, but
> also allows subtle variations that don't conform to the standard
> like omitting the 'T' separator:
>
> >>> import iso8601
> >>> iso8601.parse_date('2014-04-29 11:37:00Z')
> datetime.datetime(2014, 4, 29, 11, 37, tzinfo=<iso8601.iso8601.Utc object at 0x214b050>)
>
> Presumably this is for the pragmatic reason that when you stringify
> a datetime object, the resulting string uses ' ' as a separator:
>
> >>> import datetime
> >>> str(datetime.datetime(2014, 4, 29, 11, 37))
> '2014-04-29 11:37:00'
>
> And now some observations on what's going on in Nova:
>
> - We don't store timezone information in the database, but all our
> timestamps are relative to UTC nonetheless.
>
> - The objects code automatically adds the UTC to naive datetime
> objects:
>
> if value.utcoffset() is None:
> value = value.replace(tzinfo=iso8601.iso8601.Utc())
>
> so code that is ported to objects may now be using aware datetime
> objects where they were previously using naive objects.
>
> - Whether we store sub-second resolution timestamps in the database
> appears to be database specific. In my quick tests, we store that
> information in sqlite but not MySQL.
>
> - However, timestamps added by SQLAlchemy when you do e.g. save() do
> include sub-second information, so some DB API calls may return
> sub-second timestamps even when that information isn't stored in
> the database.
>
> In our REST APIs, you'll essentially see one of three time formats. I'm
> calling them 'isotime', 'strtime' and 'xmltime':
>
> - 'isotime' - this is the result from timeutils.isotime(). It
> includes timezone information (i.e. a 'Z' prefix) but not
> microseconds. You'll see this in places where we stringify the
> datetime objects in the API layer using isotime() before passing
> them to the JSON/XML serializers.
>
> - 'strtime' - this is the result from timeutils.strtime(). It doesn't
> include timezone information but does include decimal seconds. This
> is what jsonutils.dumps() uses when we're serializing API responses
>
> - 'xmltime' or 'str(datetime)' format - this is just what you get
> when you stringify a datetime using str(). If the datetime is tz
> aware or includes non-zero microseconds, then that information will
> be included in the result. This is a significant different versus
> the other two formats where it is clear whether tz and microsecond
> information is included in the string.
>
> but there are some caveats:
>
> - I don't know how significant it is these days, but timestamps will
> be serialized to strtime format when going over RPC, but won't be
> de-serialized on the remote end. This could lead to a situation
> where the API layer tries and stringify a strtime formatted string
> using timeutils.isotime(). (see below for a description of those
> formats)
>
> - In at least one place - e.g. the 'updated' timestamp for v2
> extensions - we hardcode the timestamp as strings in the code and
> don't currently use one of the formats above.
>
>
> My conclusions from all that:
>
> 1) This sucks
>
> 2) At the very least, we should be clear in our API samples tests
> which of the three formats we expect - we should only change the
> format used in a given part of the API after considering any
> compatibility considerations
>
> 3) We should unify on a single format in the v3 API - IMHO, we should
> be explicit about use of the UTC timezone and we should avoid
> including microseconds unless there's a clear use case. In other
> words, we should use the 'isotime' format.
This seems like a situation where we should try take the needs of all
projects into account, so we converge on a consistent timestamp format
across APIs. For example, ceilometer's database schema was updated to
support sub-second timestamps to differentiate between events coming
in very close together
(https://bugs.launchpad.net/ceilometer/+bug/1215676). I don't know if
Marconi uses timestamps in their API, but if so that's another case
where I would expect the caller to want sub-second precision, at least
sometimes.
Doug
>
> 4) The 'xmltime' format is just a dumb historical mistake and since
> XML support is now firmly out of favor, let's not waste time
> improving the timestamp situation in XML.
>
> 5) We should at least consider moving to a single format in the v2
> (JSON) API. IMHO, moving from strtime to isotime for fields like
> created_at and updated_at would be highly unlikely to cause any
> real issues for API users.
>
> (Following up this email with some patches that I'll link to, but I want
> to link to this email from the patches themselves)
>
> Mark.
>
>
> _______________________________________________
> OpenStack-dev mailing list
> OpenStack-dev at lists.openstack.org
> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
More information about the OpenStack-dev
mailing list