DEV Community

Nico Reyes
Nico Reyes

Posted on

datetime said midnight. Server logged 5 AM.

datetime said midnight. Server logged 5 AM.

Built a scheduler that ran tasks at midnight. Worked fine on my laptop. Deployed to AWS and everything started running at 5 AM.

What happened

I was scheduling database backups using Python's datetime. Simple code:

from datetime import datetime, time
import schedule

def backup_database():
    print(f"Backup started at {datetime.now()}")
    # database backup logic here

schedule.every().day.at("00:00").do(backup_database)

while True:
    schedule.run_pending()
    time.sleep(60)
Enter fullscreen mode Exit fullscreen mode

Ran it locally (Peru timezone UTC-5), worked perfect. Midnight backups like clockwork.

Deployed to AWS EC2 instance (UTC timezone). Checked logs next morning and backups ran at 5 AM local time.

Why it broke

The schedule library uses local server time. My EC2 instance defaulted to UTC. When I said "00:00", it scheduled for UTC midnight, which is 5 AM Peru time.

I assumed datetime was timezone aware. It's not unless you explicitly make it.

What fixed it

Stopped trusting naive datetime objects. Started forcing timezone awareness:

from datetime import datetime
from zoneinfo import ZoneInfo
import schedule

def backup_database():
    peru_tz = ZoneInfo("America/Lima")
    now = datetime.now(peru_tz)
    print(f"Backup started at {now.strftime('%Y-%m-%d %H:%M %Z')}")
    # database backup logic

# Get current hour in Peru time
peru_tz = ZoneInfo("America/Lima")
current_hour = datetime.now(peru_tz).hour

# Schedule for midnight Peru time
schedule.every().day.at("00:00").do(backup_database)
Enter fullscreen mode Exit fullscreen mode

But that still used server local time for scheduling. Real fix was converting target time to server timezone:

from datetime import datetime, time as dt_time
from zoneinfo import ZoneInfo
import schedule

def backup_database():
    peru_tz = ZoneInfo("America/Lima")
    print(f"Backup at {datetime.now(peru_tz)}")

# Convert midnight Peru to UTC for scheduling
peru_tz = ZoneInfo("America/Lima")
utc_tz = ZoneInfo("UTC")

midnight_peru = datetime.now(peru_tz).replace(hour=0, minute=0, second=0)
midnight_utc = midnight_peru.astimezone(utc_tz)

schedule.every().day.at(midnight_utc.strftime("%H:%M")).do(backup_database)
Enter fullscreen mode Exit fullscreen mode

Now it schedules at 05:00 UTC (which is midnight Peru). Logs show correct time.

Switched to APScheduler eventually because it handles timezones better out of the box. Still annoyed I spent a day debugging something that obvious tho.

Python datetime being naive by default feels like a design mistake honestly. Or maybe I just suck at reading docs.

Top comments (0)