| Home | Trees | Indices | Help |
|
|---|
|
|
1 __doc__ = """
2 GNUmed date/time handling.
3
4 This modules provides access to date/time handling
5 and offers an fuzzy timestamp implementation
6
7 It utilizes
8
9 - Python time
10 - Python datetime
11 - mxDateTime
12
13 Note that if you want locale-aware formatting you need to call
14
15 locale.setlocale(locale.LC_ALL, '')
16
17 somewhere before importing this script.
18
19 Note regarding UTC offsets
20 --------------------------
21
22 Looking from Greenwich:
23 WEST (IOW "behind"): negative values
24 EAST (IOW "ahead"): positive values
25
26 This is in compliance with what datetime.tzinfo.utcoffset()
27 does but NOT what time.altzone/time.timezone do !
28
29 This module also implements a class which allows the
30 programmer to define the degree of fuzziness, uncertainty
31 or imprecision of the timestamp contained within.
32
33 This is useful in fields such as medicine where only partial
34 timestamps may be known for certain events.
35 """
36 #===========================================================================
37 __version__ = "$Revision: 1.34 $"
38 __author__ = "K. Hilbert <Karsten.Hilbert@gmx.net>"
39 __license__ = "GPL (details at http://www.gnu.org)"
40
41 # stdlib
42 import sys, datetime as pyDT, time, os, re as regex, locale, logging
43
44
45 # 3rd party
46 import mx.DateTime as mxDT
47 import psycopg2 # this will go once datetime has timezone classes
48
49
50 if __name__ == '__main__':
51 sys.path.insert(0, '../../')
52 from Gnumed.pycommon import gmI18N
53
54
55 _log = logging.getLogger('gm.datetime')
56 _log.info(__version__)
57 _log.info(u'mx.DateTime version: %s', mxDT.__version__)
58
59 dst_locally_in_use = None
60 dst_currently_in_effect = None
61
62 current_local_utc_offset_in_seconds = None
63 current_local_timezone_interval = None
64 current_local_iso_numeric_timezone_string = None
65 current_local_timezone_name = None
66 py_timezone_name = None
67 py_dst_timezone_name = None
68
69 cLocalTimezone = psycopg2.tz.LocalTimezone # remove as soon as datetime supports timezone classes
70 cFixedOffsetTimezone = psycopg2.tz.FixedOffsetTimezone # remove as soon as datetime supports timezone classes
71 gmCurrentLocalTimezone = 'gmCurrentLocalTimezone not initialized'
72
73
74 ( acc_years,
75 acc_months,
76 acc_weeks,
77 acc_days,
78 acc_hours,
79 acc_minutes,
80 acc_seconds,
81 acc_subseconds
82 ) = range(1,9)
83
84 _accuracy_strings = {
85 1: 'years',
86 2: 'months',
87 3: 'weeks',
88 4: 'days',
89 5: 'hours',
90 6: 'minutes',
91 7: 'seconds',
92 8: 'subseconds'
93 }
94
95 gregorian_month_length = {
96 1: 31,
97 2: 28, # FIXME: make leap year aware
98 3: 31,
99 4: 30,
100 5: 31,
101 6: 30,
102 7: 31,
103 8: 31,
104 9: 30,
105 10: 31,
106 11: 30,
107 12: 31
108 }
109
110 avg_days_per_gregorian_year = 365
111 avg_days_per_gregorian_month = 30
112 avg_seconds_per_day = 24 * 60 * 60
113 days_per_week = 7
114
115 #===========================================================================
116 # module init
117 #---------------------------------------------------------------------------
119
120 _log.debug('mx.DateTime.now(): [%s]' % mxDT.now())
121 _log.debug('datetime.now() : [%s]' % pyDT.datetime.now())
122 _log.debug('time.localtime() : [%s]' % str(time.localtime()))
123 _log.debug('time.gmtime() : [%s]' % str(time.gmtime()))
124
125 try:
126 _log.debug('$TZ: [%s]' % os.environ['TZ'])
127 except KeyError:
128 _log.debug('$TZ not defined')
129
130 _log.debug('time.daylight: [%s] (whether or not DST is locally used at all)' % time.daylight)
131 _log.debug('time.timezone: [%s] seconds' % time.timezone)
132 _log.debug('time.altzone : [%s] seconds' % time.altzone)
133 _log.debug('time.tzname : [%s / %s] (non-DST / DST)' % time.tzname)
134 _log.debug('mx.DateTime.now().gmtoffset(): [%s]' % mxDT.now().gmtoffset())
135
136 global py_timezone_name
137 py_timezone_name = time.tzname[0].decode(gmI18N.get_encoding(), 'replace')
138
139 global py_dst_timezone_name
140 py_dst_timezone_name = time.tzname[1].decode(gmI18N.get_encoding(), 'replace')
141
142 global dst_locally_in_use
143 dst_locally_in_use = (time.daylight != 0)
144
145 global dst_currently_in_effect
146 dst_currently_in_effect = bool(time.localtime()[8])
147 _log.debug('DST currently in effect: [%s]' % dst_currently_in_effect)
148
149 if (not dst_locally_in_use) and dst_currently_in_effect:
150 _log.error('system inconsistency: DST not in use - but DST currently in effect ?')
151
152 global current_local_utc_offset_in_seconds
153 msg = 'DST currently%sin effect: using UTC offset of [%s] seconds instead of [%s] seconds'
154 if dst_currently_in_effect:
155 current_local_utc_offset_in_seconds = time.altzone * -1
156 _log.debug(msg % (' ', time.altzone * -1, time.timezone * -1))
157 else:
158 current_local_utc_offset_in_seconds = time.timezone * -1
159 _log.debug(msg % (' not ', time.timezone * -1, time.altzone * -1))
160
161 if current_local_utc_offset_in_seconds > 0:
162 _log.debug('UTC offset is positive, assuming EAST of Greenwich (clock is "ahead")')
163 elif current_local_utc_offset_in_seconds < 0:
164 _log.debug('UTC offset is negative, assuming WEST of Greenwich (clock is "behind")')
165 else:
166 _log.debug('UTC offset is ZERO, assuming Greenwich Time')
167
168 global current_local_timezone_interval
169 current_local_timezone_interval = mxDT.now().gmtoffset()
170 _log.debug('ISO timezone: [%s] (taken from mx.DateTime.now().gmtoffset())' % current_local_timezone_interval)
171
172 global current_local_iso_numeric_timezone_string
173 current_local_iso_numeric_timezone_string = str(current_local_timezone_interval).replace(',', '.')
174
175 global current_local_timezone_name
176 try:
177 current_local_timezone_name = os.environ['TZ'].decode(gmI18N.get_encoding(), 'replace')
178 except KeyError:
179 if dst_currently_in_effect:
180 current_local_timezone_name = time.tzname[1].decode(gmI18N.get_encoding(), 'replace')
181 else:
182 current_local_timezone_name = time.tzname[0].decode(gmI18N.get_encoding(), 'replace')
183
184 # do some magic to convert Python's timezone to a valid ISO timezone
185 # is this safe or will it return things like 13.5 hours ?
186 #_default_client_timezone = "%+.1f" % (-tz / 3600.0)
187 #_log.info('assuming default client time zone of [%s]' % _default_client_timezone)
188
189 global gmCurrentLocalTimezone
190 gmCurrentLocalTimezone = cFixedOffsetTimezone (
191 offset = (current_local_utc_offset_in_seconds / 60),
192 name = current_local_iso_numeric_timezone_string
193 )
194 #===========================================================================
196 """Returns NOW @ HERE (IOW, in the local timezone."""
197 return pyDT.datetime.now(gmCurrentLocalTimezone)
198 #===========================================================================
199 # wxPython conversions
200 #---------------------------------------------------------------------------
202 if not wxDate.IsValid():
203 raise ArgumentError (u'invalid wxDate: %s-%s-%s %s:%s %s.%s',
204 wxDate.GetYear(),
205 wxDate.GetMonth(),
206 wxDate.GetDay(),
207 wxDate.GetHour(),
208 wxDate.GetMinute(),
209 wxDate.GetSecond(),
210 wxDate.GetMillisecond()
211 )
212
213 try:
214 return pyDT.datetime (
215 year = wxDate.GetYear(),
216 month = wxDate.GetMonth() + 1,
217 day = wxDate.GetDay(),
218 tzinfo = gmCurrentLocalTimezone
219 )
220 except:
221 _log.debug (u'error converting wxDateTime to Python: %s-%s-%s %s:%s %s.%s',
222 wxDate.GetYear(),
223 wxDate.GetMonth(),
224 wxDate.GetDay(),
225 wxDate.GetHour(),
226 wxDate.GetMinute(),
227 wxDate.GetSecond(),
228 wxDate.GetMillisecond()
229 )
230 raise
231 #---------------------------------------------------------------------------
233 wxdt = wx.DateTime()
234 wxdt.SetYear(py_dt.year)
235 wxdt.SetMonth(py_dt.month-1)
236 wxdt.SetDay(py_dt.day)
237 return wxdt
238 #===========================================================================
239 # interval related
240 #---------------------------------------------------------------------------
242
243 years, days = divmod(interval.days, avg_days_per_gregorian_year)
244 months, days = divmod(days, avg_days_per_gregorian_month)
245 weeks, days = divmod(days, days_per_week)
246 days, secs = divmod((days * avg_seconds_per_day) + interval.seconds, avg_seconds_per_day)
247 hours, secs = divmod(secs, 3600)
248 mins, secs = divmod(secs, 60)
249
250 tmp = u''
251
252 if years > 0:
253 tmp += u'%s%s' % (int(years), _('interval_format_tag::years::y')[-1:])
254
255 if accuracy_wanted < acc_months:
256 return tmp.strip()
257
258 if months > 0:
259 tmp += u' %s%s' % (int(months), _('interval_format_tag::months::m')[-1:])
260
261 if accuracy_wanted < acc_weeks:
262 return tmp.strip()
263
264 if weeks > 0:
265 tmp += u' %s%s' % (int(weeks), _('interval_format_tag::weeks::w')[-1:])
266
267 if accuracy_wanted < acc_days:
268 return tmp.strip()
269
270 if days > 0:
271 tmp += u' %s%s' % (int(days), _('interval_format_tag::days::d')[-1:])
272
273 if accuracy_wanted < acc_hours:
274 return tmp.strip()
275
276 if hours > 0:
277 tmp += u' %s/24' % int(hours)
278
279 if accuracy_wanted < acc_minutes:
280 return tmp.strip()
281
282 if mins > 0:
283 tmp += u' %s/60' % int(mins)
284
285 if accuracy_wanted < acc_seconds:
286 return tmp.strip()
287
288 if secs > 0:
289 tmp += u' %s/60' % int(secs)
290
291 return tmp.strip()
292 #---------------------------------------------------------------------------
294 """Formats an interval.
295
296 This isn't mathematically correct but close enough for display.
297 """
298 # FIXME: i18n for abbrevs
299
300 # more than 1 year ?
301 if interval.days > 363:
302 years, days = divmod(interval.days, 364)
303 leap_days, tmp = divmod(years, 4)
304 months, day = divmod((days + leap_days), 30.33)
305 if int(months) == 0:
306 return "%sy" % int(years)
307 return "%sy %sm" % (int(years), int(months))
308
309 # more than 30 days / 1 month ?
310 if interval.days > 30:
311 months, days = divmod(interval.days, 30.33)
312 weeks, days = divmod(days, 7)
313 if int(weeks + days) == 0:
314 result = '%smo' % int(months)
315 else:
316 result = '%sm' % int(months)
317 if int(weeks) != 0:
318 result += ' %sw' % int(weeks)
319 if int(days) != 0:
320 result += ' %sd' % int(days)
321 return result
322
323 # between 7 and 30 days ?
324 if interval.days > 7:
325 return "%sd" % interval.days
326
327 # between 1 and 7 days ?
328 if interval.days > 0:
329 hours, seconds = divmod(interval.seconds, 3600)
330 if hours == 0:
331 return '%sd' % interval.days
332 return "%sd (%sh)" % (interval.days, int(hours))
333
334 # between 5 hours and 1 day
335 if interval.seconds > (5*3600):
336 return "%sh" % int(interval.seconds // 3600)
337
338 # between 1 and 5 hours
339 if interval.seconds > 3600:
340 hours, seconds = divmod(interval.seconds, 3600)
341 minutes = seconds // 60
342 if minutes == 0:
343 return '%sh' % int(hours)
344 return "%s:%02d" % (int(hours), int(minutes))
345
346 # minutes only
347 if interval.seconds > (5*60):
348 return "0:%02d" % (int(interval.seconds // 60))
349
350 # seconds
351 minutes, seconds = divmod(interval.seconds, 60)
352 if minutes == 0:
353 return '%ss' % int(seconds)
354 if seconds == 0:
355 return '0:%02d' % int(minutes)
356 return "%s.%ss" % (int(minutes), int(seconds))
357 #---------------------------------------------------------------------------
359
360 unit_keys = {
361 'year': _('yYaA_keys_year'),
362 'month': _('mM_keys_month'),
363 'week': _('wW_keys_week'),
364 'day': _('dD_keys_day'),
365 'hour': _('hH_keys_hour')
366 }
367
368 str_interval = str_interval.strip()
369
370 # "(~)35(yY)" - at age 35 years
371 keys = '|'.join(list(unit_keys['year'].replace('_keys_year', u'')))
372 if regex.match(u'^~*(\s|\t)*\d+(%s)*$' % keys, str_interval, flags = regex.LOCALE | regex.UNICODE):
373 return pyDT.timedelta(days = (int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]) * avg_days_per_gregorian_year))
374
375 # "(~)12mM" - at age 12 months
376 keys = '|'.join(list(unit_keys['month'].replace('_keys_month', u'')))
377 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*(%s)+$' % keys, str_interval, flags = regex.LOCALE | regex.UNICODE):
378 years, months = divmod (
379 int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]),
380 12
381 )
382 return pyDT.timedelta(days = ((years * avg_days_per_gregorian_year) + (months * avg_days_per_gregorian_month)))
383
384 # weeks
385 keys = '|'.join(list(unit_keys['week'].replace('_keys_week', u'')))
386 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*(%s)+$' % keys, str_interval, flags = regex.LOCALE | regex.UNICODE):
387 return pyDT.timedelta(weeks = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
388
389 # days
390 keys = '|'.join(list(unit_keys['day'].replace('_keys_day', u'')))
391 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*(%s)+$' % keys, str_interval, flags = regex.LOCALE | regex.UNICODE):
392 return pyDT.timedelta(days = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
393
394 # hours
395 keys = '|'.join(list(unit_keys['hour'].replace('_keys_hour', u'')))
396 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*(%s)+$' % keys, str_interval, flags = regex.LOCALE | regex.UNICODE):
397 return pyDT.timedelta(hours = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
398
399 # x/12 - months
400 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*/(\s|\t)*12$', str_interval, flags = regex.LOCALE | regex.UNICODE):
401 years, months = divmod (
402 int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]),
403 12
404 )
405 return pyDT.timedelta(days = ((years * avg_days_per_gregorian_year) + (months * avg_days_per_gregorian_month)))
406
407 # x/52 - weeks
408 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*/(\s|\t)*52$', str_interval, flags = regex.LOCALE | regex.UNICODE):
409 # return pyDT.timedelta(days = (int(regex.findall('\d+', str_interval)[0]) * days_per_week))
410 return pyDT.timedelta(weeks = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
411
412 # x/7 - days
413 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*/(\s|\t)*7$', str_interval, flags = regex.LOCALE | regex.UNICODE):
414 return pyDT.timedelta(days = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
415
416 # x/24 - hours
417 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*/(\s|\t)*24$', str_interval, flags = regex.LOCALE | regex.UNICODE):
418 return pyDT.timedelta(hours = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
419
420 # x/60 - minutes
421 if regex.match(u'^~*(\s|\t)*\d+(\s|\t)*/(\s|\t)*60$', str_interval, flags = regex.LOCALE | regex.UNICODE):
422 return pyDT.timedelta(minutes = int(regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)[0]))
423
424 # nYnM - years, months
425 keys_year = '|'.join(list(unit_keys['year'].replace('_keys_year', u'')))
426 keys_month = '|'.join(list(unit_keys['month'].replace('_keys_month', u'')))
427 if regex.match(u'^~*(\s|\t)*\d+(%s|\s|\t)+\d+(\s|\t)*(%s)+$' % (keys_year, keys_month), str_interval, flags = regex.LOCALE | regex.UNICODE):
428 parts = regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)
429 years, months = divmod(int(parts[1]), 12)
430 years += int(parts[0])
431 return pyDT.timedelta(days = ((years * avg_days_per_gregorian_year) + (months * avg_days_per_gregorian_month)))
432
433 # nMnW - months, weeks
434 keys_month = '|'.join(list(unit_keys['month'].replace('_keys_month', u'')))
435 keys_week = '|'.join(list(unit_keys['week'].replace('_keys_week', u'')))
436 if regex.match(u'^~*(\s|\t)*\d+(%s|\s|\t)+\d+(\s|\t)*(%s)+$' % (keys_month, keys_week), str_interval, flags = regex.LOCALE | regex.UNICODE):
437 parts = regex.findall(u'\d+', str_interval, flags = regex.LOCALE | regex.UNICODE)
438 months, weeks = divmod(int(parts[1]), 4)
439 months += int(parts[0])
440 return pyDT.timedelta(days = ((months * avg_days_per_gregorian_month) + (weeks * days_per_week)))
441
442 return None
443
444 #===========================================================================
445 # string -> timestamp parsers
446 #---------------------------------------------------------------------------
448 """
449 Default is 'hdwm':
450 h - hours
451 d - days
452 w - weeks
453 m - months
454 y - years
455
456 This also defines the significance of the order of the characters.
457 """
458 if offset_chars is None:
459 offset_chars = _('hdwmy (single character date offset triggers)')[:5].lower()
460
461 # "+/-XXd/w/m/t"
462 if not regex.match(u"^(\s|\t)*(\+|-)?(\s|\t)*\d{1,2}(\s|\t)*[%s](\s|\t)*$" % offset_chars, str2parse, flags = regex.LOCALE | regex.UNICODE):
463 return []
464 val = int(regex.findall(u'\d{1,2}', str2parse, flags = regex.LOCALE | regex.UNICODE)[0])
465 offset_char = regex.findall(u'[%s]' % offset_chars, str2parse, flags = regex.LOCALE | regex.UNICODE)[0].lower()
466
467 now = mxDT.now()
468 enc = gmI18N.get_encoding()
469
470 # allow past ?
471 is_future = True
472 if str2parse.find('-') > -1:
473 is_future = False
474
475 ts = None
476 # hours
477 if offset_char == offset_chars[0]:
478 if is_future:
479 ts = now + mxDT.RelativeDateTime(hours = val)
480 label = _('in %d hour(s) - %s') % (val, ts.strftime('%H:%M'))
481 else:
482 ts = now - mxDT.RelativeDateTime(hours = val)
483 label = _('%d hour(s) ago - %s') % (val, ts.strftime('%H:%M'))
484 accuracy = acc_subseconds
485 # days
486 elif offset_char == offset_chars[1]:
487 if is_future:
488 ts = now + mxDT.RelativeDateTime(days = val)
489 label = _('in %d day(s) - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
490 else:
491 ts = now - mxDT.RelativeDateTime(days = val)
492 label = _('%d day(s) ago - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
493 accuracy = acc_days
494 # weeks
495 elif offset_char == offset_chars[2]:
496 if is_future:
497 ts = now + mxDT.RelativeDateTime(weeks = val)
498 label = _('in %d week(s) - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
499 else:
500 ts = now - mxDT.RelativeDateTime(weeks = val)
501 label = _('%d week(s) ago - %s)') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
502 accuracy = acc_days
503 # months
504 elif offset_char == offset_chars[3]:
505 if is_future:
506 ts = now + mxDT.RelativeDateTime(months = val)
507 label = _('in %d month(s) - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
508 else:
509 ts = now - mxDT.RelativeDateTime(months = val)
510 label = _('%d month(s) ago - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
511 accuracy = acc_days
512 # years
513 elif offset_char == offset_chars[4]:
514 if is_future:
515 ts = now + mxDT.RelativeDateTime(years = val)
516 label = _('in %d year(s) - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
517 else:
518 ts = now - mxDT.RelativeDateTime(years = val)
519 label = _('%d year(s) ago - %s') % (val, ts.strftime('%A, %Y-%m-%d').decode(enc))
520 accuracy = acc_months
521
522 if ts is None:
523 return []
524
525 tmp = {
526 'data': cFuzzyTimestamp(timestamp = ts, accuracy = accuracy),
527 'label': label
528 }
529 return [tmp]
530 #---------------------------------------------------------------------------
532 """This matches on single characters.
533
534 Spaces and tabs are discarded.
535
536 Default is 'ndmy':
537 n - now
538 d - toDay
539 m - toMorrow Someone please suggest a synonym !
540 y - yesterday
541
542 This also defines the significance of the order of the characters.
543 """
544 if trigger_chars is None:
545 trigger_chars = _('ndmy (single character date triggers)')[:4].lower()
546
547 if not regex.match(u'^(\s|\t)*[%s]{1}(\s|\t)*$' % trigger_chars, str2parse, flags = regex.LOCALE | regex.UNICODE):
548 return []
549 val = str2parse.strip().lower()
550
551 now = mxDT.now()
552 enc = gmI18N.get_encoding()
553
554 # FIXME: handle uebermorgen/vorgestern ?
555
556 # right now
557 if val == trigger_chars[0]:
558 ts = now
559 return [{
560 'data': cFuzzyTimestamp (
561 timestamp = ts,
562 accuracy = acc_subseconds
563 ),
564 'label': _('right now (%s, %s)') % (ts.strftime('%A').decode(enc), ts)
565 }]
566
567 # today
568 if val == trigger_chars[1]:
569 return [{
570 'data': cFuzzyTimestamp (
571 timestamp = now,
572 accuracy = acc_days
573 ),
574 'label': _('today (%s)') % now.strftime('%A, %Y-%m-%d').decode(enc)
575 }]
576
577 # tomorrow
578 if val == trigger_chars[2]:
579 ts = now + mxDT.RelativeDateTime(days = +1)
580 return [{
581 'data': cFuzzyTimestamp (
582 timestamp = ts,
583 accuracy = acc_days
584 ),
585 'label': _('tomorrow (%s)') % ts.strftime('%A, %Y-%m-%d').decode(enc)
586 }]
587
588 # yesterday
589 if val == trigger_chars[3]:
590 ts = now + mxDT.RelativeDateTime(days = -1)
591 return [{
592 'data': cFuzzyTimestamp (
593 timestamp = ts,
594 accuracy = acc_days
595 ),
596 'label': _('yesterday (%s)') % ts.strftime('%A, %Y-%m-%d').decode(enc)
597 }]
598
599 return []
600 #---------------------------------------------------------------------------
602 """Expand fragments containing a single slash.
603
604 "5/"
605 - 2005/ (2000 - 2025)
606 - 1995/ (1990 - 1999)
607 - Mai/current year
608 - Mai/next year
609 - Mai/last year
610 - Mai/200x
611 - Mai/20xx
612 - Mai/199x
613 - Mai/198x
614 - Mai/197x
615 - Mai/19xx
616 """
617 matches = []
618 now = mxDT.now()
619 if regex.match(u"^(\s|\t)*\d{1,2}(\s|\t)*/+(\s|\t)*$", str2parse, flags = regex.LOCALE | regex.UNICODE):
620 val = int(regex.findall(u'\d+', str2parse, flags = regex.LOCALE | regex.UNICODE)[0])
621
622 if val < 100 and val >= 0:
623 matches.append ({
624 'data': None,
625 'label': '%s/' % (val + 1900)
626 })
627
628 if val < 26 and val >= 0:
629 matches.append ({
630 'data': None,
631 'label': '%s/' % (val + 2000)
632 })
633
634 if val < 10 and val >= 0:
635 matches.append ({
636 'data': None,
637 'label': '%s/' % (val + 1990)
638 })
639
640 if val < 13 and val > 0:
641 matches.append ({
642 'data': cFuzzyTimestamp(timestamp = now, accuracy = acc_months),
643 'label': '%.2d/%s' % (val, now.year)
644 })
645 ts = now + mxDT.RelativeDateTime(years = 1)
646 matches.append ({
647 'data': cFuzzyTimestamp(timestamp = ts, accuracy = acc_months),
648 'label': '%.2d/%s' % (val, ts.year)
649 })
650 ts = now + mxDT.RelativeDateTime(years = -1)
651 matches.append ({
652 'data': cFuzzyTimestamp(timestamp = ts, accuracy = acc_months),
653 'label': '%.2d/%s' % (val, ts.year)
654 })
655 matches.append ({
656 'data': None,
657 'label': '%.2d/200' % val
658 })
659 matches.append ({
660 'data': None,
661 'label': '%.2d/20' % val
662 })
663 matches.append ({
664 'data': None,
665 'label': '%.2d/199' % val
666 })
667 matches.append ({
668 'data': None,
669 'label': '%.2d/198' % val
670 })
671 matches.append ({
672 'data': None,
673 'label': '%.2d/197' % val
674 })
675 matches.append ({
676 'data': None,
677 'label': '%.2d/19' % val
678 })
679
680 elif regex.match(u"^(\s|\t)*\d{1,2}(\s|\t)*/+(\s|\t)*\d{4}(\s|\t)*$", str2parse, flags = regex.LOCALE | regex.UNICODE):
681 parts = regex.findall(u'\d+', str2parse, flags = regex.LOCALE | regex.UNICODE)
682 fts = cFuzzyTimestamp (
683 timestamp = mxDT.now() + mxDT.RelativeDateTime(year = int(parts[1]), month = int(parts[0])),
684 accuracy = acc_months
685 )
686 matches.append ({
687 'data': fts,
688 'label': fts.format_accurately()
689 })
690
691 return matches
692 #---------------------------------------------------------------------------
694 """This matches on single numbers.
695
696 Spaces or tabs are discarded.
697 """
698 if not regex.match(u"^(\s|\t)*\d{1,4}(\s|\t)*$", str2parse, flags = regex.LOCALE | regex.UNICODE):
699 return []
700
701 # strftime() returns str but in the localized encoding,
702 # so we may need to decode that to unicode
703 enc = gmI18N.get_encoding()
704 now = mxDT.now()
705 val = int(regex.findall(u'\d{1,4}', str2parse, flags = regex.LOCALE | regex.UNICODE)[0])
706
707 matches = []
708
709 # that year
710 if (1850 < val) and (val < 2100):
711 ts = now + mxDT.RelativeDateTime(year = val)
712 target_date = cFuzzyTimestamp (
713 timestamp = ts,
714 accuracy = acc_years
715 )
716 tmp = {
717 'data': target_date,
718 'label': '%s' % target_date
719 }
720 matches.append(tmp)
721
722 # day X of this month
723 if val <= gregorian_month_length[now.month]:
724 ts = now + mxDT.RelativeDateTime(day = val)
725 target_date = cFuzzyTimestamp (
726 timestamp = ts,
727 accuracy = acc_days
728 )
729 tmp = {
730 'data': target_date,
731 'label': _('%d. of %s (this month) - a %s') % (val, ts.strftime('%B').decode(enc), ts.strftime('%A').decode(enc))
732 }
733 matches.append(tmp)
734
735 # day X of next month
736 if val <= gregorian_month_length[(now + mxDT.RelativeDateTime(months = 1)).month]:
737 ts = now + mxDT.RelativeDateTime(months = 1, day = val)
738 target_date = cFuzzyTimestamp (
739 timestamp = ts,
740 accuracy = acc_days
741 )
742 tmp = {
743 'data': target_date,
744 'label': _('%d. of %s (next month) - a %s') % (val, ts.strftime('%B').decode(enc), ts.strftime('%A').decode(enc))
745 }
746 matches.append(tmp)
747
748 # day X of last month
749 if val <= gregorian_month_length[(now + mxDT.RelativeDateTime(months = -1)).month]:
750 ts = now + mxDT.RelativeDateTime(months = -1, day = val)
751 target_date = cFuzzyTimestamp (
752 timestamp = ts,
753 accuracy = acc_days
754 )
755 tmp = {
756 'data': target_date,
757 'label': _('%d. of %s (last month) - a %s') % (val, ts.strftime('%B').decode(enc), ts.strftime('%A').decode(enc))
758 }
759 matches.append(tmp)
760
761 # X days from now
762 if val <= 400: # more than a year ahead in days ?? nah !
763 ts = now + mxDT.RelativeDateTime(days = val)
764 target_date = cFuzzyTimestamp (
765 timestamp = ts
766 )
767 tmp = {
768 'data': target_date,
769 'label': _('in %d day(s) - %s') % (val, target_date.timestamp.strftime('%A, %Y-%m-%d').decode(enc))
770 }
771 matches.append(tmp)
772
773 # X weeks from now
774 if val <= 50: # pregnancy takes about 40 weeks :-)
775 ts = now + mxDT.RelativeDateTime(weeks = val)
776 target_date = cFuzzyTimestamp (
777 timestamp = ts
778 )
779 tmp = {
780 'data': target_date,
781 'label': _('in %d week(s) - %s') % (val, target_date.timestamp.strftime('%A, %Y-%m-%d').decode(enc))
782 }
783 matches.append(tmp)
784
785 # month X of ...
786 if val < 13:
787 # ... this year
788 ts = now + mxDT.RelativeDateTime(month = val)
789 target_date = cFuzzyTimestamp (
790 timestamp = ts,
791 accuracy = acc_months
792 )
793 tmp = {
794 'data': target_date,
795 'label': _('%s (%s this year)') % (target_date, ts.strftime('%B').decode(enc))
796 }
797 matches.append(tmp)
798
799 # ... next year
800 ts = now + mxDT.RelativeDateTime(years = 1, month = val)
801 target_date = cFuzzyTimestamp (
802 timestamp = ts,
803 accuracy = acc_months
804 )
805 tmp = {
806 'data': target_date,
807 'label': _('%s (%s next year)') % (target_date, ts.strftime('%B').decode(enc))
808 }
809 matches.append(tmp)
810
811 # ... last year
812 ts = now + mxDT.RelativeDateTime(years = -1, month = val)
813 target_date = cFuzzyTimestamp (
814 timestamp = ts,
815 accuracy = acc_months
816 )
817 tmp = {
818 'data': target_date,
819 'label': _('%s (%s last year)') % (target_date, ts.strftime('%B').decode(enc))
820 }
821 matches.append(tmp)
822
823 # fragment expansion
824 matches.append ({
825 'data': None,
826 'label': '%s/200' % val
827 })
828 matches.append ({
829 'data': None,
830 'label': '%s/199' % val
831 })
832 matches.append ({
833 'data': None,
834 'label': '%s/198' % val
835 })
836 matches.append ({
837 'data': None,
838 'label': '%s/19' % val
839 })
840
841 # day X of ...
842 if val < 8:
843 # ... this week
844 ts = now + mxDT.RelativeDateTime(weekday = (val-1, 0))
845 target_date = cFuzzyTimestamp (
846 timestamp = ts,
847 accuracy = acc_days
848 )
849 tmp = {
850 'data': target_date,
851 'label': _('%s this week (%s of %s)') % (ts.strftime('%A').decode(enc), ts.day, ts.strftime('%B').decode(enc))
852 }
853 matches.append(tmp)
854
855 # ... next week
856 ts = now + mxDT.RelativeDateTime(weeks = +1, weekday = (val-1, 0))
857 target_date = cFuzzyTimestamp (
858 timestamp = ts,
859 accuracy = acc_days
860 )
861 tmp = {
862 'data': target_date,
863 'label': _('%s next week (%s of %s)') % (ts.strftime('%A').decode(enc), ts.day, ts.strftime('%B').decode(enc))
864 }
865 matches.append(tmp)
866
867 # ... last week
868 ts = now + mxDT.RelativeDateTime(weeks = -1, weekday = (val-1, 0))
869 target_date = cFuzzyTimestamp (
870 timestamp = ts,
871 accuracy = acc_days
872 )
873 tmp = {
874 'data': target_date,
875 'label': _('%s last week (%s of %s)') % (ts.strftime('%A').decode(enc), ts.day, ts.strftime('%B').decode(enc))
876 }
877 matches.append(tmp)
878
879 if val < 100:
880 matches.append ({
881 'data': None,
882 'label': '%s/' % (1900 + val)
883 })
884
885 if val == 200:
886 tmp = {
887 'data': cFuzzyTimestamp(timestamp = now, accuracy = acc_days),
888 'label': '%s' % target_date
889 }
890 matches.append(tmp)
891 matches.append ({
892 'data': cFuzzyTimestamp(timestamp = now, accuracy = acc_months),
893 'label': '%.2d/%s' % (now.month, now.year)
894 })
895 matches.append ({
896 'data': None,
897 'label': '%s/' % now.year
898 })
899 matches.append ({
900 'data': None,
901 'label': '%s/' % (now.year + 1)
902 })
903 matches.append ({
904 'data': None,
905 'label': '%s/' % (now.year - 1)
906 })
907
908 if val < 200 and val >= 190:
909 for i in range(10):
910 matches.append ({
911 'data': None,
912 'label': '%s%s/' % (val, i)
913 })
914
915 return matches
916 #---------------------------------------------------------------------------
918 """Expand fragments containing a single dot.
919
920 Standard colloquial date format in Germany: day.month.year
921
922 "14."
923 - 14th current month this year
924 - 14th next month this year
925 """
926 if not regex.match(u"^(\s|\t)*\d{1,2}\.{1}(\s|\t)*$", str2parse, flags = regex.LOCALE | regex.UNICODE):
927 return []
928
929 val = int(regex.findall(u'\d+', str2parse, flags = regex.LOCALE | regex.UNICODE)[0])
930 now = mxDT.now()
931 enc = gmI18N.get_encoding()
932
933 matches = []
934
935 # day X of this month
936 ts = now + mxDT.RelativeDateTime(day = val)
937 if val > 0 and val <= gregorian_month_length[ts.month]:
938 matches.append ({
939 'data': cFuzzyTimestamp(timestamp = ts, accuracy = acc_days),
940 'label': '%s.%s.%s - a %s this month' % (ts.day, ts.month, ts.year, ts.strftime('%A').decode(enc))
941 })
942
943 # day X of next month
944 ts = now + mxDT.RelativeDateTime(day = val, months = +1)
945 if val > 0 and val <= gregorian_month_length[ts.month]:
946 matches.append ({
947 'data': cFuzzyTimestamp(timestamp = ts, accuracy = acc_days),
948 'label': '%s.%s.%s - a %s next month' % (ts.day, ts.month, ts.year, ts.strftime('%A').decode(enc))
949 })
950
951 # day X of last month
952 ts = now + mxDT.RelativeDateTime(day = val, months = -1)
953 if val > 0 and val <= gregorian_month_length[ts.month]:
954 matches.append ({
955 'data': cFuzzyTimestamp(timestamp = ts, accuracy = acc_days),
956 'label': '%s.%s.%s - a %s last month' % (ts.day, ts.month, ts.year, ts.strftime('%A').decode(enc))
957 })
958
959 return matches
960 #---------------------------------------------------------------------------
962 """
963 Turn a string into candidate fuzzy timestamps and auto-completions the user is likely to type.
964
965 You MUST have called locale.setlocale(locale.LC_ALL, '')
966 somewhere in your code previously.
967
968 @param default_time: if you want to force the time part of the time
969 stamp to a given value and the user doesn't type any time part
970 this value will be used
971 @type default_time: an mx.DateTime.DateTimeDelta instance
972
973 @param patterns: list of [time.strptime compatible date/time pattern, accuracy]
974 @type patterns: list
975 """
976 matches = __single_dot(str2parse)
977 matches.extend(__numbers_only(str2parse))
978 matches.extend(__single_slash(str2parse))
979 matches.extend(__single_char(str2parse))
980 matches.extend(__explicit_offset(str2parse))
981
982 # try mxDT parsers
983 if mxDT is not None:
984 try:
985 # date ?
986 date_only = mxDT.Parser.DateFromString (
987 text = str2parse,
988 formats = ('euro', 'iso', 'us', 'altus', 'altiso', 'lit', 'altlit', 'eurlit')
989 )
990 # time, too ?
991 time_part = mxDT.Parser.TimeFromString(text = str2parse)
992 datetime = date_only + time_part
993 if datetime == date_only:
994 accuracy = acc_days
995 if isinstance(default_time, mxDT.DateTimeDeltaType):
996 datetime = date_only + default_time
997 accuracy = acc_minutes
998 else:
999 accuracy = acc_subseconds
1000 fts = cFuzzyTimestamp (
1001 timestamp = datetime,
1002 accuracy = accuracy
1003 )
1004 matches.append ({
1005 'data': fts,
1006 'label': fts.format_accurately()
1007 })
1008 except (ValueError, mxDT.RangeError):
1009 pass
1010
1011 if patterns is None:
1012 patterns = []
1013
1014 patterns.append(['%Y.%m.%d', acc_days])
1015 patterns.append(['%Y/%m/%d', acc_days])
1016
1017 for pattern in patterns:
1018 try:
1019 fts = cFuzzyTimestamp (
1020 timestamp = pyDT.datetime.fromtimestamp(time.mktime(time.strptime(str2parse, pattern[0]))),
1021 accuracy = pattern[1]
1022 )
1023 matches.append ({
1024 'data': fts,
1025 'label': fts.format_accurately()
1026 })
1027 except AttributeError:
1028 # strptime() only available starting with Python 2.5
1029 break
1030 except OverflowError:
1031 # time.mktime() cannot handle dates older than a platform-dependant limit :-(
1032 continue
1033 except ValueError:
1034 # C-level overflow
1035 continue
1036
1037 return matches
1038 #===========================================================================
1039 # fuzzy timestamp class
1040 #---------------------------------------------------------------------------
1042
1043 # FIXME: add properties for year, month, ...
1044
1045 """A timestamp implementation with definable inaccuracy.
1046
1047 This class contains an mxDateTime.DateTime instance to
1048 hold the actual timestamp. It adds an accuracy attribute
1049 to allow the programmer to set the precision of the
1050 timestamp.
1051
1052 The timestamp will have to be initialzed with a fully
1053 precise value (which may, of course, contain partially
1054 fake data to make up for missing values). One can then
1055 set the accuracy value to indicate up to which part of
1056 the timestamp the data is valid. Optionally a modifier
1057 can be set to indicate further specification of the
1058 value (such as "summer", "afternoon", etc).
1059
1060 accuracy values:
1061 1: year only
1062 ...
1063 7: everything including milliseconds value
1064
1065 Unfortunately, one cannot directly derive a class from mx.DateTime.DateTime :-(
1066 """
1067 #-----------------------------------------------------------------------
1069
1070 if timestamp is None:
1071 timestamp = mxDT.now()
1072 accuracy = acc_subseconds
1073 modifier = ''
1074
1075 if isinstance(timestamp, pyDT.datetime):
1076 timestamp = mxDT.DateTime(timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second)
1077
1078 if type(timestamp) != mxDT.DateTimeType:
1079 raise TypeError, '%s.__init__(): <timestamp> must be of mx.DateTime.DateTime or datetime.datetime type' % self.__class__.__name__
1080
1081 self.timestamp = timestamp
1082
1083 if (accuracy < 1) or (accuracy > 8):
1084 raise ValueError, '%s.__init__(): <accuracy> must be between 1 and 7' % self.__class__.__name__
1085 self.accuracy = accuracy
1086
1087 self.modifier = modifier
1088
1089 #-----------------------------------------------------------------------
1090 # magic API
1091 #-----------------------------------------------------------------------
1093 """Return string representation meaningful to a user, also for %s formatting."""
1094 return self.format_accurately()
1095 #-----------------------------------------------------------------------
1097 """Return string meaningful to a programmer to aid in debugging."""
1098 tmp = '<[%s]: timestamp [%s], accuracy [%s] (%s), modifier [%s] at %s>' % (
1099 self.__class__.__name__,
1100 repr(self.timestamp),
1101 self.accuracy,
1102 _accuracy_strings[self.accuracy],
1103 self.modifier,
1104 id(self)
1105 )
1106 return tmp
1107 #-----------------------------------------------------------------------
1108 # external API
1109 #-----------------------------------------------------------------------
1111 if self.accuracy == 7:
1112 return self.timestamp.strftime(format_string)
1113 return self.format_accurately()
1114 #-----------------------------------------------------------------------
1116 return self.strftime(format_string)
1117 #-----------------------------------------------------------------------
1119 if self.accuracy == acc_years:
1120 return unicode(self.timestamp.year)
1121
1122 if self.accuracy == acc_months:
1123 return unicode(self.timestamp.strftime('%m/%Y')) # FIXME: use 3-letter month ?
1124
1125 if self.accuracy == acc_days:
1126 return unicode(self.timestamp.strftime('%Y-%m-%d'))
1127
1128 if self.accuracy == acc_hours:
1129 return unicode(self.timestamp.strftime("%Y-%m-%d %I%p"))
1130
1131 if self.accuracy == acc_minutes:
1132 return unicode(self.timestamp.strftime("%Y-%m-%d %H:%M"))
1133
1134 if self.accuracy == acc_seconds:
1135 return unicode(self.timestamp.strftime("%Y-%m-%d %H:%M:%S"))
1136
1137 if self.accuracy == acc_subseconds:
1138 return unicode(self.timestamp)
1139
1140 raise ValueError, '%s.format_accurately(): <accuracy> (%s) must be between 1 and 7' % (
1141 self.__class__.__name__,
1142 self.accuracy
1143 )
1144 #-----------------------------------------------------------------------
1147 #-----------------------------------------------------------------------
1149 try:
1150 gmtoffset = self.timestamp.gmtoffset()
1151 except mxDT.Error:
1152 # Windows cannot deal with dates < 1970, so
1153 # when that happens switch to now()
1154 now = mxDT.now()
1155 gmtoffset = now.gmtoffset()
1156 tz = cFixedOffsetTimezone(gmtoffset.minutes, self.timestamp.tz)
1157 secs, msecs = divmod(self.timestamp.second, 1)
1158 ts = pyDT.datetime (
1159 year = self.timestamp.year,
1160 month = self.timestamp.month,
1161 day = self.timestamp.day,
1162 hour = self.timestamp.hour,
1163 minute = self.timestamp.minute,
1164 second = secs,
1165 microsecond = msecs,
1166 tzinfo = tz
1167 )
1168 return ts
1169 #===========================================================================
1170 # main
1171 #---------------------------------------------------------------------------
1172 if __name__ == '__main__':
1173
1174 intervals_as_str = [
1175 '7', '12', ' 12', '12 ', ' 12 ', ' 12 ', '0', '~12', '~ 12', ' ~ 12', ' ~ 12 ',
1176 '12a', '12 a', '12 a', '12j', '12J', '12y', '12Y', ' ~ 12 a ', '~0a',
1177 '12m', '17 m', '12 m', '17M', ' ~ 17 m ', ' ~ 3 / 12 ', '7/12', '0/12',
1178 '12w', '17 w', '12 w', '17W', ' ~ 17 w ', ' ~ 15 / 52', '2/52', '0/52',
1179 '12d', '17 d', '12 t', '17D', ' ~ 17 T ', ' ~ 12 / 7', '3/7', '0/7',
1180 '12h', '17 h', '12 H', '17H', ' ~ 17 h ', ' ~ 36 / 24', '7/24', '0/24',
1181 ' ~ 36 / 60', '7/60', '190/60', '0/60',
1182 '12a1m', '12 a 1 M', '12 a17m', '12j 12m', '12J7m', '12y7m', '12Y7M', ' ~ 12 a 37 m ', '~0a0m',
1183 '10m1w',
1184 'invalid interval input'
1185 ]
1186 #-----------------------------------------------------------------------
1188 for tmp in intervals_as_str:
1189 intv = str2interval(str_interval = tmp)
1190 for acc in _accuracy_strings.keys():
1191 print '[%s]: "%s" -> "%s"' % (acc, tmp, format_interval(intv, acc))
1192 #-----------------------------------------------------------------------
1194
1195 intervals = [
1196 pyDT.timedelta(seconds = 1),
1197 pyDT.timedelta(seconds = 5),
1198 pyDT.timedelta(seconds = 30),
1199 pyDT.timedelta(seconds = 60),
1200 pyDT.timedelta(seconds = 94),
1201 pyDT.timedelta(seconds = 120),
1202 pyDT.timedelta(minutes = 5),
1203 pyDT.timedelta(minutes = 30),
1204 pyDT.timedelta(minutes = 60),
1205 pyDT.timedelta(minutes = 90),
1206 pyDT.timedelta(minutes = 120),
1207 pyDT.timedelta(minutes = 200),
1208 pyDT.timedelta(minutes = 400),
1209 pyDT.timedelta(minutes = 600),
1210 pyDT.timedelta(minutes = 800),
1211 pyDT.timedelta(minutes = 1100),
1212 pyDT.timedelta(minutes = 2000),
1213 pyDT.timedelta(minutes = 3500),
1214 pyDT.timedelta(minutes = 4000),
1215 pyDT.timedelta(hours = 1),
1216 pyDT.timedelta(hours = 2),
1217 pyDT.timedelta(hours = 4),
1218 pyDT.timedelta(hours = 8),
1219 pyDT.timedelta(hours = 12),
1220 pyDT.timedelta(hours = 20),
1221 pyDT.timedelta(hours = 23),
1222 pyDT.timedelta(hours = 24),
1223 pyDT.timedelta(hours = 25),
1224 pyDT.timedelta(hours = 30),
1225 pyDT.timedelta(hours = 48),
1226 pyDT.timedelta(hours = 98),
1227 pyDT.timedelta(hours = 120),
1228 pyDT.timedelta(days = 1),
1229 pyDT.timedelta(days = 2),
1230 pyDT.timedelta(days = 4),
1231 pyDT.timedelta(days = 16),
1232 pyDT.timedelta(days = 29),
1233 pyDT.timedelta(days = 30),
1234 pyDT.timedelta(days = 31),
1235 pyDT.timedelta(days = 37),
1236 pyDT.timedelta(days = 40),
1237 pyDT.timedelta(days = 47),
1238 pyDT.timedelta(days = 126),
1239 pyDT.timedelta(days = 127),
1240 pyDT.timedelta(days = 128),
1241 pyDT.timedelta(days = 300),
1242 pyDT.timedelta(days = 359),
1243 pyDT.timedelta(days = 360),
1244 pyDT.timedelta(days = 361),
1245 pyDT.timedelta(days = 362),
1246 pyDT.timedelta(days = 363),
1247 pyDT.timedelta(days = 364),
1248 pyDT.timedelta(days = 365),
1249 pyDT.timedelta(days = 366),
1250 pyDT.timedelta(days = 367),
1251 pyDT.timedelta(days = 400),
1252 pyDT.timedelta(weeks = 52 * 30),
1253 pyDT.timedelta(weeks = 52 * 79, days = 33)
1254 ]
1255
1256 idx = 1
1257 for intv in intervals:
1258 print '%s) %s -> %s' % (idx, intv, format_interval_medically(intv))
1259 idx += 1
1260 #-----------------------------------------------------------------------
1262 print "testing str2interval()"
1263 print "----------------------"
1264
1265 for interval_as_str in intervals_as_str:
1266 print "input: <%s>" % interval_as_str
1267 print " ==>", str2interval(str_interval=interval_as_str)
1268
1269 return True
1270 #-------------------------------------------------
1272 print "DST currently in effect:", dst_currently_in_effect
1273 print "current UTC offset:", current_local_utc_offset_in_seconds, "seconds"
1274 print "current timezone (interval):", current_local_timezone_interval
1275 print "current timezone (ISO conformant numeric string):", current_local_iso_numeric_timezone_string
1276 print "local timezone class:", cLocalTimezone
1277 print ""
1278 tz = cLocalTimezone()
1279 print "local timezone instance:", tz
1280 print " (total) UTC offset:", tz.utcoffset(pyDT.datetime.now())
1281 print " DST adjustment:", tz.dst(pyDT.datetime.now())
1282 print " timezone name:", tz.tzname(pyDT.datetime.now())
1283 print ""
1284 print "current local timezone:", gmCurrentLocalTimezone
1285 print " (total) UTC offset:", gmCurrentLocalTimezone.utcoffset(pyDT.datetime.now())
1286 print " DST adjustment:", gmCurrentLocalTimezone.dst(pyDT.datetime.now())
1287 print " timezone name:", gmCurrentLocalTimezone.tzname(pyDT.datetime.now())
1288 print ""
1289 print "now here:", pydt_now_here()
1290 print ""
1291 #-------------------------------------------------
1293 print "testing function str2fuzzy_timestamp_matches"
1294 print "--------------------------------------------"
1295
1296 val = None
1297 while val != 'exit':
1298 val = raw_input('Enter date fragment ("exit" quits): ')
1299 matches = str2fuzzy_timestamp_matches(str2parse = val)
1300 for match in matches:
1301 print 'label shown :', match['label']
1302 print 'data attached:', match['data']
1303 print ""
1304 print "---------------"
1305 #-------------------------------------------------
1307 print "testing fuzzy timestamp class"
1308 print "-----------------------------"
1309
1310 ts = mxDT.now()
1311 print "mx.DateTime timestamp", type(ts)
1312 print " print ... :", ts
1313 print " print '%%s' %% ...: %s" % ts
1314 print " str() :", str(ts)
1315 print " repr() :", repr(ts)
1316
1317 fts = cFuzzyTimestamp()
1318 print "\nfuzzy timestamp <%s '%s'>" % ('class', fts.__class__.__name__)
1319 for accuracy in range(1,8):
1320 fts.accuracy = accuracy
1321 print " accuracy : %s (%s)" % (accuracy, _accuracy_strings[accuracy])
1322 print " format_accurately:", fts.format_accurately()
1323 print " strftime() :", fts.strftime('%c')
1324 print " print ... :", fts
1325 print " print '%%s' %% ... : %s" % fts
1326 print " str() :", str(fts)
1327 print " repr() :", repr(fts)
1328 raw_input('press ENTER to continue')
1329 #-------------------------------------------------
1331 print "testing platform for handling dates before 1970"
1332 print "-----------------------------------------------"
1333 ts = mxDT.DateTime(1935, 4, 2)
1334 fts = cFuzzyTimestamp(timestamp=ts)
1335 print "fts :", fts
1336 print "fts.get_pydt():", fts.get_pydt()
1337 #-------------------------------------------------
1338 if len(sys.argv) > 1 and sys.argv[1] == "test":
1339
1340 # GNUmed libs
1341 gmI18N.activate_locale()
1342 gmI18N.install_domain('gnumed')
1343
1344 init()
1345
1346 #test_date_time()
1347 #test_str2fuzzy_timestamp_matches()
1348 #test_cFuzzyTimeStamp()
1349 #test_get_pydt()
1350 #test_str2interval()
1351 #test_format_interval()
1352 test_format_interval_medically()
1353
1354 #===========================================================================
1355
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Mon Jun 28 04:13:07 2010 | http://epydoc.sourceforge.net |