Skip to content

Instantly share code, notes, and snippets.

@a-luna
Last active May 31, 2023 15:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-luna/a641096f5ec16887febb48c81743ade0 to your computer and use it in GitHub Desktop.
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!
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