skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

    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.


  2. 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search