Is strtotime() having a bug? - php

Consider this code where we want to add or substract one second:
date_default_timezone_set("Europe/Amsterdam");
$time = 1477789199;
echo $time . ' - ' . date('r', $time) . "\n";
// 1477789199 - Sun, 30 Oct 2016 02:59:59 +0200
This is correct, as this timestamp is still just within DST (daylight savings time / summer time).
But now let's add one second to the timestamp integer, and exit DST:
$new = $time + 1;
echo $new . ' - ' . date('r', $new);
// 1477789200 - Sun, 30 Oct 2016 02:00:00 +0100
Hooray! PHP sees that one second later there is no DST anymore and shows a proper time string.
But what if we didn't add a second to the timestamp integer, but we used strtotime() to add that one second:
$new = strtotime('+1 second', $time);
echo $new . ' - ' . date('r', $new);
// 1477792800 - Sun, 30 Oct 2016 03:00:00 +0100
Yikes! We just went ahead by more than one hour instead of one second. And it doesn't even matter if you add one second, one hour, one day or one year you will always get one extra hour with it. Even if you add multiple years, you will only get one extra hour, which is weird because we enter and exit DST every year but you only get one extra hour regardless of how many years you add
But once we exit DST in October and subtract one second, all goes fine...
But then again. If we were in March and we have just entered DST, and we subtract one second, we observe exactly the same in reverse.
Wait, what ?! So ... ?
echo strtotime('+ 1 second - 1 second', 1477789199); // echoes 1477792799
Whoa ...
To me this sounds like a bug. Or is this 'by design'? Does anyone even know if this is documented somewhere, or whether it needs to be reported?

The behavior is "well documented" .... in a test:
See https://bugs.php.net/bug.php?id=30532 (which also presents your expected result as expected) and the related test file (which asserts that the current behavior is correct) https://github.com/php/php-src/blob/master/ext/date/tests/bug30532.phpt
<?php date_default_timezone_set("America/New_York");
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 01:00:00 EST
2004-10-31 02:00:00 EST */
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 02:00:00 EST
2004-10-31 03:00:00 EST */
Note that in the former case the timezone (here: EDT) is being passed directly to the string, in the latter case it isn't.
In general strtotime is taking the timestamp (i.e. of 2004-10-31 - or in your specific case: the passed timestamp), converted to a representation with individual parameters, ignoring DST (i.e. individual hours, minutes, seconds, day, month, year etc.), the operation is applied to it and then converted back to the timestamp.
In particular:
echo date('r', strtotime('+ 0 second', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0100
strtotime() throws the timezone after conversion away, i.e. only takes
Sun, 30 Oct 2016 02:59:59
and then applies the primary applicable timezone to your timezone location (i.e. Europe/Amsterdam), ending up with CET (primary!) - CEST is also possible, but only second choice.
Now, look back at the test above, just specify the originating timezone explicitly.
Thus, if you wish it to behave the way you need it:
echo date('r', strtotime('CEST', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0200
echo date('r', strtotime('CEST + 1 second', 1477789199));
#> Sun, 30 Oct 2016 02:00:00 +0100
In fact, prepending 'CEST ' will be fine for all the times (as it will always fallback to CET if CEST is not matching and there's no overlap on CET -> CEST transition).

Related

strtotime wrong value after I added 1 month

this line gives me the correct value:
echo strtotime(date('d.m.Y 00:00:00'));
Output:
1623362400
Converted:
Fri Jun 11 2021 00:00:00 GMT+0200 (CEST)
Now I would like to get the same, but +1 month.
I tried this:
echo strtotime('+1 month', date('d.m.Y 00:00:00'));
Output:
2678411
Converted:
Sun Feb 01 1970 01:00:11 GMT+0100 (CET)
Where is my fault?
You're not using well the first strtotime() param. Passing 2 arguments ask the function to "compare" and use the second param as a baseTimestamp.
For the result you want, you only need the first param, and have to specify you want "+1 month" before. You can do it concatenating the string with date() result :
echo strtotime(date('d.m.Y 00:00:00').' +1 month');
You don't need to nest string operations or convert back and forth:
$t = strtotime('midnight +1 month');
echo date('r', $t);

Round Timestamp to a specific hour

I have a timestamp say 1512070200 which translates to November 30, 2017 7:30:00 PM GMT or December 1, 2017 01:00:00 AM GMT+05:30 in IST.
I want to be able to subtract the time that has passed on that day and revert back to the time at 12:00:00 AM.
For example
If i get a timestamp of 1512978955 which is December 11, 2017 7:55:55 AM GMT I want the output to be 1512950400 which is December 11, 2017 12:00:00 AM GMT.
There is no fixed amount of hours that can be subtracted from the timestamp, instead it would be a variable amount depending on the time that has passed for that particular day so it could be 1 millisecond or 1 second or 1 minute or 1 hour since 12:00:00 AM.
One way would be to convert the timestamp to a date and then break into it's constituent parts so that you can use mktime to generate the date at midday
$ts=1512070200;
$y=date('Y',$ts);
$m=date('m',$ts);
$d=date('d',$ts);
$date=date('Y-m-d H:i:s',mktime(12,0,0,$m,$d,$y));
echo date('Y-m-d H:i:s',$ts).' -> '.$date;
which outputs
2017-11-30 19:30:00 -> 2017-11-30 12:00:00
or, if the output date needs to be as shown use
$format=DATE_COOKIE;
$ts=1512070200;
$y=date('Y',$ts);
$m=date('m',$ts);
$d=date('d',$ts);
$date=date($format,mktime(12,0,0,$m,$d,$y));
echo date($format,$ts).' -> '.$date;
#Thursday, 30-Nov-17 19:30:00 GMT -> Thursday, 30-Nov-17 12:00:00 GMT
Even easier is to use noon as shown by #splash58
echo date( $format, strtotime( 'noon', $ts ) );
You can set noon time to DateTime object
$ts=1512070200;
$date = new DateTime();
$date->setTimestamp($ts);
$date->modify('noon');
echo $date->format(DATE_COOKIE); // Thu, 30 Nov 2017 12:00:00 +0000
demo

Converting date from JSON response in PHP

I am getting the following date format from a JSON response and want to format it better, but I am a little unsure how to.
Current Response: Wed Mar 02 03:00:00 +1100 2016
Required Response: 2nd of March 2016
Current PHP for output:
$purchase_data['verify-purchase']['supported_until']
some speacial formatting here, but possible when reading the manual.
also take care of time zone…
<?php
//custom function
function reformatDate( $old, $correction ) {
// makes it a number of seconds since 1970…
$old_date_timestamp = strtotime( $old );
//formats again as string
return date( 'jS F Y', $old_date_timestamp + $correction );
}
//Input: Wed Mar 02 03:00:00 +1100 2016
//timezone needs to be taken care of
print reformatDate(
"Wed Mar 02 03:00:00 +1100 2016", //here you put your input variable
11*60*60 // here 11h, but maybe the difference of timezones needs to be changed – only you will know after edge cases ;)
);
//desired output: 2nd of March 2016 – check
?>
to do it even better you could ask your own timezone from the local setting. date can help you there as well, or you go by timezone_offset_get to automate that … the latter is more tricky as it raises an error when not set before.
Try this out:
$old_date_timestamp = strtotime($purchase_data['verify-purchase']['supported_until']);
$new_date = date('d F Y', $old_date_timestamp);
print $new_date;
Someone posted an answer on here but for some reason was deleted, however i used some of their solution and adapted and created into a function so for anyone else needing to handle a returned date formatted in such a way here is what i done.
function dateFormat($date){
$current_date = $date;
return date("jS", strtotime($current_date) ) . ' of ' . date("F Y", strtotime($current_date) );
}
Then called it like so....
dateFormat($purchase_data['verify-purchase']['supported_until']);
Output went from:
Wed Mar 02 03:00:00 +1100 2016
To:
1st of March 2016
Actually noticed now writing this, it is rounding off to 1st rather than 2nd?
UPDATED
Updated with answer from #vv01f to correct the date, here is the final result
function dateFormat( $old, $correction ) {
$old_date_timestamp = strtotime( $old );
return date( 'jS F Y', $old_date_timestamp + $correction );
}
Calling it like so...
dateFormat($purchase_data['verify-purchase']['supported_until'], 11*60*60);

Convert a datetime format to match MySQL's datetime with PHP

I need a way to convert this format Tue, 20 Oct 2015 17:43:23 0000
to the datetime format that MySQL accepts.
I have tried to convert it with strtotime() but the function returns a negative number.
The problem appears to be the trailing zeroes, by trimming them from the date string it seems to work fine. The code below uses one of the Date constants - change that for the format desired.
$d='Tue, 20 Oct 2015 17:43:23 0000';
echo date( DATE_COOKIE, strtotime( trim($d,' 0000') ) );
outputs -> Tuesday, 20-Oct-15 17:43:23 BST
echo date( 'Y-m-d H:i:s', strtotime( trim($d,' 0000') ) );
outputs -> 2015-10-20 17:43:23
Try this with your time specified as the $inputtime variable:
strftime("%F %H:%M:%S", strtotime($inputtime))
The problem lies in your time format Tue, 20 Oct 2015 17:43:23 0000. Here 0000 means time zone. But it should have format + or - before value to work properly. Look at example:
echo strtotime("Tue, 20 Oct 2015 17:43:23 +0000");
Try this
$date = \DateTime::createFromFormat('r',your date);
$date = $date->format(format that you need);

Javascript time to PHP time

I have a time value in javascript for example 11:30:00.
Date {Mon Oct 22 2012 11:30:00 GMT+0800 (Taipei Standard Time)}
and I passed to a php file and converted it by:
$newTime = date('H:i:s', $theTime);
But, it return 05:36:00. What is the right way of concerting time?
Use myDate.getTime() instead, and then divide this by 1000 since PHP deals with seconds while JavaScript deals with milliseconds.
If you're looking to use PHP to parse the date/datetime, then you should use strtotime(). Something like:
$time = "Mon Oct 22 2012 11:30:00 GMT+0800";
echo date('Y-m-d h:i:s', strtotime($time));
Which would output:
2012-10-22 04:30:00
This output is GMT, which you can change if required.
EDIT:
If you're expecting 11:30:00, then try the following:
date_default_timezone_set('UTC');
$time = "Mon Oct 22 2012 11:30:00 GMT+0800";
echo date('Y-m-d h:i:s', strtotime($time));

Categories