-
Notifications
You must be signed in to change notification settings - Fork 609
Description
Today on Reddit, a question came up about whether Perl is Y2K38-compliant, so I wrote a response explaining how Perl’s localtime() fallback handles dates beyond 2038. Afterward, I checked the localtime() and perlport documentation, but neither describes how this fallback actually works. I believe the documentation should explain the fallback implementation and warn that localtime() may discard known timezone changes which may result in incorrect times.
Personally, I think it would have been far better to fail hard than to produce incorrect times.
On systems where localtime() is limited to 2038, to avoid Year-2038 limits, Perl maps out-of-range dates to a “calendar-equivalent” year between 2010 and 2037 and calls the system’s localtime(). The mapped year has the same leap-year and weekday pattern, so localtime() works, after which the original year is restored. This preserves the calendar shape but uses the DST rules of the mapped year.
Here is a concrete example of how this affects the Europe/Moscow time zone:
Europe/Moscow changed from UTC+04:00 to UTC+03:00 on 26 October 2014. Because Perl maps out-of-range dates to a calendar-equivalent year within 2010–2037, every 28-year cycle after 2037 contains a consecutive five-year span during which times in Europe/Moscow are off by one hour.
May 31 04:00:00 2010
May 31 04:00:00 2011
May 30 04:00:00 2012
May 30 04:00:00 2013
May 30 04:00:00 2014
May 30 03:00:00 2015 <- switched to UTC+03:00
May 29 03:00:00 2016
May 29 03:00:00 2017
May 29 03:00:00 2018
May 29 03:00:00 2019
May 28 03:00:00 2020
May 28 03:00:00 2021
May 28 03:00:00 2022
May 28 03:00:00 2023
May 27 03:00:00 2024
May 27 03:00:00 2025
May 27 03:00:00 2026
May 27 03:00:00 2027
May 26 03:00:00 2028
May 26 03:00:00 2029
May 26 03:00:00 2030
May 26 03:00:00 2031
May 25 03:00:00 2032
May 25 03:00:00 2033
May 25 03:00:00 2034
May 25 03:00:00 2035
May 24 03:00:00 2036
May 24 03:00:00 2037
May 24 04:00:00 2038 <- Incorrect UTC+04:00
May 24 04:00:00 2039 <-
May 23 04:00:00 2040 <-
May 23 04:00:00 2041 <-
May 23 04:00:00 2042 <-
May 23 03:00:00 2043
May 22 03:00:00 2044
May 22 03:00:00 2045
May 22 03:00:00 2046
May 22 03:00:00 2047
May 21 03:00:00 2048
May 21 03:00:00 2049
May 21 03:00:00 2050
May 21 03:00:00 2051
May 20 03:00:00 2052
May 20 03:00:00 2053
May 20 03:00:00 2054
May 20 03:00:00 2055
May 19 03:00:00 2056
May 19 03:00:00 2057
May 19 03:00:00 2058
May 19 03:00:00 2059
May 18 03:00:00 2060
May 18 03:00:00 2061
May 18 03:00:00 2062
May 18 03:00:00 2063
May 17 03:00:00 2064
May 17 03:00:00 2065
May 17 04:00:00 2066 <- 28-year cycle repeats
May 17 04:00:00 2067