How long is a date?
Or “Why does @Jean have so much trouble with international announcements?”
How long is a day? Easy, 24 hours, give or take a few seconds, because planetary rotations and orbits aren’t static.
But how long is a date? Well, it can seem like forever if you aren’t interested in the other person…
Ooops, sorry, I meant, for a given date, say November 6, 2022, how many continuous hours is it that date somewhere on Earth? This is a different question than the number of hours in a day. I didn’t trust my mental arithmetic, so I wrote a little Haskell program to convince myself.
This is a literate Haskell program, and I’m going to use the standard time library, even though it lacks some elegance.
import Data.Time
First, I’m going to calculate how many hours are in a day, just to verify that my method works. I’m going to take the difference of two date/time values and show the result in hours. The values represent midnight on successive dates, in the same timezone. I’m using UTC for convenience.
howLongIsADay :: Hours
howLongIsADay = toHours (diffUTCTime ut1 ut0)
ghci> howLongIsADay
Hours 24
Great. So, if we stay within one timezone, we get the standard answer. But what if we consider the difference between the beginning of the day in New Zealand and the end of the day in Hawaii? For that, we need to start with ZonedTime values, convert them to UTC, and then take the difference.
howLongIsADate :: Hours
howLongIsADate = toHours (diffZonedTime zt1 zt0)
ghci> howLongIsADate
Hours 46
Well, not 24, but also not 48. New Zealand is UTC+12 and Hawaii is UTC-10, which is a difference of 22 hours. Presumably I could find more exotic time zones 24 hours apart, but I don’t need to bother. The surprising part is that any particlar date spans 48 hours.
I suppose anyone who deals in international finance knows this quite well, but I don’t think I had understood this fully. The new reality has replaced my old, fuzzy understanding, but I think I would have thought about 36 hours, thinking sunrise to sunset…somehow.
If you find this confusing, just be glad I only used standard time. Many places change to and from daylight savings time on different dates, so the number of hours difference can change during the year.
Anyway, I expect that contributes to @Jean having a hard time scheduling these challenges. Pun intended.
newtype Hours = Hours Int deriving Show
diffZonedTime :: ZonedTime -> ZonedTime -> NominalDiffTime
diffZonedTime t1 t0 = diffUTCTime (zonedTimeToUTC t1) (zonedTimeToUTC t0)
today :: Day
today = ModifiedJulianDay 59889
tomorrow :: Day
tomorrow = succ today
-- I avoided using IO to simplify the presentation, but I acquired the correct
-- number by running this once using it in the pure value of 'today', found above.
today' :: IO Day
today' = utctDay <$> getCurrentTime
ut0 :: UTCTime
ut0 = UTCTime today 0
ut1 :: UTCTime
ut1 = UTCTime tomorrow 0
zt :: Day -> TimeZone -> ZonedTime
zt d tz = ZonedTime (LocalTime d midnight) tz
zt0 :: ZonedTime
zt0 = zt today nzst
zt1 :: ZonedTime
zt1 = zt tomorrow hst
nzst :: TimeZone
nzst = TimeZone (12*60) False "NZST"
hst :: TimeZone
hst = TimeZone (-10*60) False "HST"
toHours :: NominalDiffTime -> Hours
toHours = Hours . cvt . truncate . nominalDiffTimeToSeconds
where cvt h = h `div` (60*60)