forked from mit-dig/air-reasoner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
isodate.py
123 lines (107 loc) · 3.76 KB
/
isodate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python
"""
isodate.py
Copyright 2002 Mark Nottingham, <mailto:mnot@pobox.com>
THIS SOFTWARE IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, AND MAY BE
COPIED, MODIFIED OR DISTRIBUTED IN ANY WAY, AS LONG AS THIS NOTICE
AND ACKNOWLEDGEMENT OF AUTHORSHIP REMAIN.
Functions for manipulating a subset of ISO8601 date, as specified by
<http://www.w3.org/TR/NOTE-datetime>
Exposes:
- parse(s)
s being a conforming (regular or unicode) string. Raises ValueError for
invalid strings. Returns a float (representing seconds from the epoch;
see the time module).
- asString(i)
i being an integer or float. Returns a conforming string.
TODO:
- Precision? it would be nice to have an interface that tells us how
precise a datestring is, so that we don't make assumptions about it;
e.g., 2001 != 2001-01-01T00:00:00Z.
2002-06-22 added bad string to error message -- timbl@w3.org
"""
import sys, time, re, operator
import calendar # timegm - from python
from types import StringType, UnicodeType, IntType, LongType, FloatType
__version__ = "0.6"
date_parser = re.compile(r"""^
(?P<year>\d{4,4})
(?:
-
(?P<month>\d{1,2})
(?:
-
(?P<day>\d{1,2})
(?:
T
(?P<hour>\d{1,2})
:
(?P<minute>\d{1,2})
(?:
:
(?P<second>\d{1,2})
(?:
\.
(?P<dec_second>\d+)?
)?
)?
(?:
Z
|
(?:
(?P<tz_sign>[+-])
(?P<tz_hour>\d{1,2})
:
(?P<tz_min>\d{2,2})
)
)
)?
)?
)?
$""", re.VERBOSE)
def parse(s):
""" parse a string and return seconds since the epoch. """
assert type(s) in [StringType, UnicodeType]
r = date_parser.search(s)
try:
a = r.groupdict('0')
except:
raise ValueError, 'invalid date string format:'+s
y = int(a['year'])
if y < 1970:
raise ValueError, 'Sorry, date must be in Unix era (1970 or after):'+s
d = calendar.timegm(( int(a['year']),
int(a['month']) or 1,
int(a['day']) or 1,
int(a['hour']),
int(a['minute']),
int(a['second']),
0,
0,
0
))
return d - int("%s%s" % (
a.get('tz_sign', '+'),
( int(a.get('tz_hour', 0)) * 60 * 60 ) - \
( int(a.get('tz_min', 0)) * 60 ))
)
def fullString(i):
""" given seconds since the epoch, return a full dateTime string in Z timezone. """
assert type(i) in [IntType, FloatType, LongType], "Wrong type: "+ `type(i)` +`i`
year, month, day, hour, minute, second, wday, jday, dst = time.gmtime(i)
return str(year) + '-%2.2d-%2.2dT%2.2d:%2.2d:%2.2dZ' % (month, day, hour, minute, second)
def asString(i):
""" given seconds since the epoch, return a dateTime string. """
assert type(i) in [IntType, FloatType]
year, month, day, hour, minute, second, wday, jday, dst = time.gmtime(i)
o = str(year)
if (month, day, hour, minute, second) == (1, 1, 0, 0, 0): return o
o = o + '-%2.2d' % month
if (day, hour, minute, second) == (1, 0, 0, 0): return o
o = o + '-%2.2d' % day
if (hour, minute, second) == (0, 0, 0): return o
o = o + 'T%2.2d:%2.2d' % (hour, minute)
if second != 0:
o = o + ':%2.2d' % second
o = o + 'Z'
return o