Last active
May 31, 2023 15:38
-
-
Save a-luna/a641096f5ec16887febb48c81743ade0 to your computer and use it in GitHub Desktop.
Helpful Python datetime functions I've curated over time: timezone conversion, formatting aware/naive objects as strings, custom "timespan" namedtuple that provides more data than timedelta object, and more!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
from collections import namedtuple | |
from datetime import datetime, timedelta, timezone | |
from dateutil import tz | |
DT_AWARE = "%m/%d/%y %I:%M:%S %p %Z" | |
DT_NAIVE = "%m/%d/%y %I:%M:%S %p" | |
DATE_MONTH_NAME = "%b %d %Y" | |
DATE_ISO = "%Y-%m-%d" | |
timespan = namedtuple( | |
"timespan", | |
[ | |
"days", | |
"hours", | |
"minutes", | |
"seconds", | |
"milliseconds", | |
"microseconds", | |
"total_seconds", | |
"total_milliseconds", | |
"total_microseconds", | |
], | |
) | |
def is_naive(dt): | |
"""Return True if datetime object is not time-zone aware.""" | |
return not dt.tzinfo or not dt.tzinfo.utcoffset(dt) | |
def is_tzaware(dt): | |
"""Return True if datetime object is time-zone aware.""" | |
return dt.tzinfo and dt.tzinfo.utcoffset(dt) | |
def localized_dt_string(dt, use_tz=None): | |
"""Convert datetime value to a string, localized for the specified timezone.""" | |
if not dt.tzinfo and not use_tz: | |
return dt.strftime(DT_NAIVE) | |
if not dt.tzinfo: | |
return dt.replace(tzinfo=use_tz).strftime(DT_AWARE) | |
return dt.astimezone(use_tz).strftime(DT_AWARE) if use_tz else dt.strftime(DT_AWARE) | |
def get_local_utcoffset(): | |
"""Get UTC offset from local system and return tzinfo.""" | |
utc_offset = timedelta(seconds=time.localtime().tm_gmtoff) | |
return timezone(offset=utc_offset) | |
def make_tzaware(dt, use_tz): | |
"""Make a naive datetime object timezone-aware.""" | |
return dt.replace(tzinfo=use_tz) | |
def date_today_tzaware(use_tz=timezone.utc): | |
"""Timezone-aware datetime object for today's date with time portion set to 00:00:00""" | |
today = datetime.now(use_tz).date() | |
return datetime.combine(today, datetime.min.time()).replace(tzinfo=use_tz) | |
def get_date_with_min_time(dt): | |
"""Convert the time portion of a datetime object to 00:00:00.""" | |
return datetime.combine(dt.date(), datetime.min.time()) | |
def dtaware_fromtimestamp(timestamp, use_tz=timezone.utc): | |
"""Time-zone aware datetime object from UNIX timestamp.""" | |
timestamp_utc = datetime.fromtimestamp(timestamp).astimezone(timezone.utc) | |
return timestamp_utc.astimezone(use_tz) | |
def remaining_fromtimestamp(timestamp): | |
"""Calculate time remaining from now until UNIX timestamp value.""" | |
now = datetime.now(timezone.utc) | |
dt_aware = dtaware_fromtimestamp(timestamp) | |
if dt_aware < now: | |
return timespan(0, 0, 0, 0, 0, 0, 0, 0, 0) | |
return get_timespan(dt_aware - now) | |
def format_timespan_digits(ts): | |
"""Format a timespan namedtuple as a string resembling a digital display.""" | |
if ts.days: | |
return f"{ts.days}, {ts.hours:02d}:{ts.minutes:02d}:{ts.seconds:02d}" | |
if ts.seconds: | |
return f"{ts.hours:02d}:{ts.minutes:02d}:{ts.seconds:02d}" | |
return f"0:{ts.milliseconds}.{ts.microseconds}" | |
def format_timedelta_digits(td): | |
"""Format a timedelta object as a string resembling a digital display.""" | |
return format_timespan_digits(get_timespan(td)) | |
def format_timespan_str(ts): | |
"""Format a timespan namedtuple as a readable string.""" | |
if ts.days: | |
return f"{ts.days}d {ts.hours:.0f}h {ts.minutes:.0f}m {ts.seconds}s" | |
if ts.hours: | |
return f"{ts.hours:.0f}h {ts.minutes:.0f}m {ts.seconds}s" | |
if ts.minutes: | |
return f"{ts.minutes:.0f}m {ts.seconds}s" | |
if ts.seconds: | |
return f"{ts.seconds}s {ts.milliseconds:.0f}ms" | |
return f"{ts.milliseconds:.0f}.{ts.microseconds:.0f}ms " | |
def format_timedelta_str(td): | |
"""Format a timedelta object as a readable string.""" | |
return format_timespan_str(get_timespan(td)) | |
def get_timespan(td): | |
"""Convert timedelta object to timespan namedtuple.""" | |
td_days = td.days | |
td_hours = 0 | |
td_seconds = td.seconds % 60 | |
td_minutes = (td.seconds - td_seconds) / 60 | |
(td_milliseconds, td_microseconds) = divmod(td.microseconds, 1000) | |
if td_minutes > 60: | |
(td_hours, td_minutes) = divmod(td_minutes, 60) | |
return timespan( | |
td_days, | |
td_hours, | |
int(td_minutes), | |
td_seconds, | |
td_milliseconds, | |
td_microseconds, | |
td.seconds, | |
(td.seconds * 1000 + td_milliseconds), | |
(td.seconds * 1000 * 1000 + td_milliseconds * 1000 + td_microseconds), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment