|
5 | 5 | # SPDX-License-Identifier: GPL-2.0-or-later |
6 | 6 |
|
7 | 7 | import os |
| 8 | +import re |
8 | 9 | import sys |
9 | 10 | import argparse |
10 | 11 | import warnings |
11 | | -from datetime import datetime |
12 | 12 | from fractions import Fraction |
| 13 | +from datetime import datetime, timedelta |
13 | 14 |
|
14 | 15 | from blessings import Terminal |
15 | 16 | from tqdm import tqdm |
@@ -172,9 +173,12 @@ def get_config(args): |
172 | 173 | "be specified as an absolute timestamp (in ISO-8601 format) or a " |
173 | 174 | "duration to be added to the current timestamp") |
174 | 175 | parser.add_argument( |
175 | | - '--epoch', type=epoch, metavar='WHEN', default='unix', |
176 | | - help="The epoch from which datetimes are measured. Can be specified " |
177 | | - "as an absolute timestamp (in ISO-8601 format), or one of the special " |
| 176 | + '--timestamps', type=timestamps, default='unix', |
| 177 | + metavar='[UNIT since] EPOCH', |
| 178 | + help="The units and epoch from which datetimes are measured. Can be " |
| 179 | + "specified as a string in the form 'duration since timestamp' (for " |
| 180 | + "example 'days since 1970-01-01' or 'seconds since 1900-01-01'), a " |
| 181 | + "standalone timestamp (in ISO-8601 format), or one of the special " |
178 | 182 | 'strings, "unix" or "excel" (default: %(default)s)') |
179 | 183 | parser.add_argument( |
180 | 184 | '--max-numeric-len', type=int, metavar='LEN', default=30, |
@@ -316,6 +320,8 @@ def from_config(cls, config, progress): |
316 | 320 | strip_whitespace=config.strip_whitespace, |
317 | 321 | min_timestamp=config.min_timestamp, |
318 | 322 | max_timestamp=config.max_timestamp, |
| 323 | + epoch=config.timestamps[1], |
| 324 | + epoch_unit=config.timestamps[0], |
319 | 325 | progress=progress) |
320 | 326 |
|
321 | 327 |
|
@@ -352,21 +358,29 @@ def max_timestamp(s, now=_start): |
352 | 358 | else: |
353 | 359 | return now + t |
354 | 360 |
|
355 | | -def epoch(s): |
| 361 | +def timestamps(s): |
356 | 362 | try: |
357 | | - return { |
| 363 | + unit, epoch = { |
358 | 364 | # The Excel epoch is defined as 1900-01-01, but that is date "1" |
359 | 365 | # in Excel, rather than "0". Furthermore, for compat. with good |
360 | 366 | # ol' 1-2-3, 1900 was treated (incorrectly) as a leap-year leading |
361 | 367 | # to a +1 offset for all dates after 1900-02-28. Rather than |
362 | 368 | # emulate all that nonsense, we just use 1899-12-30 as the epoch |
363 | 369 | # which is good enough for all detection purposes (which is all |
364 | 370 | # structa cares about anyway) |
365 | | - 'excel': datetime(1899, 12, 30), |
366 | | - 'unix': datetime.utcfromtimestamp(0), |
| 371 | + 'excel': (timedelta(days=1), datetime(1899, 12, 30)), |
| 372 | + 'unix': (timedelta(seconds=1), datetime.utcfromtimestamp(0)), |
367 | 373 | }[s] |
368 | 374 | except KeyError: |
369 | | - return parse_timestamp(s) |
| 375 | + fmt_re = re.compile(r'((?P<unit>\D+) since )?(?P<epoch>[^ ]+)') |
| 376 | + m = fmt_re.match(s) |
| 377 | + if not m: |
| 378 | + raise ValueError('invalid timestamp representation {s}'.format(s=s)) |
| 379 | + if m.group('unit') is None: |
| 380 | + unit = timedelta(seconds=1) |
| 381 | + else: |
| 382 | + unit = parse_duration('1' + m.group('unit'), delta_type=timedelta) |
| 383 | + return unit, parse_timestamp(m.group('epoch')) |
370 | 384 |
|
371 | 385 | def num(s): |
372 | 386 | if s.endswith('%'): |
|
0 commit comments