Date arithmetic can be dangerous
Every time I review code others have written, I blame people for doing date arithmetic of their own. However, some time ago, I received a pull request for a module that had some date arithmetic inside. As all tests passed, I could not see something dangerous in it and followed the pull request. Today, I found the date tests failing. Why? Why today? Well, this is worth some investigation.
The main part of the module generates an HTTP-Header using this construct ($c is the mocked catalyst context, expire_in is a method containing the nr of seconds to expire in):
$c->response->headers->expires(time() + $self->expire_in) if ....some_condition...
Well, adding a number of seconds to an epoch value cannot hurt. Can it? The test looked like this:
my $expected_date = (DateTime->now + DateTime::Duration->new(seconds => $controller->{expire_in} )->strftime('%a, %d %b %Y %H:%M:%S GMT'); is $c->response->header('expires'), $expected_date, 'expired header date is OK';
For the test case having an expiry of 3 years, the test failed with a difference of exactly one second:
# Failed test 'expired header date is OK' # at t/5-expire.t line 55. # got: 'Thu, 19 Feb 2015 18:27:59 GMT' # expected: 'Thu, 19 Feb 2015 18:27:58 GMT' not ok 4 - expired header date is OK
One second? Do we have a rounding problem? No. After a while, I remembered that DateTime mentioned a leap-second in its Change-Log some time ago. This could explain our difference.
Doing time-calculations by ourselves is wrong. Replacing the header generation with a more complicated but correct construct worked. Using DateTime before 0.71 kept the old date arithmetic-tests working, but actually the tests should have failed, because the leap-second was ignored.
$c->response->headers->expires( DateTime->now ->add(seconds => $self->expire_in) ->epoch )
My personal conclusion: Date arithmetic is dangerous. Be more strict to any kind of date arithmetic. Never ever do date-math again. Never. Instead: keep all date manipulating modules at a current version and trust in them. Their authors known what they are doing, I don't. I didn't :-(