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

str

Note

For more info see [WikiISO8601], [PyStrptime], [PyTime].

References

WikiISO8601

https://en.wikipedia.org/wiki/ISO_8601

PyStrptime

https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior

PyTime

https://docs.python.org/3/library/time.html

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

datetime.datetime

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
  • elapsed (float) – number of seconds measured by the context manager

  • tstart (float) – time of last tic reported by self._time()

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
tic()[source]

starts the timer

toc()[source]

stops the timer