Skip to content

Y2K38 documentation/fallback #24102

@chansen

Description

@chansen

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions