comparison roundup/date.py @ 4986:fe140bc0eaa9

Implement (and document) timezone offsets
author Ralf Schlatterbeck <rsc@runtux.com>
date Tue, 21 Apr 2015 17:33:06 +0200
parents 07c59221f363
children 03505579abef
comparison
equal deleted inserted replaced
4985:07c59221f363 4986:fe140bc0eaa9
36 date_re = re.compile(r'''^ 36 date_re = re.compile(r'''^
37 ((?P<y>\d\d\d\d)([/-](?P<m>\d\d?)([/-](?P<d>\d\d?))?)? # yyyy[-mm[-dd]] 37 ((?P<y>\d\d\d\d)([/-](?P<m>\d\d?)([/-](?P<d>\d\d?))?)? # yyyy[-mm[-dd]]
38 |(?P<a>\d\d?)[/-](?P<b>\d\d?))? # or mm-dd 38 |(?P<a>\d\d?)[/-](?P<b>\d\d?))? # or mm-dd
39 (?P<n>\.)? # . 39 (?P<n>\.)? # .
40 (((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d?(\.\d+)?))?)? # hh:mm:ss 40 (((?P<H>\d?\d):(?P<M>\d\d))?(:(?P<S>\d\d?(\.\d+)?))?)? # hh:mm:ss
41 (?P<o>[\d\smywd\-+]+)? # offset 41 (?:(?P<tz>\s?[+-]\d{4})|(?P<o>[\d\smywd\-+]+))? # time-zone offset, offset
42 (?P<tz>[+-]\d{4})? # time-zone offset
43 $''', re.VERBOSE) 42 $''', re.VERBOSE)
44 serialised_date_re = re.compile(r''' 43 serialised_date_re = re.compile(r'''
45 (\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d?(\.\d+)?) 44 (\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d?(\.\d+)?)
46 ''', re.VERBOSE) 45 ''', re.VERBOSE)
47 46
188 or just the year may be omitted. If the time is given, the time is 187 or just the year may be omitted. If the time is given, the time is
189 interpreted in the user's local time zone. The Date constructor takes 188 interpreted in the user's local time zone. The Date constructor takes
190 care of these conversions. In the following examples, suppose that yyyy 189 care of these conversions. In the following examples, suppose that yyyy
191 is the current year, mm is the current month, and dd is the current day 190 is the current year, mm is the current month, and dd is the current day
192 of the month; and suppose that the user is on Eastern Standard Time. 191 of the month; and suppose that the user is on Eastern Standard Time.
192
193 Note that Date conversion from user inputs will use the local
194 timezone, either from the database user (some database schemas have
195 a timezone property for a user) or from a default in the roundup
196 configuration. Roundup will store all times in UTC in the database
197 but display the time to the user in their local timezone as
198 configured. In the following examples the timezone correction for
199 Eastern Standard Time (GMT-5, no DST) will be applied explicitly via
200 an offset, but times are given in UTC in the output.
201
193 Examples:: 202 Examples::
194 203
195 "2000-04-17" means <Date 2000-04-17.00:00:00> 204
196 "01-25" means <Date yyyy-01-25.00:00:00> 205 make doctest think it's always 2000-06-26.00:34:02:
197 "2000-04-17.03:45" means <Date 2000-04-17.08:45:00> 206 >>> u = test_ini('2000-06-26.00:34:02.0')
198 "08-13.22:13" means <Date yyyy-08-14.03:13:00> 207
199 "11-07.09:32:43" means <Date yyyy-11-07.14:32:43> 208 >>> Date("2000-04-17-0500")
200 "14:25" means <Date yyyy-mm-dd.19:25:00> 209 <Date 2000-04-17.05:00:00.000>
201 "8:47:11" means <Date yyyy-mm-dd.13:47:11> 210 >>> Date("01-25-0500")
202 "2003" means <Date 2003-01-01.00:00:00> 211 <Date 2000-01-25.05:00:00.000>
203 "2003-06" means <Date 2003-06-01.00:00:00> 212 >>> Date("2000-04-17.03:45-0500")
204 "." means "right now" 213 <Date 2000-04-17.08:45:00.000>
214 >>> Date("08-13.22:13-0500")
215 <Date 2000-08-14.03:13:00.000>
216 >>> Date("11-07.09:32:43-0500")
217 <Date 2000-11-07.14:32:43.000>
218 >>> Date("14:25-0500")
219 <Date 2000-06-26.19:25:00.000>
220 >>> Date("8:47:11-0500")
221 <Date 2000-06-26.13:47:11.000>
222 >>> Date("2003 -0500")
223 <Date 2003-01-01.05:00:00.000>
224 >>> Date("2003-06 -0500")
225 <Date 2003-06-01.05:00:00.000>
226
227 "." means "right now":
228 >>> Date(".")
229 <Date 2000-06-26.00:34:02.000>
230
231 >>> test_fin(u)
205 232
206 The Date class should understand simple date expressions of the form 233 The Date class should understand simple date expressions of the form
207 stamp + interval and stamp - interval. When adding or subtracting 234 stamp + interval and stamp - interval. When adding or subtracting
208 intervals involving months or years, the components are handled 235 intervals involving months or years, the components are handled
209 separately. For example, when evaluating "2000-06-25 + 1m 10d", we 236 separately. For example, when evaluating "2000-06-25 + 1m 10d", we
231 258
232 The date format 'yyyymmddHHMMSS' (year, month, day, hour, 259 The date format 'yyyymmddHHMMSS' (year, month, day, hour,
233 minute, second) is the serialisation format returned by the serialise() 260 minute, second) is the serialisation format returned by the serialise()
234 method, and is accepted as an argument on instatiation. 261 method, and is accepted as an argument on instatiation.
235 262
236 The date class handles basic arithmetic:: 263 In addition, a timezone specifier can be appended to the date format.
264 The timezone specifier is a sign ("+" or "-") followed by a 4-digit
265 number as in the RFC 2822 date format.
266 The first two digits indicate the number of hours, while the last two
267 digits indicate the number of minutes the time is offset from
268 Coordinated Universal Time (UTC). The "+" or "-" sign indicate whether
269 the time is ahead of (east of) or behind (west of) UTC. Note that a
270 given timezone specifier *overrides* an offset given to the Date
271 constructor. Examples::
272
273 >>> Date ("2000-08-14+0200")
274 <Date 2000-08-13.22:00:00.000>
275 >>> Date ("08-15.22:00+0200")
276 <Date 2000-08-15.20:00:00.000>
277 >>> Date ("08-15.22:47+0200")
278 <Date 2000-08-15.20:47:00.000>
279 >>> Date ("08-15.22:47+0200", offset = 5)
280 <Date 2000-08-15.20:47:00.000>
281 >>> Date ("08-15.22:47", offset = 5)
282 <Date 2000-08-15.17:47:00.000>
283
284 The date class handles basic arithmetic, but note that arithmetic
285 cannot be combined with timezone offsets (see last example)::
237 286
238 >>> x=test_ini('2004-04-06.22:04:20.766830') 287 >>> x=test_ini('2004-04-06.22:04:20.766830')
239 >>> d1=Date('.') 288 >>> d1=Date('.')
240 >>> d1 289 >>> d1
241 <Date 2004-04-06.22:04:20.767> 290 <Date 2004-04-06.22:04:20.767>
378 S = 0 427 S = 0
379 if info['S'] is not None: 428 if info['S'] is not None:
380 S = float(info['S']) 429 S = float(info['S'])
381 adjust = True 430 adjust = True
382 431
432 if info.get('tz', None):
433 offset = 0
383 434
384 # now handle the adjustment of hour 435 # now handle the adjustment of hour
385 frac = S - int(S) 436 frac = S - int(S)
386 dt = datetime.datetime(y,m,d,H,M,int(S), int(frac * 1000000.)) 437 dt = datetime.datetime(y,m,d,H,M,int(S), int(frac * 1000000.))
387 y, m, d, H, M, S, x, x, x = dt.timetuple() 438 y, m, d, H, M, S, x, x, x = dt.timetuple()
397 self.applyInterval(Interval(info['o'], allowdate=0)) 448 self.applyInterval(Interval(info['o'], allowdate=0))
398 except ValueError: 449 except ValueError:
399 raise ValueError, self._('%r not a date / time spec ' 450 raise ValueError, self._('%r not a date / time spec '
400 '"yyyy-mm-dd", "mm-dd", "HH:MM", "HH:MM:SS" or ' 451 '"yyyy-mm-dd", "mm-dd", "HH:MM", "HH:MM:SS" or '
401 '"yyyy-mm-dd.HH:MM:SS.SSS"')%(spec,) 452 '"yyyy-mm-dd.HH:MM:SS.SSS"')%(spec,)
453
454 if info.get('tz', None):
455 tz = info ['tz'].strip ()
456 sign = [-1,1][tz[0] == '-']
457 minute = int (tz[3:], 10)
458 hour = int (tz[1:3], 10)
459 self.applyInterval(Interval((0, 0, 0, hour, minute, 0), sign=sign))
402 460
403 # adjust by added granularity 461 # adjust by added granularity
404 if add_granularity: 462 if add_granularity:
405 self.applyInterval(add_granularity) 463 self.applyInterval(add_granularity)
406 self.applyInterval(Interval('- 00:00:01')) 464 self.applyInterval(Interval('- 00:00:01'))

Roundup Issue Tracker: http://roundup-tracker.org/