~a-j-delaney/dagda/trunk

« back to all changes in this revision

Viewing changes to dagda/rfc3339.py

  • Committer: Aidan Delaney
  • Date: 2009-02-03 21:12:46 UTC
  • Revision ID: balor@scarymonster-20090203211246-stq0o2y72zle53yj
* Transitioning to proper RFC3339 date parsing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
'''
 
3
The function `rfc3339` formats dates according to the :RFC:`3339`. `rfc3339`
 
4
tries to have as much as possible sensible defaults.
 
5
'''
 
6
 
 
7
__author__ = 'Henry Precheur <henry@precheur.org>'
 
8
__license__ = "Public Domain"
 
9
__all__ = ('rfc3339',)
 
10
 
 
11
import datetime
 
12
import time
 
13
 
 
14
def _timezone(utcoffset):
 
15
    '''
 
16
    Return a string reprenseting the timezone offset.
 
17
 
 
18
    >>> _timezone(3600)
 
19
    '+01:00'
 
20
    >>> _timezone(-28800)
 
21
    '-08:00'
 
22
    '''
 
23
    hours = abs(utcoffset) // 3600
 
24
    minutes = abs(utcoffset) % 3600
 
25
    if utcoffset >= 0:
 
26
        return '+%02d:%02d' % (hours, minutes)
 
27
    else:
 
28
        return '-%02d:%02d' % (hours, minutes)
 
29
 
 
30
def _utc_offset(date, use_system_timezone):
 
31
    '''
 
32
    Return the UTC offset of `date`. If `date` does not have any `tzinfo`, use
 
33
    the timezone informations stored locally on the system.
 
34
 
 
35
    >>> if time.daylight:
 
36
    ...     system_timezone = -time.altzone
 
37
    ... else:
 
38
    ...     system_timezone = -time.timezone
 
39
    >>> _utc_offset(datetime.datetime.now(), True) == system_timezone
 
40
    True
 
41
    >>> _utc_offset(datetime.datetime.now(), False)
 
42
    0
 
43
    '''
 
44
    if date.utcoffset() is not None:
 
45
        return date.utcoffset()
 
46
    elif use_system_timezone:
 
47
        if time.daylight:
 
48
            return -time.altzone
 
49
        else:
 
50
            return -time.timezone
 
51
    else:
 
52
        return 0
 
53
 
 
54
def _utc_string(d):
 
55
    return d.strftime('%Y-%m-%dT%H:%M:%SZ')
 
56
 
 
57
def rfc3339(date, utc=False, use_system_timezone=True):
 
58
    '''
 
59
    Return a string formatted according to the :RFC:`3339`. If called with
 
60
    `utc=True`, it normalizes `date` to the UTC date. If `date` does not have
 
61
    any timezone information, uses the local timezone::
 
62
 
 
63
        >>> date = datetime.datetime(2008, 4, 2, 20)
 
64
        >>> rfc3339(date, utc=True, use_system_timezone=False)
 
65
        '2008-04-02T20:00:00Z'
 
66
        >>> rfc3339(date) # doctest: +ELLIPSIS
 
67
        '2008-04-02T20:00:00...'
 
68
 
 
69
    If called with `user_system_time=False` don't use the local timezone and
 
70
    consider the offset to UTC to be zero::
 
71
 
 
72
        >>> rfc3339(date, use_system_timezone=False)
 
73
        '2008-04-02T20:00:00+00:00'
 
74
 
 
75
    `date` must be a a `datetime.datetime`, `datetime.date` or a timestamp as
 
76
    returned by `time.time()`::
 
77
 
 
78
        >>> rfc3339(0, utc=True, use_system_timezone=False)
 
79
        '1970-01-01T00:00:00Z'
 
80
        >>> rfc3339(datetime.date(2008, 9, 6), use_system_timezone=False)
 
81
        '2008-09-06T00:00:00+00:00'
 
82
        >>> rfc3339('foo bar')
 
83
        Traceback (most recent call last):
 
84
        ...
 
85
        TypeError: excepted datetime, got str instead
 
86
    '''
 
87
    # Check if `date` is a timestamp.
 
88
    try:
 
89
        if utc:
 
90
            return _utc_string(datetime.datetime.utcfromtimestamp(date))
 
91
        else:
 
92
            date = datetime.datetime.fromtimestamp(date)
 
93
    except TypeError:
 
94
        pass
 
95
    if isinstance(date, datetime.date):
 
96
        # If `date` is a `datetime.date` convert it to a `datetime.datetime`.
 
97
        if not isinstance(date, datetime.datetime):
 
98
            date = datetime.datetime(*date.timetuple()[:3])
 
99
        utcoffset = _utc_offset(date, use_system_timezone)
 
100
        if utc:
 
101
            return _utc_string(date + datetime.timedelta(seconds=utcoffset))
 
102
        else:
 
103
            return date.strftime('%Y-%m-%dT%H:%M:%S') + _timezone(utcoffset)
 
104
    else:
 
105
        raise TypeError('excepted %s, got %s instead' %
 
106
                        (datetime.datetime.__name__, date.__class__.__name__))
 
107
 
 
108
if __name__ == '__main__':
 
109
    import doctest
 
110
    doctest.testmod()