Attachment 'dateutils.py'
Download 1 #
2 # dateutils.py
3 #
4 # SVN Keywords
5 #----------------------------------
6 # $Author: $
7 # $Date: $
8 # $Revision: $
9 #----------------------------------
10
11 import re, locale, datetime
12
13
14 class DateUtils(object):
15 __SPLIT_REGEX = re.compile(r"(.*)([Tt ])(.*)")
16 __DATE_REGEX = re.compile(r"[/.]+")
17 __ZONE_REGEX = re.compile(r"(.*)([-Zz+])(.*)")
18 __MONTH_NUM = {
19 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
20 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12
21 }
22 __KW_NAMES = ('hour', 'minute', 'second', 'microsecond', 'tzinfo')
23 _YMD = "yyyy-mm-dd hh:mm:ss"
24 _MDY = "mm-dd-yyyy hh:mm:ss"
25 _DMY = "dd-mm-yyyy hh:mm:ss"
26 _YMD_NON_DLM = "yyyymmddHHMMSS"
27 _RFC2616_RFC1123 = "wkd, dd month yyyy hh:mm:ss GMT"
28 _RFC2616_RFC850 = "weekday, dd-mmm-yy hh:mm:ss GMT"
29 _RFC2616_ASCTIME = "wkd mmm dd hh:mm:ss yyyy"
30 _RFC3339_ISO8601 = "yyyy-mm-ddTHH:MM:SS.ssssssZ"
31
32 def __transposeFromYMDHMS(self, value):
33 """
34 yyyy-mm-dd hh:mm:ss[.ssssss]
35 """
36 value, dot, ms = value.partition('.')
37 y = int(value[:4])
38 m = int(value[5:7])
39 d = int(value[8:10])
40 size = len(value)
41 H = size >= 13 and int(value[11:13]) or 0
42 M = size >= 16 and int(value[14:16]) or 0
43 S = size >= 19 and int(value[17:]) or 0
44 ms = ms.isdigit() and int("{:<06d}".format(int(ms))) or 0
45 return ((y, m, d), (H, M, S, ms, None))
46
47 def __transposeFromMDYHMS(self, value):
48 """
49 mm-dd-yyyy hh:mm:ss[.ssssss]
50 """
51 value, dot, ms = value.partition('.')
52 m = int(value[:2])
53 d = int(value[3:5])
54 y = int(value[6:10])
55 size = len(value)
56 H = size >= 13 and int(value[11:13]) or 0
57 M = size >= 16 and int(value[14:16]) or 0
58 S = size >= 19 and int(value[17:]) or 0
59 ms = ms.isdigit() and int("{:<06d}".format(int(ms))) or 0
60 return ((y, m, d), (H, M, S, ms, None))
61
62 def __transposeFromDMYHMS(self, value):
63 """
64 dd-mm-yyyy hh:mm:ss[.ssssss]
65 or
66 dd-MMM-yyyy hh:mm:ss[.ssssss]
67 """
68 value, dot, ms = value.partition('.')
69 d = int(value[:2])
70 m = self.__MONTH_NUM.get(value[3:6].capitalize())
71
72 if m:
73 idx = 1
74 else:
75 idx = 0
76 m = int(value[3:5])
77
78 y = int(value[idx+6:idx+10])
79 size = len(value)
80 H = size >= (idx+13) and int(value[idx+11:idx+13]) or 0
81 M = size >= (idx+16) and int(value[idx+14:idx+16]) or 0
82 S = size >= (idx+19) and int(value[idx+17:]) or 0
83 ms = ms.isdigit() and int("{:<06d}".format(int(ms))) or 0
84 return ((y, m, d), (H, M, S, ms, None))
85
86 def __transposeNonDelimiterYMDHMS(self, value):
87 """
88 yyyymmddHHMMSS
89 """
90 value, ms = len(value) > 14 and (value[:14], value[14:]) or (value, "")
91 y = int(value[:4])
92 m = int(value[4:6])
93 d = int(value[6:8])
94 size = len(value)
95 H = size >= 10 and int(value[8:10]) or 0
96 M = size >= 12 and int(value[10:12]) or 0
97 S = size >= 14 and int(value[12:]) or 0
98 ms = ms.isdigit() and int("{:<06d}".format(int(ms))) or 0
99 return ((y, m, d), (H, M, S, ms, None))
100
101 def __transposeRFC1123(self, value):
102 """
103 wkd mmm dd hh:mm:ss yyyy
104 """
105 d = int(value[5:7])
106 m = self.__MONTH_NUM.get(value[8:11], 1) # Default to Jan
107 y = int(value[12:16])
108 H = int(value[17:19])
109 M = int(value[20:22])
110 S = int(value[23:25])
111 return ((y, m, d), (H, M, S, 0, None))
112
113 def __transposeRFC850(self, value):
114 """
115 weekday, dd-mmm-yy hh:mm:ss GMT
116 """
117 start = value.index(',') + 2
118 d = int(value[start:start+2])
119 m = self.__MONTH_NUM.get(value[start+3:start+3+3], 1) # Default to Jan
120 y = value[start+7:start+7+2]
121 # Assume life began at the UNIX epic 1970-01-01.
122 y = int(int(y) < 70 and '20' + y or '19' + y)
123 H = int(value[start+10:start+10+2])
124 M = int(value[start+13:start+13+2])
125 S = int(value[start+16:start+16+2])
126 # TODO Fix time zones
127 return ((y, m, d), (H, M, S, 0, ))
128
129 def __transposeASCTIME(self, value):
130 """
131 wkd mmm dd hh:mm:ss yyyy
132 """
133 m = self.__MONTH_NUM.get(value[4:7], 1) # Default to Jan
134 d = int(value[8:10].strip())
135 y = int(value[20:])
136 H = int(value[11:13])
137 M = int(value[14:16])
138 S = int(value[17:19])
139 return ((y, m, d), (H, M, S, 0, None))
140
141 def __transposeRFC3339(self, value):
142 """
143 yyyy-mm-ddTHH:MM:SS[.ssssss][Z]|[[+]|[-]HH:MM]
144 """
145 value, dot, tmp = value.partition('.')
146 splitTmp = self.__ZONE_REGEX.findall(dot and tmp or value)
147 ms, sym, zone = splitTmp and splitTmp[0] or (tmp, '', '')
148 y = int(value[:4])
149 m = int(value[5:7])
150 d = int(value[8:10])
151 H = int(value[11:13])
152 M = int(value[14:16])
153 S = int(value[17:19])
154 ms = ms.isdigit() and int("{:<06d}".format(int(ms))) or 0
155 # TODO Fix time zones
156 #zone = sym.upper() == 'Z' and "+0000" or
157 return ((y, m, d), (H, M, S, ms, ))
158
159
160 __FROM_DATE_FORMATS = {
161 _YMD: __transposeFromYMDHMS,
162 _MDY: __transposeFromMDYHMS,
163 _DMY: __transposeFromDMYHMS,
164 _YMD_NON_DLM: __transposeNonDelimiterYMDHMS,
165 _RFC2616_RFC1123: __transposeRFC1123,
166 _RFC2616_RFC850: __transposeRFC850,
167 _RFC2616_ASCTIME: __transposeASCTIME,
168 _RFC3339_ISO8601: __transposeRFC3339
169 }
170
171
172 @classmethod
173 def toDatetime(self, value, format=None):
174 """
175 Convert a string representation of a date and time to a python
176 datetime object.
177
178 @param value: The string value to convert.
179 @keyword format: The format to convert from.
180 @return: A Python datetime object.
181 """
182 tmp = self.__SPLIT_REGEX.findall(value)
183 head, sep, tail = tmp and tmp[0] or (value, "", "")
184 head = self.__DATE_REGEX.sub('-', head)
185 value = head + sep + tail.lstrip()
186
187 if format is None:
188 format = DateUtils._snoopDateFormat(value)
189
190 try:
191 args, kwargs = self.__FROM_DATE_FORMATS[format](self, value)
192 kwargs = dict(zip(self.__KW_NAMES, kwargs))
193 except KeyError as e:
194 msg = "Invalid date format should be one of {}."
195 raise KeyError(msg.format(self.__FROM_DATE_FORMATS.keys()))
196 except ValueError as e:
197 msg = "The value {} does not match the format {}, {}"
198 raise ValueError(msg.format(value, format, e))
199
200 try:
201 return datetime.datetime(*args, **kwargs)
202 except ValueError as e:
203 msg = "Invalid format for datetime {}, found: {}, {}".format(
204 fmt, value, e)
205 raise ValueError(msg)
206
207 @classmethod
208 def _snoopDateFormat(self, value):
209 """
210 We determine what we can then rely on the current systems locale
211 setting to determine the difference of 01/01/2010 to mean mm/dd/yyy
212 or dd/mm/yyyy.
213 """
214 fmt = None
215 delim = any([char for char in value if char in ('-', '.', '/', ':')])
216 hasT = len(value) >= 11 and "T" == value[10]
217 year = value[:4].isdigit()
218 day = value[:3].isalpha()
219 comma = value.find(',')
220 lfmt = locale.nl_langinfo(locale.D_FMT)
221
222 if hasT:
223 fmt = self._RFC3339_ISO8601
224 elif day and comma == 3:
225 fmt = self._RFC2616_RFC1123
226 elif day and comma > 3:
227 fmt = self._RFC2616_RFC850
228 elif day and comma < 0:
229 fmt = self._RFC2616_ASCTIME
230 elif year and not delim:
231 fmt = self._YMD_NON_DLM
232 elif year and delim:
233 fmt = self._YMD
234 elif lfmt[1] == 'm':
235 fmt = self._MDY
236 elif lfmt[1] == 'd':
237 fmt = self._DMY
238 else:
239 msg = "Invalid date time format: {}"
240 raise ValueError(msg.format(value))
241
242 return fmt
243
244 @classmethod
245 def getFormatTypes(self):
246 return (self._YMD, self._MDY, self._DMY, self._YMD_NON_DLM,
247 self._RFC2616_RFC1123, self._RFC2616_RFC850,
248 self._RFC2616_ASCTIME, self._RFC3339_ISO8601)
249
250
251 def testYMDHMS():
252 print "Testing {}".format(DateUtils._YMD)
253 value = "2010-12-14 20:56:15"
254 print "String", value, "Object:", DateUtils.toDatetime(value)
255 value = "2010.12.14 20:56:15"
256 print "String", value, "Object:", DateUtils.toDatetime(value)
257 value = "2010/12/14 20:56:15"
258 print "String", value, "Object:", DateUtils.toDatetime(value)
259 value = "2010-12-14 20"
260 print "String", value, "Object:", DateUtils.toDatetime(value)
261 value = "2010-12-14 20:56"
262 print "String", value, "Object:", DateUtils.toDatetime(value)
263 value = "2010-12-14 20:56:15.9"
264 print "String", value, "Object:", DateUtils.toDatetime(value)
265
266 def testMDYHMS():
267 print "Testing {}".format(DateUtils._MDY)
268 value = "12-14-2010 20:56:15"
269 print "String", value, "Object:", DateUtils.toDatetime(value)
270 value = "12.14.2010 20:56:15"
271 print "String", value, "Object:", DateUtils.toDatetime(value)
272 value = "12/14/2010 20:56:15"
273 print "String", value, "Object:", DateUtils.toDatetime(value)
274 value = "12-14-2010 20"
275 print "String", value, "Object:", DateUtils.toDatetime(value)
276 value = "12-14-2010 20:56"
277 print "String", value, "Object:", DateUtils.toDatetime(value)
278 value = "12-14-2010 20:56:15.99"
279 print "String", value, "Object:", DateUtils.toDatetime(value)
280
281 def testDMYHMS():
282 print "Testing {}".format(DateUtils._DMY)
283 locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8')
284 value = "14-12-2010 20:56:15"
285 print "String", value, "Object:", DateUtils.toDatetime(value)
286 value = "14.12.2010 20:56:15"
287 print "String", value, "Object:", DateUtils.toDatetime(value)
288 value = "14/12/2010 20:56:15"
289 print "String", value, "Object:", DateUtils.toDatetime(value)
290 value = "14-12-2010 20"
291 print "String", value, "Object:", DateUtils.toDatetime(value)
292 value = "14-12-2010 20:56"
293 print "String", value, "Object:", DateUtils.toDatetime(value)
294 value = "14-12-2010 20:56:15.999"
295 print "String", value, "Object:", DateUtils.toDatetime(value)
296 locale.resetlocale()
297
298 def testNonDelimiterYMDHMS():
299 print "Testing {}".format(DateUtils._YMD_NON_DLM)
300 value = "20101214205615"
301 print "String", value, "Object:", DateUtils.toDatetime(value)
302 value = "201012142056"
303 print "String", value, "Object:", DateUtils.toDatetime(value)
304 value = "2010121420"
305 print "String", value, "Object:", DateUtils.toDatetime(value)
306 value = "201012142056159999"
307 print "String", value, "Object:", DateUtils.toDatetime(value)
308
309 def testDmmmYHMS():
310 print "Testing {}".format(DateUtils._DMY)
311 locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8')
312 value = "14-DEC-2010 20:56:15"
313 print "String", value, "Object:", DateUtils.toDatetime(value)
314 value = "14.DEC.2010 20:56:15"
315 print "String", value, "Object:", DateUtils.toDatetime(value)
316 value = "14/DEC/2010 20:56:15"
317 print "String", value, "Object:", DateUtils.toDatetime(value)
318 value = "14-DEC-2010 20"
319 print "String", value, "Object:", DateUtils.toDatetime(value)
320 value = "14-DEC-2010 20:56"
321 print "String", value, "Object:", DateUtils.toDatetime(value)
322 value = "14-DEC-2010 20:56:15.99999"
323 print "String", value, "Object:", DateUtils.toDatetime(value)
324 locale.resetlocale()
325
326 def testRFC1123():
327 print "Testing {}".format(DateUtils._RFC2616_RFC1123)
328 value = "Tue, 14 Dec 2010 20:56:15 GMT"
329 print "String", value, "Object:", DateUtils.toDatetime(value)
330
331 def testRFC850():
332 print "Testing {}".format(DateUtils._RFC2616_RFC850)
333 value = "Tuesday, 14-Dec-10 20:56:15 GMT"
334 print "String", value, "Object:", DateUtils.toDatetime(value)
335
336 def testASCTIME():
337 print "Testing {}".format(DateUtils._RFC2616_ASCTIME)
338 value = "Tue Dec 14 20:56:15 2010"
339 print "String", value, "Object:", DateUtils.toDatetime(value)
340 value = "Tue Dec 4 20:56:15 2010"
341 print "String", value, "Object:", DateUtils.toDatetime(value)
342
343 def testRFC3339():
344 print "Testing {}".format(DateUtils._RFC3339_ISO8601)
345 value = "2013-07-06T11:33:40Z"
346 print "String", value, "Object:", DateUtils.toDatetime(value)
347 value = "2013-07-06T11:33:40+00:00"
348 print "String", value, "Object:", DateUtils.toDatetime(value)
349
350
351 if __name__=='__main__':
352 import sys, traceback
353
354 try:
355 testYMDHMS()
356 except:
357 tb = sys.exc_info()[2]
358 traceback.print_tb(tb)
359 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
360
361 try:
362 testMDYHMS()
363 except:
364 tb = sys.exc_info()[2]
365 traceback.print_tb(tb)
366 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
367
368 try:
369 testDMYHMS()
370 except:
371 tb = sys.exc_info()[2]
372 traceback.print_tb(tb)
373 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
374
375 try:
376 testNonDelimiterYMDHMS()
377 except:
378 tb = sys.exc_info()[2]
379 traceback.print_tb(tb)
380 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
381
382 try:
383 testDmmmYHMS()
384 except:
385 tb = sys.exc_info()[2]
386 traceback.print_tb(tb)
387 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
388
389 try:
390 testRFC1123()
391 except:
392 tb = sys.exc_info()[2]
393 traceback.print_tb(tb)
394 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
395
396 try:
397 testRFC850()
398 except:
399 tb = sys.exc_info()[2]
400 traceback.print_tb(tb)
401 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
402
403 try:
404 testASCTIME()
405 except:
406 tb = sys.exc_info()[2]
407 traceback.print_tb(tb)
408 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
409
410 try:
411 testRFC3339()
412 except:
413 tb = sys.exc_info()[2]
414 traceback.print_tb(tb)
415 print "%s: %s\n" % (sys.exc_info()[0], sys.exc_info()[1])
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.