Source code for utool.util_time

# -*- coding: utf-8 -*-
"""
TODO: This file seems to care about timezone

TODO: Use UTC/GMT time here for EVERYTHING

References:
    http://www.timeanddate.com/time/aboututc.html

"""
from __future__ import absolute_import, division, print_function
import sys
import six
import time
import calendar
import datetime
from utool import util_inject
from utool import util_cplat
from utool import util_arg

print, rrr, profile = util_inject.inject2(__name__)
print_ = util_inject.make_module_write_func(__name__)


if util_cplat.WIN32:
    # Use time.clock in win32
    default_timer = time.clock
else:
    default_timer = time.time


# --- Timing ---
[docs]def tic(msg=None): """ similar to matlab tic SeeAlso: ut.toc """ return (msg, default_timer())
[docs]def toc(tt, return_msg=False, write_msg=True, verbose=None): """ similar to matlab toc SeeAlso: ut.tic """ if verbose is not None: write_msg = verbose (msg, start_time) = tt ellapsed = default_timer() - start_time if (not return_msg) and write_msg and msg is not None: sys.stdout.write('...toc(%.4fs, ' % ellapsed + '"' + str(msg) + '"' + ')\n') if return_msg: return msg else: return ellapsed
[docs]def get_timestamp( format_='iso', use_second=False, delta_seconds=None, isutc=False, timezone=False ): """ get_timestamp Args: format_ (str): (tag, printable, filename, other) use_second (bool): delta_seconds (None): Returns: str: stamp Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> format_ = 'printable' >>> use_second = False >>> delta_seconds = None >>> stamp = get_timestamp(format_, use_second, delta_seconds) >>> print(stamp) >>> assert len(stamp) == len('15:43:04 2015/02/24') """ # TODO: time.timezone if format_ == 'int': if isutc: stamp = int(time.mktime(time.gmtime())) else: stamp = int(time.mktime(time.localtime())) return stamp if isutc: now = datetime.datetime.utcnow() else: now = datetime.datetime.now() if delta_seconds is not None: now += datetime.timedelta(seconds=delta_seconds) if format_ == 'iso': # ISO 8601 # utcnow = datetime.datetime.utcnow() # utcnow.isoformat() localOffsetHour = time.timezone // 3600 utc_offset = ( '-' + str(localOffsetHour) if localOffsetHour < 0 else '+' + str(localOffsetHour) ) stamp = time.strftime('%Y-%m-%dT%H%M%S') + utc_offset return stamp if format_ == 'tag': time_tup = (now.year - 2000, now.month, now.day) stamp = '%02d%02d%02d' % time_tup elif format_ == 'printable': time_tup = (now.hour, now.minute, now.second, now.year, now.month, now.day) time_format = '%02d:%02d:%02d %02d/%02d/%02d' stamp = time_format % time_tup else: if use_second: time_tup = (now.year, now.month, now.day, now.hour, now.minute, now.second) time_formats = { 'filename': 'ymd_hms-%04d-%02d-%02d_%02d-%02d-%02d', 'comment': '# (yyyy-mm-dd hh:mm:ss) %04d-%02d-%02d %02d:%02d:%02d', } else: time_tup = (now.year, now.month, now.day, now.hour, now.minute) time_formats = { 'filename': 'ymd_hm-%04d-%02d-%02d_%02d-%02d', 'comment': '# (yyyy-mm-dd hh:mm) %04d-%02d-%02d %02d:%02d', } stamp = time_formats[format_] % time_tup if timezone: if isutc: stamp += '_UTC' else: from pytz import reference localtime = reference.LocalTimezone() tzname = localtime.tzname(now) stamp += '_' + tzname return stamp
[docs]def get_datestamp(explicit=True, isutc=False): if isutc: now = datetime.datetime.utcnow() else: now = datetime.datetime.now() stamp = '%04d-%02d-%02d' % (now.year, now.month, now.day) if explicit: return 'ymd-' + stamp + time.timezone[0] else: return stamp
# alias timestamp = get_timestamp
[docs]class Timer(object): """ Timer with-statment context object. Example: >>> # ENABLE_DOCTEST >>> import utool as ut >>> timer = ut.Timer('Timer test!', verbose=1) >>> with timer: >>> prime = ut.get_nth_prime(400) >>> assert timer.ellapsed > 0 """ def __init__(self, msg='', verbose=True, newline=True): self.msg = msg self.verbose = verbose self.newline = newline self.tstart = -1 self.ellapsed = -1
[docs] def tic(self): if self.verbose: sys.stdout.flush() print_('\ntic(%r)' % self.msg) if self.newline: print_('\n') sys.stdout.flush() self.tstart = default_timer()
[docs] def toc(self): ellapsed = default_timer() - self.tstart if self.verbose: print_('...toc(%r)=%.4fs\n' % (self.msg, ellapsed)) sys.stdout.flush() return ellapsed
start = tic stop = toc def __enter__(self): self.tic() return self def __exit__(self, type_, value, trace): self.ellapsed = self.toc() if trace is not None: return False # return a falsey value on error
[docs]class Timerit(object): """ Reports the average time to run a block of code. Unlike `timeit`, `Timerit` can handle multiline blocks of code Args: num (int): number of times to run the loop label (str): identifier for printing unit (str): reporting unit of time (e.g. 'ms', 's', None) CommandLine: python -m utool.util_time Timerit python -m utool.util_time Timerit:0 python -m utool.util_time Timerit:1 Notes: Minimal syntax with less-precise timing ```python import utool as ut for timer in ut.Timerit(100): # <write code to time here> ``` Full syntax with most-precise timing ```python import utool as ut for timer in ut.Timerit(100): # <write untimed setup code here> with timer: # <write code to time here> ``` Can also keep track of the Timerit object for extra statistics ```python import utool as ut t1 = ut.Timerit(100) for timer in t1: # <write untimed setup code here> with timer: # <write code to time here> # <you can now access Timerit attributes like t1.total_time> ``` Example: >>> # ENABLE_DOCTEST >>> import utool as ut >>> num = 15 >>> t1 = ut.Timerit(num) >>> for timer in t1: >>> # <write untimed setup code here> this example has no setup >>> with timer: >>> # <write code to time here> for example... >>> ut.get_nth_prime_bruteforce(100) >>> # <you can now access Timerit attributes> >>> print('t1.total_time = %r' % (t1.total_time,)) >>> assert t1.total_time > 0 >>> assert t1.n_loops == t1.num >>> assert t1.n_loops == num Example: >>> # DISABLE_DOCTEST >>> import utool as ut >>> num = 10000 >>> n = 50 >>> # If the timer object is unused, time will still be recoreded, >>> # but with less precision. >>> for _ in ut.Timerit(num, 'inprecise'): >>> ut.get_nth_prime_bruteforce(n) >>> # Using the timer object results in the most precise timeings >>> for timer in ut.Timerit(num, 'precise'): >>> with timer: >>> ut.get_nth_prime_bruteforce(n) """ def __init__(self, num, label=None, unit=None, verbose=1): self.num = num self.label = label self.times = [] self.verbose = verbose self.total_time = None self.n_loops = None self.unit = unit def __iter__(self): import utool as ut if self.verbose > 1: if self.label is None: print('Timing for %d loops' % self.num) else: print('Timing %s for %d loops.' % (self.label, self.num,)) self.n_loops = 0 self.total_time = 0 # Create a foreground and background timer bg_timer = ut.Timer(verbose=0) # (ideally this is unused) fg_timer = ut.Timer(verbose=0) # (used directly by user) # Core timing loop for i in range(self.num): # Start background timer (in case the user doesnt use fg_timer) # Yield foreground timer to let the user run a block of code # When we return from yield the user code will have just finishec # Then record background time + loop overhead bg_timer.tic() yield fg_timer bg_time = bg_timer.toc() # Check if the fg_timer object was used, but fallback on bg_timer if fg_timer.ellapsed >= 0: block_time = fg_timer.ellapsed # high precision else: block_time = bg_time # low precision # record timeings self.times.append(block_time) self.total_time += block_time self.n_loops += 1 # Timeing complete, print results assert len(self.times) == self.num, 'incorrectly recorded times' if self.verbose > 0: self._print_report(self.verbose) @property def ave_secs(self): return self.total_time / self.n_loops def _print_report(self, verbose=1): import utool as ut ave_secs = self.ave_secs if self.label is None: print('Timing complete, %d loops' % (self.n_loops,)) else: print('Timing complete for: %s, %d loops' % (self.label, self.n_loops)) if verbose > 2: body = ut.second_str(self.total_time, unit=self.unit, precision=4) print(' body took: %s' % body) perloop = ut.second_str(ave_secs, unit=self.unit, precision=4) print(' time per loop : %s' % (perloop,))
[docs]def determine_timestamp_format(datetime_str, warn=True): r""" Args: datetime_str (str): Returns: str: References: https://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior CommandLine: python -m utool.util_time --exec-determine_timestamp_format Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> datetime_str_list = [ >>> '0000:00:00 00:00:00', >>> ' : : : : ', >>> '2015:04:01 00:00:00', >>> '2080/04/01 00:00:00', >>> '2005-10-27T14:35:20+02:00', >>> '6:35:01\x002006:03:19 1', >>> '2016/05/03 16:34:57 EST' >>> ] >>> result = ut.repr4([determine_timestamp_format(datetime_str) >>> for datetime_str in datetime_str_list]) >>> print(result) """ import re # try to determine the format clean_datetime_str = datetime_str.replace('\x00', ' ').strip(';').strip() if len(clean_datetime_str) == 25 and 'T' in clean_datetime_str: # Delete last colon from ISO 8601 format # clean_datetime_str = clean_datetime_str[:-3] + clean_datetime_str[-2:] if True or six.PY2: if warn: print( 'WARNING: Python 2.7 does not support %z directive ' 'in strptime, ignoring timezone in parsing: ' + clean_datetime_str ) clean_datetime_str = clean_datetime_str[:-6] year_regex = r'(\d\d)?\d\d' month_regex = '[0-1]?[0-9]' day_regex = '[0-3]?[0-9]' time_regex = r'[0-6]?[0-9]:[0-6]?[0-9]:[0-6]?[0-9]' # odd_time_regex = r'[0-6]?[0-9]:[0-6]?[0-9]:[0-6 ]?[0-9]' date_regex1 = '/'.join([year_regex, month_regex, day_regex]) date_regex2 = ':'.join([year_regex, month_regex, day_regex]) date_regex3 = '-'.join([year_regex, month_regex, day_regex]) datetime_regex1 = date_regex1 + ' ' + time_regex datetime_regex2 = date_regex2 + ' ' + time_regex datetime_regex3 = date_regex3 + 'T' + time_regex # + r'\+[0-2]?[0-9]?[0-6]?[0-9]' datetime_regex4 = time_regex + ' ' + date_regex2 + ' 1' timefmt = None if re.match(datetime_regex1, clean_datetime_str): timefmt = '%Y/%m/%d %H:%M:%S' elif re.match(datetime_regex2, clean_datetime_str): timefmt = '%Y:%m:%d %H:%M:%S' elif re.match(datetime_regex3, clean_datetime_str): # timefmt = '%Y-%m-%dT%H:%M:%S%z' timefmt = '%Y-%m-%dT%H:%M:%S' elif re.match(datetime_regex4, clean_datetime_str): # timefmt = '%Y-%m-%dT%H:%M:%S%z' timefmt = '%H:%M:%S %Y:%m:%d 1' # Just dont accept this bad format # elif re.match(datetime_regex3, clean_datetime_str): # timefmt = '%Y:%m:%d %H:%M: %S' else: if isinstance(clean_datetime_str, six.string_types): if len(clean_datetime_str.strip()) == 0: return None elif len(clean_datetime_str.strip(':/ ')) == 0: return None elif clean_datetime_str.find('No EXIF Data') == 0: return None elif clean_datetime_str.find('Invalid') == 0: return None elif clean_datetime_str == '0000:00:00 00:00:00': return None elif [ord(_) >= 128 for _ in clean_datetime_str].count(True) > 1: return None # return -1 # import utool as ut # ut.embed() msg = 'Unknown format: datetime_str=%r' % (datetime_str,) print(msg) return None # raise NotImplementedError(msg) return timefmt
[docs]def local_timezone(): import time return time.tzname
[docs]def utcnow_tz(): import pytz dt = datetime.datetime.utcnow() dt = dt.replace(tzinfo=pytz.timezone('UTC')) return dt
[docs]def parse_timestamp(timestamp, zone='UTC', timestamp_format=None): r""" pip install delorean Args: timestamp (str): timestampe string zone (bool): assumes input is zone (only if not specified) and gives output in zone. CommandLine: python -m utool.util_time --test-parse_timestamp python -m utool.util_time parse_timestamp Example0: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> utc = True >>> timestampe_format = None >>> timestamps = [ >>> ('2015:04:01 00:00:00',), >>> ('2005-10-27T14:35:20+02:00',), >>> ('2000-01-01T09:00:00-05:00', 'UTC'), >>> ('2000-01-01T09:00:00-05:00', 'EST'), >>> ('2000-01-01T09:00:00', 'EST'), >>> ('2000-01-01T09:00:00', 'UTC'), >>> ('6:35:01\x002006:03:19 1',), >>> ('2016/08/18 10:51:02 EST',), >>> ('2016-08-18T10:51:02-05:00',), >>> ] >>> timestamp = timestamps[-1][0] >>> dn_list = [parse_timestamp(*args) for args in timestamps] >>> result = ut.NEWLINE.join([str(dn) for dn in dn_list]) >>> print(result) 2015-04-01 00:00:00+00:00 2005-10-27 12:35:20+00:00 2000-01-01 14:00:00+00:00 2000-01-01 09:00:00-05:00 2000-01-01 09:00:00-05:00 2000-01-01 09:00:00+00:00 2006-03-19 06:35:01+00:00 2016-08-18 15:51:02+00:00 2016-08-18 15:51:02+00:00 """ if timestamp is None: return None use_delorean = True or six.PY2 if use_delorean: import delorean ## customize delorean string method # def __str__(self): # return str(self.datetime) # #return str(self.datetime) + ' ' + str(self.timezone) # delorean.Delorean.__str__ = __str__ ## method types must be injected into the class ##ut.inject_func_as_method(dn, __str__, '__repr__', override=True) if not isinstance(timestamp, six.string_types): raise NotImplementedError('Unknown format: timestamp=%r' % (timestamp,)) # Normal format, or non-standard year first data if timestamp_format is None: # dont warn because we will take care of utc timefmt = determine_timestamp_format(timestamp, warn=False) else: timefmt = timestamp_format if timefmt is None or not isinstance(timefmt, six.string_types): raise AssertionError('unknown timestamp_format=%r' % (timestamp_format,)) # Fixup timestamp utc_offset = None if len(timestamp) == 20 and '\x00' in timestamp: timestamp_ = timestamp.replace('\x00', ' ').strip(';').strip() elif use_delorean and len(timestamp) > 19: timestamp_ = timestamp[:19].strip(';').strip() utc_offset = timestamp[19:] else: timestamp_ = timestamp dt_ = datetime.datetime.strptime(timestamp_, timefmt) if use_delorean: # if utc and utc_offset is not None: # if utc: # dn_ = delorean.Delorean(dt_, 'UTC') # else: if zone is None: zone = time.tzname[0] if zone == 'local': zone = time.tzname[0] dn_ = delorean.Delorean(dt_, zone) else: dn_ = dt_ if utc_offset is not None and zone == 'UTC': if use_delorean: # Python 2.7 does not account for timezones if ':' in utc_offset: sign = {' ': +1, '+': +1, '-': -1}[utc_offset[0]] hours, seconds = utc_offset[1:].split(':') delta_ = datetime.timedelta(hours=int(hours), seconds=int(seconds)) delta = sign * delta_ else: import pytz tzname = utc_offset.strip() delta = pytz.timezone(tzname).utcoffset(dt_) # Move back to utc dn = dn_ - delta else: raise AssertionError('python3 should take care of timezone') else: dn = dn_ if use_delorean: if not zone != 'UTC': dn.shift(zone) return dn.datetime
# return dn
[docs]def exiftime_to_unixtime(datetime_str, timestamp_format=None, strict=None): r""" converts a datetime string to posixtime (unixtime) Use parse timestamp instead Args: datetime_str (str): timestamp_format (int): Returns: int: unixtime seconds from 1970 (currently not UTC; this will change) CommandLine: python -m utool.util_time --test-exiftime_to_unixtime:2 Example0: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> datetime_str = '0000:00:00 00:00:00' >>> timestamp_format = 1 >>> result = exiftime_to_unixtime(datetime_str, timestamp_format) >>> print(result) -1 Example1: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> datetime_str = '2015:04:01 00:00:00' >>> timestamp_format = 1 >>> result = exiftime_to_unixtime(datetime_str, timestamp_format) >>> print(result) 1427846400 Example2: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> datetime_str = '2005-10-27T14:35:20+02:00' >>> timestamp_format = None >>> result = exiftime_to_unixtime(datetime_str, timestamp_format) >>> print(result) 1130423720 Example3: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> datetime_str = '6:35:01\x002006:03:19 1' >>> timestamp_format = None >>> result = exiftime_to_unixtime(datetime_str, timestamp_format) >>> print(result) 1142750101 """ invalid_value = -1 if isinstance(datetime_str, int): if datetime_str == -1: return invalid_value elif datetime_str is None: return None # TODO: use parse_timestamp to reduce duplicate code # try: # dt = parse_timestamp(datetime_str) # except TypeError: # #if datetime_str is None: # #return -1 # return -1 # except ValueError as ex: # if strict is None: # ... if not isinstance(datetime_str, six.string_types): raise NotImplementedError('Unknown format: datetime_str=%r' % (datetime_str,)) # Normal format, or non-standard year first data if timestamp_format is None: timefmt = determine_timestamp_format(datetime_str) if timefmt is None: return invalid_value elif timestamp_format == 2: timefmt = '%m/%d/%Y %H:%M:%S' elif timestamp_format == 1: timefmt = '%Y:%m:%d %H:%M:%S' else: assert isinstance(timestamp_format, six.string_types) timefmt = timestamp_format # raise AssertionError('unknown timestamp_format=%r' % (timestamp_format,)) try: if len(datetime_str) == 20 and '\x00' in datetime_str: datetime_str_ = datetime_str.replace('\x00', ' ').strip(';').strip() elif len(datetime_str) > 19: datetime_str_ = datetime_str[:19].strip(';').strip() else: datetime_str_ = datetime_str # try: dt = datetime.datetime.strptime(datetime_str_, timefmt) # except ValueError as ex: # import utool as ut # ut.printex(ex, iswarning=True) # return invalid_value return calendar.timegm(dt.timetuple()) # return time.mktime(dt.timetuple()) except TypeError: # if datetime_str is None: # return -1 return -1 except ValueError as ex: if strict is None: strict = util_arg.SUPER_STRICT # strict = False # from utool.util_arg import STRICT if isinstance(datetime_str, six.string_types): if len(datetime_str_.strip()) == 0: return invalid_value if datetime_str_.find('No EXIF Data') == 0: return invalid_value if datetime_str_.find('Invalid') == 0: return invalid_value if datetime_str_ == '0000:00:00 00:00:00': return invalid_value print('<!!! ValueError !!!>') print('[util_time] Caught Error: ' + repr(ex)) print('[util_time] type(datetime_str) = %r' % type(datetime_str)) print('[util_time] repr(datetime_str) = %r' % datetime_str) print('[util_time] (datetime_str) = %s' % datetime_str) print('[util_time] len(datetime_str) = %d' % len(datetime_str)) print('[util_time] repr(datetime_str_) = %r' % datetime_str_) print('[util_time] len(datetime_str_) = %d' % len(datetime_str_)) print('</!!! ValueError !!!>') debug = True if debug: def find_offending_part(datetime_str_, timefmt, splitchar=' '): import utool as ut parts_list = datetime_str_.split(splitchar) fmt_list = timefmt.split(splitchar) if len(parts_list) == 1: return for part, fmt in zip(parts_list, fmt_list): print('Trying:') with ut.Indenter(' '): try: print('fmt = %r' % (fmt,)) print('part = %r' % (part,)) datetime.datetime.strptime(part, fmt) except ValueError: find_offending_part(part, fmt, '/') print('Failed') else: print('Passed') find_offending_part(datetime_str_, timefmt) # import utool as ut # ut.embed() if strict: raise else: print('Supressed ValueError') return invalid_value
[docs]def parse_timedelta_str(str_): r""" Args: str_ (str): Returns: float: timedelta CommandLine: python -m utool.util_time --exec-parse_timedelta_str Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> str_ = '24h' >>> timedelta = parse_timedelta_str(str_) >>> result = ('timedelta = %s' % (str(timedelta),)) >>> print(result) timedelta = 86400.0 """ if str_.endswith('m'): timedelta = float(str_[0:-1]) * 60 elif str_.endswith('h'): timedelta = float(str_[0:-1]) * 60 * 60 elif str_.endswith('s'): timedelta = float(str_[0:-1]) else: raise NotImplementedError('Unknown timedelta format %r' % (str_)) return timedelta
[docs]def ensure_timedelta(str_or_num): if isinstance(str_or_num, six.string_types): return parse_timedelta_str(str_or_num) else: return str_or_num
[docs]def unixtime_to_datetimestr(unixtime, timefmt='%Y/%m/%d %H:%M:%S', isutc=True): """ TODO: ranme to datetimestr """ try: if unixtime == -1: return 'NA' if unixtime is None: return None if isutc: return datetime.datetime.utcfromtimestamp(unixtime).strftime(timefmt) else: return datetime.datetime.fromtimestamp(unixtime).strftime(timefmt) except ValueError: raise
# return 'NA'
[docs]def unixtime_to_datetimeobj(unixtime, isutc=True): try: if unixtime == -1: return 'NA' if unixtime is None: return None if isutc: return datetime.datetime.utcfromtimestamp(unixtime) else: return datetime.datetime.fromtimestamp(unixtime) except ValueError: raise
[docs]def unixtime_to_timedelta(unixtime_diff): """ alias for get_unix_timedelta """ return get_unix_timedelta(unixtime_diff)
[docs]def get_unix_timedelta(unixtime_diff): timedelta = datetime.timedelta(seconds=abs(unixtime_diff)) return timedelta
[docs]def get_unix_timedelta_str(unixtime_diff): """ TODO: rectify this function with get_posix_timedelta_str Args: unixtime_diff (int): number of seconds Returns: timestr (str): formated time string Args: unixtime_diff (int): Returns: str: timestr CommandLine: python -m utool.util_time --test-get_unix_timedelta_str Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> unixtime_diff = 0 >>> timestr = get_unix_timedelta_str(unixtime_diff) >>> timestr_list = [get_unix_timedelta_str(_) for _ in [-9001, -1, 0, 1, 9001]] >>> result = ut.repr2(timestr_list) >>> print(result) ['2 hours 30 minutes 1 second', '1 second', '0 seconds', '1 second', '2 hours 30 minutes 1 second'] """ timedelta = get_unix_timedelta(unixtime_diff) timestr = get_timedelta_str(timedelta) return timestr
[docs]def get_timedelta_str(timedelta, exclude_zeros=False): """ get_timedelta_str Returns: str: timedelta_str, formated time string References: http://stackoverflow.com/questions/8906926/formatting-python-timedelta-objects Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> timedelta = get_unix_timedelta(10) >>> timedelta_str = get_timedelta_str(timedelta) >>> result = (timedelta_str) >>> print(result) 10 seconds """ if timedelta == datetime.timedelta(0): return '0 seconds' days = timedelta.days hours, rem = divmod(timedelta.seconds, 3600) minutes, seconds = divmod(rem, 60) fmtstr_list = [] fmtdict = {} def append_cases(unit, fmtlbl): if not exclude_zeros or unit != 0: if unit == 1: fmtstr_list.append('{%s} %s' % (fmtlbl, fmtlbl)) else: fmtstr_list.append('{%s} %ss' % (fmtlbl, fmtlbl)) fmtdict[fmtlbl] = unit if abs(days) > 0: append_cases(days, 'day') if len(fmtstr_list) > 0 or abs(hours) > 0: append_cases(hours, 'hour') if len(fmtstr_list) > 0 or abs(minutes) > 0: append_cases(minutes, 'minute') if len(fmtstr_list) > 0 or abs(seconds) > 0: append_cases(seconds, 'second') fmtstr = ' '.join(fmtstr_list) timedelta_str = fmtstr.format(**fmtdict) return timedelta_str
[docs]def get_posix_timedelta_str(posixtime, year=False, approx=True): """ get_timedelta_str TODO: rectify this function with get_unix_timedelta_str (unix_timedelta_str probably has better implementation) Returns: str: timedelta_str, formated time string CommandLine: python -m utool.util_time --test-get_posix_timedelta_str Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> posixtime_list = [-13, 10.2, 10.2 ** 2, 10.2 ** 3, 10.2 ** 4, 10.2 ** 5, 10.2 ** 8, 60 * 60 * 60 * 24 * 7] >>> posixtime = posixtime_list[-1] >>> timedelta_str = [get_posix_timedelta_str(posixtime) for posixtime in posixtime_list] >>> result = ut.repr2(timedelta_str) >>> print(result) ['-00:00:13', '00:00:10', '00:01:44', '00:17:41', '03:00:24', '1 day', '193 weeks', '60 weeks'] Timeit:: import datetime # Seems like like timedelta is just faster. must be because it is builtin %timeit get_posix_timedelta_str(posixtime) %timeit str(datetime.timedelta(seconds=posixtime)) """ import numpy as np if np.isnan(posixtime): return 'NaN' sign, posixtime_ = (1, posixtime) if posixtime >= 0 else (-1, -posixtime) seconds_, subseconds = divmod(posixtime_, 1) minutes_, seconds = divmod(int(seconds_), 60) hours_, minutes = divmod(minutes_, 60) days_, hours = divmod(hours_, 24) weeks_, days = divmod(days_, 7) if year: years, weeks = divmod(weeks_, 52) # not accurate else: years = 0 weeks = weeks_ timedelta_parts = [] if subseconds > 0: timedelta_parts += [('%.2f' % (subseconds,))[1:]] timedelta_parts += [':'.join(['%02d' % _ for _ in (hours, minutes, seconds)])] import utool as ut if days > 0: timedelta_parts += ['%d %s ' % (days, ut.pluralize('day', days))] if weeks > 0: timedelta_parts += ['%d %s ' % (weeks, ut.pluralize('week', weeks))] if years > 0: timedelta_parts += ['%d %s ' % (years, ut.pluralize('year', years))] if sign == -1: timedelta_parts += ['-'] else: timedelta_parts += [''] if approx is not False: if approx is True: approx = 1 timedelta_str = ''.join(timedelta_parts[::-1][0 : (approx + 1)]).strip() else: timedelta_str = ''.join(timedelta_parts[::-1]) return timedelta_str
[docs]def get_posix_timedelta_str2(posixtime): try: return get_posix_timedelta_str(posixtime) except ValueError: # handle nones and nans return 'None'
# def get_simple_posix_timedelta_str(posixtime): # """ # get_timedelta_str # Returns: # str: timedelta_str, formated time string # CommandLine: # python -m utool.util_time --test-get_posix_timedelta_str # Example: # >>> # ENABLE_DOCTEST # >>> from utool.util_time import * # NOQA # >>> posixtime_list = [13, 10.2, 10.2 ** 2, 10.2 ** 3, 10.2 ** 4, 10.2 ** 5, 10.2 ** 8] # >>> posixtime = posixtime_list[1] # >>> timedelta_str = [get_simple_posix_timedelta_str(posixtime) for posixtime in posixtime_list] # >>> result = (timedelta_str) # >>> print(result) # Timeit:: # import datetime # posixtime = 10.2 ** 8 # %timeit get_simple_posix_timedelta_str(posixtime) # %timeit str(datetime.timedelta(seconds=posixtime)) # """ # seconds_ = int(posixtime) # minutes_, seconds = divmod(seconds_, 60) # hours_, minutes = divmod(minutes_, 60) # days_, hours = divmod(hours_, 24) # weeks_, days = divmod(days_, 7) # timedelta_str = ':'.join(['%02d' % _ for _ in (hours, minutes, seconds)]) # #if days_ > 0: # # timedelta_str = '%d days ' % (days,) + timedelta_str # #if weeks_ > 0: # # timedelta_str = '%d weeks ' % (weeks_,) + timedelta_str # return timedelta_str # def get_month(): # return datetime.datetime.now().month # def get_day(): # return datetime.datetime.now().day # def get_year(): # return datetime.datetime.now().year
[docs]def get_timestats_str(unixtime_list, newlines=1, full=True, isutc=True): r""" Args: unixtime_list (list): newlines (bool): Returns: str: timestat_str CommandLine: python -m utool.util_time --test-get_timestats_str Example: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> unixtime_list = [0, 0 + 60 * 60 * 5 , 10 + 60 * 60 * 5, 100 + 60 * 60 * 5, 1000 + 60 * 60 * 5] >>> newlines = 1 >>> full = False >>> timestat_str = get_timestats_str(unixtime_list, newlines, full=full, isutc=True) >>> result = ut.align(str(timestat_str), ':') >>> print(result) { 'max' : '1970/01/01 05:16:40', 'mean' : '1970/01/01 04:03:42', 'min' : '1970/01/01 00:00:00', 'range': '5:16:40', 'std' : '2:02:01', } Example2: >>> # ENABLE_DOCTEST >>> from utool.util_time import * # NOQA >>> import utool as ut >>> unixtime_list = [0, 0 + 60 * 60 * 5 , 10 + 60 * 60 * 5, 100 + 60 * 60 * 5, 1000 + 60 * 60 * 5, float('nan'), 0] >>> newlines = 1 >>> timestat_str = get_timestats_str(unixtime_list, newlines, isutc=True) >>> result = ut.align(str(timestat_str), ':') >>> print(result) { 'max' : '1970/01/01 05:16:40', 'mean' : '1970/01/01 03:23:05', 'min' : '1970/01/01 00:00:00', 'nMax' : 1, 'nMin' : 2, 'num_nan': 1, 'range' : '5:16:40', 'shape' : (7,), 'std' : '2:23:43', } """ import utool as ut datetime_stats = get_timestats_dict(unixtime_list, full=full, isutc=isutc) timestat_str = ut.repr4(datetime_stats, newlines=newlines) return timestat_str
[docs]def get_timestats_dict(unixtime_list, full=True, isutc=True): import utool as ut unixtime_stats = ut.get_stats(unixtime_list, use_nan=True) datetime_stats = {} if unixtime_stats.get('empty_list', False): datetime_stats = unixtime_stats return datetime_stats # elif unixtime_stats.get('num_nan', 0) == unixtime_stats.get('shape')[0]: # datetime_stats = unixtime_stats # return datetime_stats for key in ['max', 'min', 'mean']: try: datetime_stats[key] = ut.unixtime_to_datetimestr( unixtime_stats[key], isutc=isutc ) except KeyError: pass except (ValueError, OSError) as ex: datetime_stats[key] = 'NA' except Exception as ex: ut.printex(ex, keys=['key', 'unixtime_stats']) raise for key in ['std']: try: datetime_stats[key] = str( ut.get_unix_timedelta(int(round(unixtime_stats[key]))) ) except KeyError: pass except (ValueError, OSError) as ex: datetime_stats[key] = 'NA' try: datetime_stats['range'] = str( ut.get_unix_timedelta( int(round(unixtime_stats['max'] - unixtime_stats['min'])) ) ) except KeyError: pass except (ValueError, OSError) as ex: datetime_stats['range'] = 'NA' if full: # unused_keys = (set(unixtime_stats.keys()) - set(datetime_stats.keys()) for key in ['nMax', 'num_nan', 'shape', 'nMin']: datetime_stats[key] = unixtime_stats[key] # print('Unused keys = %r' % (set(unixtime_stats.keys()) - set(datetime_stats.keys()),)) return datetime_stats
[docs]def date_to_datetime(date, fraction=0.0): """ fraction is how much through the day you are. 0=start of the day, 1=end of the day. """ day_seconds = (60 * 60 * 24) - 1 total_seconds = int(day_seconds * fraction) delta = datetime.timedelta(seconds=total_seconds) time = datetime.time() dt = datetime.datetime.combine(date, time) + delta return dt
[docs]def datetime_to_posixtime(dt): posixtime = time.mktime(dt.timetuple()) return posixtime
# def datetime_to_posixtime(dt): # return dt.toordinal() if __name__ == '__main__': """ CommandLine: python -c "import utool, utool.util_time; utool.doctest_funcs(utool.util_time, allexamples=True)" python -c "import utool, utool.util_time; utool.doctest_funcs(utool.util_time)" python -m utool.util_time python -m utool.util_time --allexamples """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()