3

I'd like to write a small function that can calculate the number of hours in any given day, for any time zone. The obvious approach was to count the hours between the first instant of the day and the next day. Unfortunately, whatever day I choose, this approach always says that a day is 24 hours long.

In the UK, the clocks are advanced at 1am in March by 1 hour. That means the 28th March 2021 should have 23 hours. The time-range from 1am to 2am will not have existed that day.

Likewise, on the 31st October 2021 the clock is pushed back at 1am, so that day will have 25 hours. The time-range midnight to 1am will have occurred twice in that day.

import datetime
import pytz

# When do the clocks change?
# https://www.gov.uk/when-do-the-clocks-change

day0=datetime.datetime(2021,3,28, tzinfo=pytz.timezone("Europe/London"))
day1=datetime.datetime(2021,3,29, tzinfo=pytz.timezone("Europe/London"))

delta = day1-day0

print(delta)
hours = delta / datetime.timedelta(hours=1)
print(hours)

This script gives output that seems incorrect:

1 day, 0:00:00
24.0 

Is there a simpler way to get the number of hours in a particular day, that gives the right answer?

Ideally this should be able to account for daylight savings, leap-years and even leap seconds.

Salim Fadhley
  • 6,975
  • 14
  • 46
  • 83
  • Does this need to handle only daylight saving time changes, or are "leap seconds" also included? I don't know whether there are any other clock changes in use. – Prune May 20 '21 at 17:40
  • Yes, I've added this as a clarification to the question. Thank you. – Salim Fadhley May 20 '21 at 17:42
  • This is a good question. Leap-year day is by ISO standard. Leap seconds are negotiated by the scientific community through ISO. Daylight saving time is controlled by local authority (nation, province, state). I don't know of any convenient resource to get all of these changes for a given location. Leap seconds in the future are a bit volatile. – Prune May 20 '21 at 17:49

1 Answers1

1

Part of the issue is "using the tzinfo argument of the standard datetime constructors ‘’does not work’’ with pytz for many timezones."

So we can work around that by using timezone.localize() with a local naive time (no tz):

London = pytz.timezone("Europe/London")

day0 = London.localize(datetime.datetime(2021,3,28))
day1 = London.localize(datetime.datetime(2021,3,29))

(day1  - day0).total_seconds() / 60 / 60  # in hours
# 23.0

And for 31st October:

day0 = London.localize(datetime.datetime(2021, 10, 31))
day1 = London.localize(datetime.datetime(2021, 11, 1))
(day1  - day0).total_seconds() / 60 / 60
# 25.0
aneroid
  • 12,983
  • 3
  • 36
  • 66