Spoiler alert: I couldn't end up doing this, jesus christ timezones are such a mess
There are many mappings between timezones.
- Obviously I could maintain one myself, but it's sufficiently complex that I don't want to take this on
- Unicode maintains a mapping of Windows to IANA zones, but it only has entryes for standard timezone names ("Pacific Standard Time") and not DST timezone names ("Pacific Daylight Time"): https://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
- The
tzlocal
module has the same problem: Windows mappings only for standard, not DST, timezone names - The
pytz
module has no support for Windows names at all - As alluded to, Windows has names like "Pacific Standard Time". The IANA
tzdb
timezone database has names like "US/Pacific".
def timezone_py2win(cls, tzname):
"""Convert a Python timezone name to a Windows timezone name
For example: CST -> Central Standard Time
"""
winzones_url = 'https://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml'
winzones_xml = urllib.request.urlopen(winzones_url).read().decode()
winzones = xml.etree.ElementTree.parse(winzones_xml)
for zone in winzones.findall('.//mapZone'):
if zone.attrib['territory'] == '001' and zone.attrib['type'] == tzname:
return zone.attrib['other']
raise Exception(
f"Could not find a Windows timezone for a Python timezone named '{tzname}''")
I had something like this in my Dockerfile. This will work fine if PSYOPS_TIMEZONE
is set to an IANA timezone
Dockerfile
(excerpt):
ENV PSYOPS_USER="psyops"
ENV PSYOPS_TIMEZONE="UTC"
RUN true \
&& apk add shadow tzdata \
&& addgroup -S timekeeper \
&& usermod -g timekeeper "$PSYOPS_USER" \
&& chgroup timekeeper /etc/localtime \
&& true
CMD /bin/bash -i
ENTRYPOINT $HOME/.entrypoint.sh
$HOME/.entrypoint.sh
:
#!/bin/bash
cat "/usr/share/zoneinfo/${PSYOPS_TIMEZONE}" > /etc/localtime
exec /bin/bash -i
This should work for any IANA value like US/Central
or whatever, and, since we don't set the timezone in the Dockerfile but rather in a script that is read when the container is started, we can change the timezone at runtime.
Linux appears to use IANA names like US/Central
Windows has its own naming system. These .NET calls, which work in both Powershell and C#:
[System.TimeZoneInfo]::Local.DisplayName
[System.TimeZoneInfo]::Local.Id
[System.TimeZoneInfo]::Local.DaylightName
currently return the following values on my system:
(UTC-06:00) Central Time (US & Canada)
Central Standard Time
Central Daylight Time
I believe macOS uses a different naming system, but I'm not sure because I don't have a Mac in front of me at the moment
Python provides
import datetime, time
datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo
datetime.datetime.now(datetime.timezone.utc).astimezone().tzname()
time.tzname
Which on my Windows system currently return
datetime.timezone(datetime.timedelta(-1, 68400), 'Central Daylight Time')
Central Daylight Time
('Central Standard Time', 'Central Daylight Time')
respectively. Note that the .tzname()
function returns the DST name on a Windows system currently observing DST, while the time.tzname
variable holds both names in a list.
Off topic for Python, but related to what I was trying to do:
When setting the time for a VM defined in an Azure Resource Manager template, you have to set the osProfile.windowsConfiguration.timeZone
property on the VM resource. This property takes only standard names, and if the timezone you pass is currently observing DST, it will still display the correct time (e.g. in the systray or with Powershell's Get-Date
).
Python provides some support for the concept of timezones, but leaves more robust timezone support to third party modules. There are a couple of Python modules I've seen recommended when dealing with time zones.
tzlocal
uses the Unicode Consortium'swindowsZones.xml
to convert between Windows time zone namespytz
is more commonly recommended and also maintains a mapping for Windows zone names, but I'm not sure whether it comes from the Unicode Consortium or elsewhere
I opened a bug with Microsoft about the lack of an enumeration, and the answer was basically that there isn't a published enumeration because it would be a maintenance burden (it probably changes frequently, as counterintuitive as that might be), but that you can get a list from .NET (C#/Powershell):
[System.TimeZoneInfo]::GetSystemTimeZones()
This even works with Powershell Core on my Mac! However, the property used in the answer is Id
, and on the Mac, that returns IANA timezone names (lol), while on Windows it apparently returns Windows names. The StandardName
property always contains the standard (non-DST) Windows timezone name, even on my Mac.