Functional Programming with datetime, and Omni-Timezone Discord Timestamps

by Audrey M. Roy Greenfeld | Tue, Jan 28, 2025

I define various useful datetime utilities with the help of fastcore's L and map, and functools' partial. Then I extend that to generate Discord timestamps, which localize Unix timestamps to the reader's timezone.


from datetime import datetime
from fastcore.utils import *
from functools import partial
from zoneinfo import ZoneInfo

Overview

I've been finding it helpful to use datetime with fastcore's L and map, and functools' partial.

I shared some useful functions here to print my colleagues' current times, and generate Discord timestamps which localize Unix timestamps to the user's timezone.

Converting the Current Time

We start off by doing things the classic way using Python stdlib datetime, which is actually quite good.

datetime.now()

now() can take a timezone:

dt = datetime.now(tz=ZoneInfo('Europe/London'))
dt
nyc = dt.astimezone(ZoneInfo('America/New_York'))
nyc

Let's make a list of timezones:

tzs = L('America/Los_Angeles', 'America/Chicago', 'America/New_York', 'Europe/London', 'Europe/Istanbul', 'Australia/Brisbane',)
tzs

Now we map that timezone list to a "time in that timezone" function:

def time_in_tz(tz:str, dt:datetime|None=None) -> str: 
    if dt is None: dt = datetime.now()
    dt = dt.astimezone(ZoneInfo(tz))
    return f"{tz:20} {dt:%H:%M}"
tzs.map(time_in_tz).map(print)

Converting a Future Time With Timezone

To get a time in the future for a particular timezone:

tomorrow_3pm_est = datetime.now(ZoneInfo('America/New_York')).replace(hour=15, minute=0, second=0, microsecond=0) + timedelta(days=1)

This also works and is more readable:

datetime.fromisoformat('2025-01-30 15:00').replace(tzinfo=ZoneInfo('America/New_York'))
current_times = partial(time_in_tz, dt=tomorrow_3pm_est)
tzs.map(current_times).map(print)

Adding Discord Timestamp

A Discord timestamp looks like <t:1738094460:F> where:

When you put one of those into a Discord message, it automatically shows in each user's local timezone.

f"<t:{int(dt.timestamp())}:f>"
def print_discord_time(dt:datetime|None=None) -> None:
    if dt is None: dt = datetime.now()
    print(f"{"Discord":20} <t:{int(dt.timestamp())}:f>")
print_discord_time()
print_discord_time(tomorrow_3pm_est)

Printing It All

def print_times(dt:datetime|None=None) -> None:
    if dt is None: dt = datetime.now()
    tzs = L('America/Los_Angeles', 'America/Chicago', 'America/New_York', 'Europe/London', 'Europe/Istanbul', 'Australia/Brisbane')
    tzs.map(time_in_tz).map(print)
    print_discord_time(dt)
print_times()

Next Steps

Create a Time Converter tool: a FastTag I can use to convert time whenever I need to.