X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=datetime_utils.py;h=6f504f6c304b850e830cffab08d0ed8be67fed39;hb=31c81f6539969a5eba864d3305f9fb7bf716a367;hp=97947203f6a126348d1b6602c320b07909f83970;hpb=36fea7f15ed17150691b5b3ead75450e575229ef;p=python_utils.git diff --git a/datetime_utils.py b/datetime_utils.py index 9794720..6f504f6 100644 --- a/datetime_utils.py +++ b/datetime_utils.py @@ -34,9 +34,7 @@ def is_timezone_naive(dt: datetime.datetime) -> bool: return not is_timezone_aware(dt) -def replace_timezone( - dt: datetime.datetime, tz: datetime.tzinfo -) -> datetime.datetime: +def replace_timezone(dt: datetime.datetime, tz: datetime.tzinfo) -> datetime.datetime: """ Replaces the timezone on a datetime object directly (leaving the year, month, day, hour, minute, second, micro, etc... alone). @@ -66,9 +64,7 @@ def replace_timezone( ) -def replace_time_timezone( - t: datetime.time, tz: datetime.tzinfo -) -> datetime.time: +def replace_time_timezone(t: datetime.time, tz: datetime.tzinfo) -> datetime.time: """ Replaces the timezone on a datetime.time directly without performing any translation. @@ -85,9 +81,7 @@ def replace_time_timezone( return t.replace(tzinfo=tz) -def translate_timezone( - dt: datetime.datetime, tz: datetime.tzinfo -) -> datetime.datetime: +def translate_timezone(dt: datetime.datetime, tz: datetime.tzinfo) -> datetime.datetime: """ Translates dt into a different timezone by adjusting the year, month, day, hour, minute, second, micro, etc... appropriately. The returned @@ -310,6 +304,17 @@ def n_timeunits_from_base( >>> n_timeunits_from_base(50, TimeUnit.SECONDS, base) datetime.datetime(2021, 9, 10, 11, 25, 41, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200))) + Next month corner case -- it will try to make Feb 31, 2022 then count + backwards. + >>> base = string_to_datetime("2022/01/31 11:24:51AM-0700")[0] + >>> n_timeunits_from_base(1, TimeUnit.MONTHS, base) + datetime.datetime(2022, 2, 28, 11, 24, 51, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200))) + + Last month with the same corner case + >>> base = string_to_datetime("2022/03/31 11:24:51AM-0700")[0] + >>> n_timeunits_from_base(-1, TimeUnit.MONTHS, base) + datetime.datetime(2022, 2, 28, 11, 24, 51, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=61200))) + """ assert TimeUnit.is_valid(unit) if count == 0: @@ -370,16 +375,23 @@ def n_timeunits_from_base( new_month %= 12 year_term += 1 new_year = base.year + year_term - return datetime.datetime( - new_year, - new_month, - base.day, - base.hour, - base.minute, - base.second, - base.microsecond, - base.tzinfo, - ) + day = base.day + while True: + try: + ret = datetime.datetime( + new_year, + new_month, + day, + base.hour, + base.minute, + base.second, + base.microsecond, + base.tzinfo, + ) + break + except ValueError: + day -= 1 + return ret # N years from base elif unit == TimeUnit.YEARS: @@ -768,7 +780,7 @@ def describe_timedelta(delta: datetime.timedelta) -> str: '1 day, and 10 minutes' """ - return describe_duration(delta.total_seconds()) + return describe_duration(int(delta.total_seconds())) # Note: drops milliseconds def describe_duration_briefly(seconds: int, *, include_seconds=False) -> str: @@ -813,7 +825,9 @@ def describe_timedelta_briefly(delta: datetime.timedelta) -> str: '1d 10m' """ - return describe_duration_briefly(delta.total_seconds()) + return describe_duration_briefly( + int(delta.total_seconds()) + ) # Note: drops milliseconds if __name__ == '__main__':