strict-rfc3339


Namestrict-rfc3339 JSON
Version 0.7 PyPI version JSON
download
home_pagehttp://www.danielrichman.co.uk/libraries/strict-rfc3339.html
SummaryStrict, simple, lightweight RFC3339 functions
upload_time2016-04-24 04:24:04
maintainerNone
docs_urlNone
authorDaniel Richman, Adam Greig
requires_pythonNone
licenseGNU General Public License Version 3
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Strict, simple, lightweight RFC3339 functions
=============================================

Goals
-----

 - Convert unix timestamps to and from RFC3339.
 - Either produce RFC3339 strings with a UTC offset (Z) or with the offset
   that the C time module reports is the local timezone offset.
 - Simple with minimal dependencies/libraries.
 - Avoid timezones as much as possible.
 - Be very strict and follow RFC3339.

Caveats
-------

 - Leap seconds are not quite supported, since timestamps do not support them,
   and it requires access to timezone data.
 - You may be limited by the size of `time_t` on 32 bit systems.

In both cases, see 'Notes' below.

Rationale
---------

 - A lot of libraries have trouble with DST transitions and ambiguous times.
 - Generally, using the python datetime object causes trouble, introducing
   problems with timezones.
 - The excellent `pytz` library seems to achieve timezone perfection, however
   it didn't (at the time of writing) have a method for getting the local
   timezone or the 'now' time in the local zone.
 - I saw a lot of problems ultimately due to information lost when converting
   or transferring between two libraries (e.g., `time` -> `datetime` loses DST
   info in the tuple)

Usage
-----

Validation:

    >>> strict_rfc3339.validate_rfc3339("some rubbish")
    False
    >>> strict_rfc3339.validate_rfc3339("2013-03-25T12:42:31+00:32")
    True

Indeed, we can then:

    >>> strict_rfc3339.rfc3339_to_timestamp("2013-03-25T12:42:31+00:32")
    1364213431
    >>> tuple(time.gmtime(1364213431))[:6]
    (2013, 3, 25, 12, 10, 31)

No need for two function calls:

    >>> strict_rfc3339.rfc3339_to_timestamp("some rubbish")
    Traceback [...]
    strict_rfc3339.InvalidRFC3339Error

Producing strings (for this example `TZ=America/New_York`):

    >>> strict_rfc3339.timestamp_to_rfc3339_utcoffset(1364213431)
    '2013-03-25T12:10:31Z'
    >>> strict_rfc3339.timestamp_to_rfc3339_localoffset(1364213431)
    '2013-03-25T08:10:31-04:00'

And with `TZ=Europe/London`:

    >>> strict_rfc3339.timestamp_to_rfc3339_localoffset(1364213431)
    '2013-03-25T12:10:31+00:00'

Convenience functions:

    >>> strict_rfc3339.now_to_rfc3339_utcoffset()
    '2013-03-25T21:39:35Z'
    >>> strict_rfc3339.now_to_rfc3339_localoffset()
    '2013-03-25T17:39:39-04:00'

Floats:

    >>> strict_rfc3339.now_to_rfc3339_utcoffset(integer=True) # The default
    '2013-03-25T22:04:01Z'
    >>> strict_rfc3339.now_to_rfc3339_utcoffset(integer=False)
    '2013-03-25T22:04:01.04399Z'
    >>> strict_rfc3339.rfc3339_to_timestamp("2013-03-25T22:04:10.04399Z")
    1364249050.0439899

Behind the scenes
-----------------

These functions are essentially string formatting and arithmetic only.  A very
small number of functions do the heavy lifting. These come from two modules:
`time` and `calendar`.

`time` is a thin wrapper around the C time functions. I'm working on the
assumption that these are usually of high quality and are correct. From the
`time` module, `strict_rfc3339` uses:

 - `time`: (actually calls `gettimeofday`) to get the current timestamp / "now"
 - `gmtime`: splits a timestamp into a UTC time tuple
 - `localtime`: splits a timestamp into a local time tuple

Based on the assumption that they are correct, we can use the difference
between the values returned by `gmtime` and `localtime` to find the local
offset.  As clunky as it sounds, it's far easier than using a fully fledged
timezone library.

`calendar` is implemented in python. From `calendar`, `strict_rfc3339` uses:

 - `timegm`: turns a UTC time tuple into a timestamp. This essentially just
   multiplies each number in the tuple by the number of seconds in it. It does
   use `datetime.date` to work out the number of days between Jan 1 1970 and the
   Y-M-D in the tuple, but this is fine. It does not perform much validation at
   all.
 - `monthrange`: gives the number of days in a (year, month). I checked and
   (at least in my copy of python 2.6) the function used for leap years is
   identical to the one specified in RFC3339 itself.

Notes
-----

 - RFC3339 specifies an offset, not a timezone, and the difference is
   important. Timezones are evil.
 - It is perhaps simpler to think of a RFC3339 string as a human readable
   method of specifying a moment in time (only). These functions merely provide
   access to the one-to-many timestamp-to-RFC3339 mapping.
 - Timestamps don't support leap seconds: a day is always 86400 "long".
   Also, validating leap seconds is particularly fiddly, because not only do
   you need some data, but it must be kept up to date.
   For this reason, `strict_rfc3339` does not support leap seconds: in validation,
   `seconds == 60` or `seconds == 61` is rejected.
   In the case of reverse leap seconds, calendar.timegm will blissfully accept
   it. The result would be about as correct as you could get.
 - RFC3339 generation using `gmtime` or `localtime` may be limited by the size
   of `time_t` on the system: if it is 32 bit, you're limited to dates between
   (approx) 1901 and 2038. This does not affect `rfc3339_to_timestamp`.
            

Raw data

            {
    "_id": null,
    "home_page": "http://www.danielrichman.co.uk/libraries/strict-rfc3339.html",
    "name": "strict-rfc3339",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": null,
    "author": "Daniel Richman, Adam Greig",
    "author_email": "main@danielrichman.co.uk",
    "download_url": "https://files.pythonhosted.org/packages/56/e4/879ef1dbd6ddea1c77c0078cd59b503368b0456bcca7d063a870ca2119d3/strict-rfc3339-0.7.tar.gz",
    "platform": "UNKNOWN",
    "description": "Strict, simple, lightweight RFC3339 functions\n=============================================\n\nGoals\n-----\n\n - Convert unix timestamps to and from RFC3339.\n - Either produce RFC3339 strings with a UTC offset (Z) or with the offset\n   that the C time module reports is the local timezone offset.\n - Simple with minimal dependencies/libraries.\n - Avoid timezones as much as possible.\n - Be very strict and follow RFC3339.\n\nCaveats\n-------\n\n - Leap seconds are not quite supported, since timestamps do not support them,\n   and it requires access to timezone data.\n - You may be limited by the size of `time_t` on 32 bit systems.\n\nIn both cases, see 'Notes' below.\n\nRationale\n---------\n\n - A lot of libraries have trouble with DST transitions and ambiguous times.\n - Generally, using the python datetime object causes trouble, introducing\n   problems with timezones.\n - The excellent `pytz` library seems to achieve timezone perfection, however\n   it didn't (at the time of writing) have a method for getting the local\n   timezone or the 'now' time in the local zone.\n - I saw a lot of problems ultimately due to information lost when converting\n   or transferring between two libraries (e.g., `time` -> `datetime` loses DST\n   info in the tuple)\n\nUsage\n-----\n\nValidation:\n\n    >>> strict_rfc3339.validate_rfc3339(\"some rubbish\")\n    False\n    >>> strict_rfc3339.validate_rfc3339(\"2013-03-25T12:42:31+00:32\")\n    True\n\nIndeed, we can then:\n\n    >>> strict_rfc3339.rfc3339_to_timestamp(\"2013-03-25T12:42:31+00:32\")\n    1364213431\n    >>> tuple(time.gmtime(1364213431))[:6]\n    (2013, 3, 25, 12, 10, 31)\n\nNo need for two function calls:\n\n    >>> strict_rfc3339.rfc3339_to_timestamp(\"some rubbish\")\n    Traceback [...]\n    strict_rfc3339.InvalidRFC3339Error\n\nProducing strings (for this example `TZ=America/New_York`):\n\n    >>> strict_rfc3339.timestamp_to_rfc3339_utcoffset(1364213431)\n    '2013-03-25T12:10:31Z'\n    >>> strict_rfc3339.timestamp_to_rfc3339_localoffset(1364213431)\n    '2013-03-25T08:10:31-04:00'\n\nAnd with `TZ=Europe/London`:\n\n    >>> strict_rfc3339.timestamp_to_rfc3339_localoffset(1364213431)\n    '2013-03-25T12:10:31+00:00'\n\nConvenience functions:\n\n    >>> strict_rfc3339.now_to_rfc3339_utcoffset()\n    '2013-03-25T21:39:35Z'\n    >>> strict_rfc3339.now_to_rfc3339_localoffset()\n    '2013-03-25T17:39:39-04:00'\n\nFloats:\n\n    >>> strict_rfc3339.now_to_rfc3339_utcoffset(integer=True) # The default\n    '2013-03-25T22:04:01Z'\n    >>> strict_rfc3339.now_to_rfc3339_utcoffset(integer=False)\n    '2013-03-25T22:04:01.04399Z'\n    >>> strict_rfc3339.rfc3339_to_timestamp(\"2013-03-25T22:04:10.04399Z\")\n    1364249050.0439899\n\nBehind the scenes\n-----------------\n\nThese functions are essentially string formatting and arithmetic only.  A very\nsmall number of functions do the heavy lifting. These come from two modules:\n`time` and `calendar`.\n\n`time` is a thin wrapper around the C time functions. I'm working on the\nassumption that these are usually of high quality and are correct. From the\n`time` module, `strict_rfc3339` uses:\n\n - `time`: (actually calls `gettimeofday`) to get the current timestamp / \"now\"\n - `gmtime`: splits a timestamp into a UTC time tuple\n - `localtime`: splits a timestamp into a local time tuple\n\nBased on the assumption that they are correct, we can use the difference\nbetween the values returned by `gmtime` and `localtime` to find the local\noffset.  As clunky as it sounds, it's far easier than using a fully fledged\ntimezone library.\n\n`calendar` is implemented in python. From `calendar`, `strict_rfc3339` uses:\n\n - `timegm`: turns a UTC time tuple into a timestamp. This essentially just\n   multiplies each number in the tuple by the number of seconds in it. It does\n   use `datetime.date` to work out the number of days between Jan 1 1970 and the\n   Y-M-D in the tuple, but this is fine. It does not perform much validation at\n   all.\n - `monthrange`: gives the number of days in a (year, month). I checked and\n   (at least in my copy of python 2.6) the function used for leap years is\n   identical to the one specified in RFC3339 itself.\n\nNotes\n-----\n\n - RFC3339 specifies an offset, not a timezone, and the difference is\n   important. Timezones are evil.\n - It is perhaps simpler to think of a RFC3339 string as a human readable\n   method of specifying a moment in time (only). These functions merely provide\n   access to the one-to-many timestamp-to-RFC3339 mapping.\n - Timestamps don't support leap seconds: a day is always 86400 \"long\".\n   Also, validating leap seconds is particularly fiddly, because not only do\n   you need some data, but it must be kept up to date.\n   For this reason, `strict_rfc3339` does not support leap seconds: in validation,\n   `seconds == 60` or `seconds == 61` is rejected.\n   In the case of reverse leap seconds, calendar.timegm will blissfully accept\n   it. The result would be about as correct as you could get.\n - RFC3339 generation using `gmtime` or `localtime` may be limited by the size\n   of `time_t` on the system: if it is 32 bit, you're limited to dates between\n   (approx) 1901 and 2038. This does not affect `rfc3339_to_timestamp`.",
    "bugtrack_url": null,
    "license": "GNU General Public License Version 3",
    "summary": "Strict, simple, lightweight RFC3339 functions",
    "version": "0.7",
    "project_urls": {
        "Download": "UNKNOWN",
        "Homepage": "http://www.danielrichman.co.uk/libraries/strict-rfc3339.html"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "56e4879ef1dbd6ddea1c77c0078cd59b503368b0456bcca7d063a870ca2119d3",
                "md5": "4d9b635b4df885bc37bc1189d66c9abc",
                "sha256": "5cad17bedfc3af57b399db0fed32771f18fc54bbd917e85546088607ac5e1277"
            },
            "downloads": -1,
            "filename": "strict-rfc3339-0.7.tar.gz",
            "has_sig": false,
            "md5_digest": "4d9b635b4df885bc37bc1189d66c9abc",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 17552,
            "upload_time": "2016-04-24T04:24:04",
            "upload_time_iso_8601": "2016-04-24T04:24:04.403344Z",
            "url": "https://files.pythonhosted.org/packages/56/e4/879ef1dbd6ddea1c77c0078cd59b503368b0456bcca7d063a870ca2119d3/strict-rfc3339-0.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2016-04-24 04:24:04",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "strict-rfc3339"
}
        
Elapsed time: 0.74723s