ubelt.util_time module¶
This is util_time, it contains functions for handling time related code.
The timestamp()
function returns an iso8601 timestamp without much fuss.
The timeparse()
is the inverse of timestamp, and makes use of
dateutil
if it is available.
The Timer
class is a context manager that times a block of indented
code. It includes tic and toc methods a more matlab like feel.
Timerit is gone! Use the standalone and separate module :module:`timerit`.
See also
tempora
- https://github.com/jaraco/tempora - time related utility functions from Jaraco
pendulum
- https://github.com/sdispater/pendulum - drop in replacement for datetime
- ubelt.util_time.timestamp(datetime=None, precision=0, default_timezone='local', allow_dateutil=True)[source]¶
Make a concise iso8601 timestamp suitable for use in filenames.
- Parameters
datetime (datetime.datetime | datetime.date | None) – A datetime to format into a timestamp. If unspecified, the current local time is used. If given as a date, the time 00:00 is used.
precision (int) – if non-zero, adds up to 6 digits of sub-second precision.
default_timezone (str | datetime.timezone) – if the input does not specify a timezone, assume this one. Can be “local” or “utc”, or a standardized code if dateutil is installed.
allow_dateutil (bool) – if True, will use dateutil to lookup the default timezone if needed
- Returns
The timestamp, which will always contain a date, time, and timezone.
- Return type
Note
For more info see [WikiISO8601], [PyStrptime], [PyTime].
References
- WikiISO8601
- PyStrptime
https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
- PyTime
Example
>>> import ubelt as ub >>> stamp = ub.timestamp() >>> print('stamp = {!r}'.format(stamp)) stamp = ...-...-...T...
Example
>>> import ubelt as ub >>> import datetime as datetime_mod >>> from datetime import datetime as datetime_cls >>> # Create a datetime object with timezone information >>> ast_tzinfo = datetime_mod.timezone(datetime_mod.timedelta(hours=-4), 'AST') >>> datetime = datetime_cls.utcfromtimestamp(123456789.123456789).replace(tzinfo=ast_tzinfo) >>> stamp = ub.timestamp(datetime, precision=2) >>> print('stamp = {!r}'.format(stamp)) stamp = '1973-11-29T213309.12-4'
>>> # Demo with a fractional hour timezone >>> act_tzinfo = datetime_mod.timezone(datetime_mod.timedelta(hours=+9.5), 'ACT') >>> datetime = datetime_cls.utcfromtimestamp(123456789.123456789).replace(tzinfo=act_tzinfo) >>> stamp = ub.timestamp(datetime, precision=2) >>> print('stamp = {!r}'.format(stamp)) stamp = '1973-11-29T213309.12+0930'
>>> # Can accept datetime or date objects with local, utc, or custom default timezones >>> act_tzinfo = datetime_mod.timezone(datetime_mod.timedelta(hours=+9.5), 'ACT') >>> datetime_utc = ub.timeparse('2020-03-05T112233', default_timezone='utc') >>> datetime_act = ub.timeparse('2020-03-05T112233', default_timezone=act_tzinfo) >>> datetime_notz = datetime_utc.replace(tzinfo=None) >>> date = datetime_utc.date() >>> stamp_utc = ub.timestamp(datetime_utc) >>> stamp_act = ub.timestamp(datetime_act) >>> stamp_date_utc = ub.timestamp(date, default_timezone='utc') >>> print(f'stamp_utc = {stamp_utc}') >>> print(f'stamp_act = {stamp_act}') >>> print(f'stamp_date_utc = {stamp_date_utc}') stamp_utc = 2020-03-05T112233+0 stamp_act = 2020-03-05T112233+0930 stamp_date_utc = 2020-03-05T000000+0
Example
>>> # xdoctest: +REQUIRES(module:dateutil) >>> # Make sure we are compatible with dateutil >>> import ubelt as ub >>> from dateutil.tz import tzlocal >>> import datetime as datetime_mod >>> from datetime import datetime as datetime_cls >>> tz_act = datetime_mod.timezone(datetime_mod.timedelta(hours=+9.5), 'ACT') >>> tzinfo_list = [ >>> tz_act, >>> datetime_mod.timezone(datetime_mod.timedelta(hours=-4), 'AST'), >>> datetime_mod.timezone(datetime_mod.timedelta(hours=0), 'UTC'), >>> datetime_mod.timezone.utc, >>> None, >>> tzlocal() >>> ] >>> # Note: there is a win32 bug here >>> # https://bugs.python.org/issue37 that means we cant use >>> # dates close to the epoch >>> datetime_list = [ >>> datetime_cls.utcfromtimestamp(123456789.123456789 + 315360000), >>> datetime_cls.utcfromtimestamp(0 + 315360000), >>> ] >>> basis = { >>> 'precision': [0, 3, 9], >>> 'tzinfo': tzinfo_list, >>> 'datetime': datetime_list, >>> 'default_timezone': ['local', 'utc', tz_act], >>> } >>> for params in ub.named_product(basis): >>> dtime = params['datetime'].replace(tzinfo=params['tzinfo']) >>> precision = params.get('precision', 0) >>> stamp = ub.timestamp(datetime=dtime, precision=precision) >>> recon = ub.timeparse(stamp) >>> alt = recon.strftime('%Y-%m-%dT%H%M%S.%f%z') >>> print('---') >>> print('params = {}'.format(ub.repr2(params, nl=1))) >>> print(f'dtime={dtime}') >>> print(f'stamp={stamp}') >>> print(f'recon={recon}') >>> print(f'alt ={alt}') >>> shift = 10 ** precision >>> a = int(dtime.timestamp() * shift) >>> b = int(recon.timestamp() * shift) >>> assert a == b, f'{a} != {b}'
- ubelt.util_time.timeparse(stamp, default_timezone='local', allow_dateutil=True)[source]¶
Create a
datetime.datetime
object from a string timestamp.Without any extra dependencies this will parse the output of
ubelt.util_time.timestamp()
into a datetime object. In the case where the format differs, dateutil.parser.parse will be used if the python-dateutil package is installed.- Parameters
stamp (str) – a string encoded timestamp
default_timezone (str) – if the input does not specify a timezone, assume this one. Can be “local” or “utc”.
allow_dateutil (bool) – if False we only use the minimal parsing and do not allow a fallback to dateutil.
- Returns
the parsed datetime
- Return type
- Raises
ValueError – if if parsing fails.
Todo
[ ] Allow defaulting to local or utm timezone (currently default is local)
Example
>>> import ubelt as ub >>> # Demonstrate a round trip of timestamp and timeparse >>> stamp = ub.timestamp() >>> datetime = ub.timeparse(stamp) >>> assert ub.timestamp(datetime) == stamp >>> # Round trip with precision >>> stamp = ub.timestamp(precision=4) >>> datetime = ub.timeparse(stamp) >>> assert ub.timestamp(datetime, precision=4) == stamp
Example
>>> import ubelt as ub >>> # We should always be able to parse these >>> good_stamps = [ >>> '2000-11-22', >>> '2000-11-22T111111.44444Z', >>> '2000-11-22T111111.44444+5', >>> '2000-11-22T111111.44444-05', >>> '2000-11-22T111111.44444-0500', >>> '2000-11-22T111111.44444+0530', >>> '2000-11-22T111111Z', >>> '2000-11-22T111111+5', >>> '2000-11-22T111111+0530', >>> ] >>> for stamp in good_stamps: >>> print(f'----') >>> print(f'stamp={stamp}') >>> result = ub.timeparse(stamp, allow_dateutil=0) >>> print(f'result={result!r}') >>> recon = ub.timestamp(result) >>> print(f'recon={recon}')
Example
>>> import ubelt as ub >>> # We require dateutil to handle these types of stamps >>> import pytest >>> conditional_stamps = [ >>> '2000-01-02T11:23:58.12345+5:30', >>> '09/25/2003', >>> 'Thu Sep 25 10:36:28 2003', >>> ] >>> for stamp in conditional_stamps: >>> with pytest.raises(ValueError): >>> result = ub.timeparse(stamp, allow_dateutil=False) >>> have_dateutil = bool(ub.modname_to_modpath('dateutil')) >>> if have_dateutil: >>> for stamp in conditional_stamps: >>> result = ub.timeparse(stamp)
- class ubelt.util_time.Timer(label='', verbose=None, newline=True)[source]¶
Bases:
object
Measures time elapsed between a start and end point. Can be used as a with-statement context manager, or using the tic/toc api.
- Parameters
label (str, default=’’) – identifier for printing
verbose (int, default=None) – verbosity flag, defaults to True if label is given
newline (bool, default=True) – if False and verbose, print tic and toc on the same line
- Variables
Example
>>> # Create and start the timer using the context manager >>> import math >>> timer = Timer('Timer test!', verbose=1) >>> with timer: >>> math.factorial(10) >>> assert timer.elapsed > 0 tic('Timer test!') ...toc('Timer test!')=...
Example
>>> # Create and start the timer using the tic/toc interface >>> timer = Timer().tic() >>> elapsed1 = timer.toc() >>> elapsed2 = timer.toc() >>> elapsed3 = timer.toc() >>> assert elapsed1 <= elapsed2 >>> assert elapsed2 <= elapsed3