babel
babel copied to clipboard
No daylight saving time applied for Europe/London timezone
Overview Description
If I convert a datetime object to the timezone Europe/London, the time is (largely) unchanged, with no daylight saving applied. The conversion works correctly for a few other timezones I tried (GB, Europe/Berlin, Africa/Johannesburg).
I also get an unexpected 1 minute offset.
Reproducibility
>>> from datetime import datetime
>>> from babel.dates import get_timezone
>>> t = datetime(2024, 5, 9, 12, 30)
>>> t
datetime.datetime(2024, 5, 9, 12, 30)
>>> t.replace(tzinfo=get_timezone()).astimezone(get_timezone('Europe/London'))
datetime.datetime(2024, 5, 9, 12, 30, tzinfo=<DstTzInfo 'Europe/London' LMT-1 day, 23:59:00 STD>)
>>> t.replace(tzinfo=get_timezone()).astimezone(get_timezone('GB'))
datetime.datetime(2024, 5, 9, 13, 31, tzinfo=<DstTzInfo 'GB' BST+1:00:00 DST>)
>>> t.replace(tzinfo=get_timezone()).astimezone(get_timezone('Europe/Berlin'))
datetime.datetime(2024, 5, 9, 14, 31, tzinfo=<DstTzInfo 'Europe/Berlin' CEST+2:00:00 DST>)
>>> t.replace(tzinfo=get_timezone()).astimezone(get_timezone('Africa/Johannesburg'))
datetime.datetime(2024, 5, 9, 14, 31, tzinfo=<DstTzInfo 'Africa/Johannesburg' SAST+2:00:00 STD>)
Additional Information
Babel 2.15.0 via pip, pytz 2024.1 via package manager (dnf), Python 3.12.3, Fedora 39.
I'm unsure what is your local timezone but datetime.astimezone() should be used rather than datetime.replace(tzinfo=...).
>>> from datetime import datetime
>>> from babel.dates import get_timezone
>>> t = datetime(2024, 5, 9, 12, 30)
>>> localtz = get_timezone()
>>> localtz
<DstTzInfo 'Asia/Tokyo' LMT+9:19:00 STD>
>>>
>>> t.astimezone(localtz)
datetime.datetime(2024, 5, 9, 12, 30, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
>>> t.astimezone(localtz).astimezone(get_timezone('Europe/London'))
datetime.datetime(2024, 5, 9, 4, 30, tzinfo=<DstTzInfo 'Europe/London' BST+1:00:00 DST>)
>>>
>>> t.replace(tzinfo=localtz)
datetime.datetime(2024, 5, 9, 12, 30, tzinfo=<DstTzInfo 'Asia/Tokyo' LMT+9:19:00 STD>)
>>> t.replace(tzinfo=localtz).astimezone(get_timezone('Europe/London'))
datetime.datetime(2024, 5, 9, 4, 11, tzinfo=<DstTzInfo 'Europe/London' BST+1:00:00 DST>)
What is your end goal here? 🤔
Also note that get_timezone() is just a simple wrapper for pytz.timezone() (if pytz is installed) or zoneinfo.ZoneInfo(); there's nothing Babel-specific about this, really...
This is something I isolated from a MkDocs plugin I've used called mkdocs-git-revision-date-localized-plugin. Specifically, these four lines (dates.py:29-32) are used to generate the local timestamp that appears on the pages:
utc_revision_date = datetime.fromtimestamp(int(unix_timestamp), tz=timezone.utc)
loc_revision_date = utc_revision_date.replace(
tzinfo=get_timezone("UTC")
).astimezone(get_timezone(time_zone))
I accept that this might be deeper than Babel but I started by digging into the code for the plugin. I'll see if I can reproduce directly with pytz.timezone or zoneinfo.ZoneInfo.
I'm happy to close this as a misuse of the functions that doesn't actually appear anywhere. The code in the plugin doesn't reproduce the error anyway, presumably, because it uses .replace(tzinfo=get_timezone("UTC")) rather than .replace(tzinfo=get_timezone()).
utc_revision_date = datetime.fromtimestamp(int(unix_timestamp), tz=timezone.utc) loc_revision_date = utc_revision_date.replace( tzinfo=get_timezone("UTC") ).astimezone(get_timezone(time_zone))
You could change that code like the following, simply:
loc_revision_date = datetime.fromtimestamp(int(unix_timestamp), tz=get_timezone(time_zone))