Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CET/CEST and Europe/Stockholm issues #84

Open
stg opened this issue Oct 5, 2022 · 1 comment
Open

CET/CEST and Europe/Stockholm issues #84

stg opened this issue Oct 5, 2022 · 1 comment

Comments

@stg
Copy link

stg commented Oct 5, 2022

For the better part of a day I've been trying to properly calculate the number of hours in a given day using Python and pytz.
I have significant experience doing date and time calculations, so this should be a simple task.
However, I feel like I am being blocked at every exit.

Please consider the following code:

from datetime import datetime, timedelta
from pytz import timezone

# Set some things up
format = "%Y-%m-%d %H:%M:%S %Z%z"
tz_local = timezone('CET') #Europe/Stockholm
tz_utc = timezone('UTC')

# Set up a date just before the switch from winter to summer time
original = datetime(2022, 3, 25, 13, 11, 25, tzinfo = tz_local)
print(original.strftime(format))
# Create the same date in the world of UTC, where date calculations are easy as pie
redating = datetime(original.year, original.month, original.day, tzinfo = tz_utc)
# Add a week to the date
redating = redating + timedelta(days = 7)
# Create new date+time, with the original time, in the original timezone
output = datetime(redating.year, redating.month, redating.day, original.hour, original.minute, original.second, original.microsecond, tzinfo = tz_local)
print(output.strftime(format))
# Convert to UTC and back again.... (!?)
output = output.astimezone(tz_utc).astimezone(tz_local)
print(output.strftime(format))

The output is:

2022-03-25 13:11:25 CET+0100
2022-04-01 13:11:25 CET+0100
2022-04-01 14:11:25 CEST+0200

I know there have been discussions regarding whether CET should, or should not, have a fixed offset from UTC.

I am working under the understanding that:

  • CET does NOT have a fixed offset from UTC - it observes summer and winter time.
  • CEST is not an actual timezone, it is still CET - but during the summer.

Since I am someone who is used to dealing with the complexities at hand, and live in a country that observes CET you should absolutely not listen to me, because who know - I might just be full of it.
Instead, you should listen to the large number of verifiable sources, online and offline, that claim the same, giving these statements at least some weight.
Also, since pytz does not make a CEST timezone available, it would seem we are in agreement.

Regardless of correctness, it seems quite schizophrenic that I am getting CET from datetime(), but CEST after converting to UTC and back.

The output I would expect from this program is:

2022-03-25 13:11:25 CET+0100
2022-04-01 13:11:25 CEST+0200
2022-04-01 13:11:25 CEST+0200

So, in light of the discussions I've seen on the topic of what CET really is, I decided to go ahead and switch tz_local to Europe/Stockholm - a location-based timezone which, according to those discussions, should always observe DST if applicable.

After this, I get the following output:

2022-03-25 13:11:25 LMT+0053
2022-04-01 13:11:25 LMT+0053
2022-04-01 14:18:25 CEST+0200

This output made me faceplant the keyboard, demand comfort from my wife, and undertake several therapy sessions at the local pub.

Sweden, including Stockholm, like most European countries, observe CET.
I know we are seen as quite backward at times here in Sweden, but I assure you that LMT+0053 is just too weird, even for us.

It may very well be that I am completely wrong or that I am doing things completely wrong.
If this is the case, then I beg your forgiveness for wasting your time and humbly ask to be corrected.
If, however, I am correct - it seems there is a bug in datetime() where it does not correctly return dates that fall within CEST as such, as well as a bug in pytz where it returns incorrect tzinfo for Europe/Stockholm.

I understand that the behavior of datetime() does not fall on pytz to dictate.
But perhaps, given pytz popularity in the date- and time-loving python subcommunity, you might have some pull with the in-crowd.

All the best.

@stg
Copy link
Author

stg commented Oct 7, 2022

What took approximately 6 hours to not solve with datetype+pytz took a single digit number of minutes with Pendulum.

In fact - every single method I tried, while probing for trust, of calculating with Pendulum gave me the expected and correct results, while every single method tried with datetime+pytz blocked me in one way or another.

Lesson learned. Trust firmly relocated.

Example from above, rewritten against Pendulum:

from pendulum import datetime, timezone

# Set some things up
format = "YYYY-MM-DD HH:mm:ss zzZZ"
tz_local = timezone('CET') #Europe/Stockholm
# Set up a date just before the switch from winter to summer time
original = datetime(2022, 3, 25, 13, 11, 25, tz = tz_local)
print(original.format(format))
# Add a week - without contortions
output = original.add(days = 7)
print(output.format(format))

The output is:

2022-03-25 13:11:25 CET+0100
2022-04-01 13:11:25 CEST+0200

And guess what?
Same results with Europe/Stockholm!
Kind of makes sense, since Sweden observes CET.

Now, what I was really looking to calculate:

from pendulum import datetime, timezone
# Set some stuff up
tz_local = 'CET'
# Get current time (emulate early afternoon on a day of DST change)
now = datetime(2022, 3, 27, 13, 14, 15, tz = tz_local)
# Get start of the today
today = now.replace(hour = 0, minute = 0, second = 0, microsecond = 0)
# Get start of tomorrow
tomorrow = today.add(days = 1)
# Print number of hours in the day
print(tomorrow.diff(today).in_hours())

Would you look at that!
The 27'th of March 2022 actually does have only 23 hours in Sweden!
And the code couldn't be more straight forward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant