2

While reading this question about parsing dates of the form %m/%d/%y, I realized that I don't know how the %y directive actually works.

The docs state the following:

Year without century as a zero-padded decimal number.

But which century does it use? If I use %y to parse the year 01, will that result in 1901 or 2001? If I re-run the same code in 100 years, will it result in 2101?


As an experiment, I wrote some code that parses all numbers from 0 to 99 and displays the results:

for year in range(100):
    date = '6/1/{:>02}'.format(year)
    dt = datetime.strptime(date, "%m/%d/%y")
    print(year, dt.date())

The results were surprising:

0 2000-06-01
1 2001-06-01
2 2002-06-01
...
67 2067-06-01
68 2068-06-01
69 1969-06-01 # <- wut
70 1970-06-01
71 1971-06-01
...
98 1998-06-01
99 1999-06-01

Why does it suddenly jump from 2068 to 1969? Is this behavior documented anywhere? What's the formal specification for %y?

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149

3 Answers3

4

From the time docs, emphasis mine:

Year 2000 (Y2K) issues: Python depends on the platform’s C library, which generally doesn’t have year 2000 issues, since all dates and times are represented internally as seconds since the epoch. Function strptime() can parse 2-digit years when given %y format code. When 2-digit years are parsed, they are converted according to the POSIX and ISO C standards: values 69–99 are mapped to 1969–1999, and values 0–68 are mapped to 2000–2068.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
miradulo
  • 28,857
  • 6
  • 80
  • 93
1

You can read the CPython implementation of strptime here, and in particular at lines 384-392 there is the interesting bit:

    if group_key == 'y':
        year = int(found_dict['y'])
        # Open Group specification for strptime() states that a %y
        #value in the range of [00, 68] is in the century 2000, while
        #[69,99] is in the century 1900
        if year <= 68:
            year += 2000
        else:
            year += 1900

This behavior is also explained in the manual ot time:

Year 2000 (Y2K) issues: Python depends on the platform’s C library, which generally doesn’t have year 2000 issues, since all dates and times are represented internally as seconds since the epoch. Function strptime() can parse 2-digit years when given %y format code. When 2-digit years are parsed, they are converted according to the POSIX and ISO C standards: values 69–99 are mapped to 1969–1999, and values 0–68 are mapped to 2000–2068.

fferri
  • 18,285
  • 5
  • 46
  • 95
  • Looks like `Year 2068 problem`... I wonder how many little `Year 20xx` problems we have around that everyone forgot about. "It's patched, but we need to fix it before year 20xx" -- "That's plenty of time. Create a low priority ticket" – Marjeta Jul 18 '23 at 03:25
0

strptime presumably is a basic wrapper around C's strptime.

Of strptime, the POSIX specification states:

%y The year within century. When a century is not otherwise specified, values in the range [69,99] shall refer to years 1969 to 1999 inclusive, and values in the range [00,68] shall refer to years 2000 to 2068 inclusive; leading zeros shall be permitted but shall not be required.

Note: It is expected that in a future version of IEEE Std 1003.1-2001 the default century inferred from a 2-digit year will change. (This would apply to all commands accepting a 2-digit year as input.)

jamesdlin
  • 81,374
  • 13
  • 159
  • 204