My Y2020 Bug

For reasons that must have been clear at the time, I once wrote a test in terms of epoch time, and wanted it to run on systems that did not use January 1 1970 as the epoch. So I loaded Time::Local and added timegm( 0, 0, 0, 1, 0, 70 ) to the desired epoch.

This morning I got a CPAN testers report failure. It seems that if you give timegm() a year in the range 0-99 it assumes it is within 50 years of the current year, so my test suddenly thought the epoch was 2070.

In this case, the obvious response is to specify a four-digit year.

Maybe a better response is to ditch timegm() and timelocal() completely in favor of timegm_modern() and timelocal_modern(). These require Time::Local version 1.27, released June 2019. According to its metadata it works back to Perl 5.6, though so far I have only verified it back to Perl 5.8.1.

With thanks to Dave Rolsky for the *_modern() variants, and to Chris Williams (BINGOS), who uncovered this in one of his CPAN tester systems.

CPAN Testers Rule!

5 Comments

Is that in fact a better response?

It comes at the cost of an additional dependency that old perls will have to install from CPAN, and every dependency installed from CPAN has the potential to come at the cost of having to upgrade your any amount of your toolchain.

Of course, this is always the case for dependencies, and it doesn’t mean that dependencies are bad per se. We add them because they provide value. All it means is that dependencies also incur a cost, meaning there is a trade-off.

So then what is the benefit to adding this dependency?

Well, if you use the _modern variants, you have to write the year as 1970.

Just like you have to if you do not.

Meaning, your use case gains absolutely nothing from the added dependency. Zero. All the added dependency does is make your code slower to install on older perls, in exchange for… the empty set.

Please don’t.

Isn’t Time::Piece->strptime( '1970-01-01', '%Y-%m-%d' ) far more defensive in that sense than either timegm( 0, 0, 0, 1, 0, 1970 ) or timegm_modern( 0, 0, 0, 1, 0, 1970 )?

(Isn’t it great that that says … 1, 0, 1970 rather than … 1, 1, 1970? Do you always immediately remember which one is supposed to be zero and which one is 1 and why?)

Thank you very much for Modern functions in a post-modern language.

You provided the impetus to write it. 🙂 There had been other discussions about the new functions, but the conversation in this comment thread is what pushed me to consolidate my thoughts into an article – both so I wouldn’t have to repeat myself, but more importantly to have the scope to lay out the full case, since individual points by themselves are not very persuasive.

But the support modules have taken on a life of their own

No surprise… arguably exactly what happened with Time::Local. I understand your position, I ran into similar issues trying to figure out how to fix the 2020 bug in Date::Parse – which advertises the fact that it’s built on top of Time::Local. (There are lots of patches claiming to fix that module, none of which seem correct to me on closer examination.)

If only we had a core timegm() that round-tripped with gmtime()!

Or, one daren’t even think it, something more reasonable than crusty old gmtime

Leave a comment

About Tom Wyant

user-pic Fine Perl code for over 0.005 centuries.