Mercurial > p > roundup > code
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')) |
