Home > database >  Python datetime not correct with regards to timezones when running in docker
Python datetime not correct with regards to timezones when running in docker

Time:11-12

I have a python 2.7 codebase that I'm trying to containerize. Much as I'd like to, our devs cannot move to Python 3.

When running natively in their dev environments, datetimes respect timezones. I can confirm that the output is as expected on a Mac running Python 3.9.6. But when we containerize this on Ubuntu base images, this no longer works correctly.

Using python:2.7.18-buster works correctly, but that is a 3 year old image that doesn't get updates. Both ubuntu:18.04 and ubuntu:16.04 fail.

The incorrect output when run at this time is

UTC Hour:  22
NY Hour: 22
1609459200.0
London Hour:  22
1609459200.0

The code to repro the issue is

import os
import datetime
import time
from dateutil.parser import parse

date_string="2021-01-01"


os.environ.get("TZ") # should be none, use system TZ, which is UTC
print ("UTC Hour: ", datetime.datetime.now().hour) # should be whatever hour it is in UTC

os.environ["TZ"] = "America/New_York"
print ("NY Hour:", datetime.datetime.now().hour)  # should be whatever hour it is in EST
print (time.mktime(parse(date_string).timetuple()))  # should be 1609477200.0

os.environ["TZ"] = "Europe/London"
print ("London Hour: ", datetime.datetime.now().hour) # should be whatever hour it is in GMT
print (time.mktime(parse(date_string).timetuple()))   # should be 1609459200.0

CodePudding user response:

It turns out that python:2.7.18-buster includes tzdata under /usr/share/zoneinfo. Neither ubuntu:16.04 nor ubuntu:18.04 does this, so the function posted fails.

Simply installing tzdata with apt resolves the issue.

CodePudding user response:

You can avoid changing environment variables by using aware datetime consistently. To calculate Unix time, derive it from a timedelta.

from datetime import datetime
from dateutil import tz

def to_unix(dt, _epoch=datetime(1970, 1, 1, tzinfo=tz.UTC)):
    """convert aware datetime object to seconds since the unix epoch"""
    return (dt-_epoch).total_seconds()

# reference date for demonstration
refdate = datetime(2021, 1, 1)

zone = tz.gettz("America/New_York")
dt_zone = refdate.replace(tzinfo=zone) # 2021-01-01 00:00:00-05:00
print(to_unix(dt_zone)) # 1609477200.0
print("UTC hour:", datetime.now(tz.UTC).hour, "NY hour:", datetime.now(zone).hour)
# -->> -5 hour offset on 11 Nov 2022

zone = tz.gettz("Europe/London")
dt_zone = refdate.replace(tzinfo=zone) # 2021-01-01 00:00:00 00:00
print(to_unix(dt_zone)) # 1609459200.0
print("UTC hour:", datetime.now(tz.UTC).hour, "London hour:", datetime.now(zone).hour)
# -->> 0 hour offset on 11 Nov 2022

Note: tested with Python 2.7.18 on Linux, but not in a Docker environment.

  • Related