PHP date/time handling puzzler

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
User avatar
califdon
Jack of Zircons
Posts: 4484
Joined: Thu Nov 09, 2006 8:30 pm
Location: California, USA

PHP date/time handling puzzler

Post by califdon »

I've run into a puzzling issue about mktime() and what you can or can't expect to do with it. I had a problem which I've now avoided by using strtotime(), and that works fine, but I just don't understand why my first intuitive approach doesn't work reliably.

My understanding of PHP's datetime data type is that it represents the number seconds since the Unix Epoch (1/1/1970) and that you should be able to add and subtract seconds to change dates and times. Like to add one day to a datetime variable, you can simply add (60 * 60 * 24). Works like a champ, right? Well, only to a certain extent. First off, when I create a new datetime variable, say $dt = mktime(0, 0, 0, 10, 1, 2009), I get a number which I can display as date('Y-m-d', $dt) and, sure enough, it yields: "2009-10-01". But if I display date('Y-m-d h:i:s', $dt), it shows: "2009-10-01 12:00:00"--NOON?? But I specifically entered a zero for the hour in mktime(). How come it displays 12? Let's say I add a week: $dt = $dt + (60 * 60 * 24 * 7). I can verify that both are on a Wednesday with date('l', $dt). Fine, so far. but then if I repeatedly add weeks, after about 40 or so times in the loop, it seems to hit a snag, and suddenly backs up a day, so that now they show as TUESDAY! What happened?? Here's a little script that does this for 100 repetitions and displays the variables in an html table. Everything seems to match up for the first 43 iterations, then it hiccups, then goes on for another 53 or so rows, then hiccups again. I find it extremely confusing!

I note, in the Manual, that an earlier optional 7th parameter, $is_dst (is it Daylight Saving Time?), has been deprecated beginning with PHP 5.1.0. I don't know if this is involved in any way.

Can anyone shine some light on this behavior?

Don

Code: Select all

<html>
  <head>
  <title>Date Test</title>
  </head>
  <body>
   <table border='1'>
   <tr><td>&nbsp;</td><td>Date in</td><td>+ 7 days</td><td>+ 604800 secs</td>
   <td>DtTm in</td><td>DtTm Out Should be</td><td>DtTm Out Is, with calc</td></tr>
<?php
   $dt = '2009-01-01';
   for($i=1; $i<100; $i++) {
      $yr = substr($dt,0,4);
      $mo = substr($dt,5,2);
      $da = substr($dt,8,2);
      $dttm = mktime(0,0,0,$mo,$da,$yr);
      $dttm2 = $dttm + 60 * 60 * 24 * 7;
      $dttm3 = date(strtotime('+7 days', $dttm));
      $dt2 = date('Y-m-d h:i:s',$dttm2);
      $dt3 = date('Y-m-d h:i:s',$dttm3);
      $dd = date('l',$dttm2);
      echo "<tr><td>$i</td><td>$dt</td><td>$dt3</td><td>$dt2 - $dd</td>";
      echo "<td>$dttm</td><td>$dttm3</td><td>$dttm2</td></tr>";
      $dt = $dt2;
   }
?>
   </table>
  </body>
</html>
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: PHP date/time handling puzzler

Post by requinix »

califdon wrote:My understanding of PHP's datetime data type is that it represents the number seconds since the Unix Epoch (1/1/1970) and that you should be able to add and subtract seconds to change dates and times. Like to add one day to a datetime variable, you can simply add (60 * 60 * 24).
Nope. But you found out that yourself.
califdon wrote:First off, when I create a new datetime variable, say $dt = mktime(0, 0, 0, 10, 1, 2009), I get a number which I can display as date('Y-m-d', $dt) and, sure enough, it yields: "2009-10-01". But if I display date('Y-m-d h:i:s', $dt), it shows: "2009-10-01 12:00:00"--NOON??
"h" is the hour on a 12-hour clock. Midnight is 12:00:00 am ;)
califdon wrote:Let's say I add a week: $dt = $dt + (60 * 60 * 24 * 7). I can verify that both are on a Wednesday with date('l', $dt). Fine, so far. but then if I repeatedly add weeks, after about 40 or so times in the loop, it seems to hit a snag, and suddenly backs up a day, so that now they show as TUESDAY! What happened??
Daylight savings happened. The timestamp is the number of seconds since January 1 1970 midnight GMT. Think about it: with daylight savings we gain or lose an hour at 2am, but when you tell it to add 604800 seconds you mean literally 604800 seconds real-time. If daylight savings ends in that time frame then you need to add another 3600 seconds (because we gained an hour) and if it starts then you added 3600 seconds too many (because we lost an hour) to make up for it.

When you do your math with a time at midnight (or anytime between 11:00pm and 1:00am) the date will jump around at either the beginning or end of daylight savings.

This is exactly why I always tell people that them doing date math themselves is bad. If you ever want to add or remove amounts of time from a date use strtotime.

Code: Select all

$timestamp = strtotime("+1 week", $timestamp); // adds one week to $timestamp
User avatar
califdon
Jack of Zircons
Posts: 4484
Joined: Thu Nov 09, 2006 8:30 pm
Location: California, USA

Re: PHP date/time handling puzzler

Post by califdon »

Many thanks for a crystal clear exposition! Yep, I found out the hard way. I also should have known (or looked up) the proper description of the "h" specifier in date() formatting--should'a used "H"! So I probably could have gotten away with using the calculated version if I had set the initial time to noon instead of midnight (since time isn't a factor in my application), but I'd rather do it the proper way. Anyway, the moral for everyone else is: use strtotime() to add or subtract periods of time!
User avatar
Weirdan
Moderator
Posts: 5978
Joined: Mon Nov 03, 2003 6:13 pm
Location: Odessa, Ukraine

Re: PHP date/time handling puzzler

Post by Weirdan »

califdon wrote:Anyway, the moral for everyone else is: use strtotime() to add or subtract periods of time!
Or, better yet, use DateTime::modify().
Post Reply