PHP strtotime timezone issue with '0:00 GMT' - php

So I have a function get_start_of_day($time), which I want to give me a timestamp representing the very very first minute of the day in which $time, a timestamp, falls.
Originally, I was using:
function get_start_of_day($time) {
return strtotime('0:00 GMT', $time);
}
which seemed to be working just fine.
Then I realized that for certain times it was returning midnight of the previous day, for example:
$x = 1432468800;
echo gmdate('Y-M-d H:i:s', $x);
$y = get_start_of_day($x);
echo gmdate('Y-M-d H:i:s', $y);
outputs:
2015-May-24 12:00:00
2015-May-24 00:00:00
BUT:
$x = 1432432800;
echo gmdate('Y-M-d H:i:s', $x);
$y = get_start_of_day($x);
echo gmdate('Y-M-d H:i:s', $y);
outputs:
2015-May-24 02:00:00
2015-May-23 00:00:00
So at some value for $x, the output was wrongly jumping to the day previous and outputting that. Some further experimentation revealed that the value for $x at which the jump happens is 4am, i.e. the timestamp 1432440000 gave the proper result, but the timestamp 1432439999 did not.
Now, according to Epoch Converter I'm in GMT-4:00. It seems as though this must somehow be the cause. I've updated the function to:
function get_start_of_day($time) {
$start_of_day = strtotime('tomorrow 0:00 GMT', $time);
if ($start_of_day > $time) {
$start_of_day -= 86400;
}
return $start_of_day;
}
which seems to work fine, but I can't help but wonder...what's going on here? Does anybody know?
Thanks in advance! :)
EDIT: I'm using GMT in case I move to a new server...I would hate to be getting different start-of-day values after I hypothetically move, which may not sync up with the old values. So I figured, just use GMT for everything, all the time.

Use strtotime('today', $time). You will need to use date_default_timezone_set or date.timezone INI setting to select your time zone.

Related

How to fix this very frustrating time bug in my time code?

I have these two functions:
function time_is_older_than($timestamp, $time_string)
{
if (strtotime($timestamp) < strtotime('-' . $time_string))
return true;
return false;
}
function time_is_younger_than($timestamp, $time_string)
{
if (strtotime($timestamp) > strtotime('-' . $time_string))
return true;
return false;
}
They enable me to do neat things like:
if (time_is_older_than($last_time_some_action_happened, '5 minutes'))
do_it_again();
They normally work, except for during one hour every six months, when my timezone switches over to "summer time" or "winter time". This means that the clocks are increased or put back one hour at midnight (according to this timezone).
The PHP manual states this for strtotime:
The Unix timestamp that this function returns does not contain information about time zones. In order to do calculations with date/time information, you should use the more capable DateTimeImmutable.
However, if I provide the exact same date/time string, with "+08:00" added in the end versus "+00:00", for example, I get different numbers of seconds returned. So strtotime() does understand timezones when it parses the provided time, even if the returned integer obviously doesn't contain this information. (Nor is it expected or required to by me.)
I've spent countless hours trying to debug this, testing countless things, and just sitting here thinking, but I can't figure out what exactly would make the code I have fail, specifically for one hour. And especially what about it I need to change. Setting the second parameter for strtotime() seems likely, but I just couldn't make it work correctly.
My hottest "lead" for quite some time was that the strtotime('-' . $time_string) part is ending up using a different timezone than the timestamp strings provided, but I do provide timezone data to it most of the time! An example of $last_time_some_action_happened might be something like 2020-10-28 02:22:41.123456+01.
I set the timezone with date_default_timezone_set().
I suspect that I only need to make some very minor change, but I've been experimenting so much and so long now, even taking rests in between, that my brain can no longer see this clearly. I bet the solution is something awfully simple.
Please don't tell me to use DateTimeImmutable. This would fundamentally change my entire structure and require me to do things very differently. Perhaps I should, and even will, at some point, but for now, I just wish to fix this rare but still very annoying bug in my existing code. (If it's possible at all, which I very much believe is the case.)
I'm able to reproduce the issue you are having:
date_default_timezone_set('Pacific/Auckland');
// Daylight saving time 2020 in New Zealand began at 2:00am on Sunday, 27 September
$current = strtotime('2020-09-27 02:04:00');
$d1 = strtotime('2020-09-27 02:05:00', $current);
$d2 = strtotime('-5 minutes', $current);
var_dump($d1 > $d2); // false
var_dump(date('Y-m-d H:i:s', $d1)); // 2020-09-27 03:05:00
var_dump(date('Y-m-d H:i:s', $d2)); // 2020-09-27 03:59:00
This person looks to be having the same issue as you and may appear to be a bug.
DateTime::modify and DST switch
The solution is to convert the dates to UTC then compare:
// Convert to UTC and compare
$d1 = new \DateTime('2020-09-27 02:05:00', new \DateTimeZone('Pacific/Auckland'));
$d2 = new \DateTime('2020-09-27 02:04:00', new \DateTimeZone('Pacific/Auckland'));
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-5 minutes');
$d2->setTimezone(new \DateTimeZone('Pacific/Auckland'));
var_dump($d1 > $d2); // true
var_dump($d1->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T03:05:00.000+13:00
var_dump($d2->format(\DateTimeInterface::RFC3339_EXTENDED)); // 2020-09-27T01:59:00.000+12:00
I've updated your functions:
function time_is_older_than($datetime, $time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 < $d2;
}
function time_is_younger_than($datetime, $time_string)
{
$d1 = new \DateTime($datetime);
$d1->setTimezone(new \DateTimeZone('UTC'));
$d2 = new \DateTime();
$d2->setTimezone(new \DateTimeZone('UTC'));
$d2->modify('-' . $time_string);
return $d1 > $d2;
}
Could you consider a solution:
In the timestamp string(like Thu, 21 Dec 2000 16:01:07 +0200), add a timezone tag which specify timezone without difference of daylight saving time.

Add 5 minutes difference

I have a problem.
I have a certain date/time (A), which is put in a variable. Lets say its May 06 2014 14:26.
I want to compare this date/time with file's modification date/time (B), and if it is the same, I put the file's modification date/time (B) in variable too.
The thing is, I cant get exactly the same date on file (B). So, I want that it would add 5 minutes difference. For example, if file (B) has modification date May 06 2014 14:28, it will be put in a variable. Or if it has modification date May 06 2014 14:22, it will be put in a variable too.
If it helps, I am using date("F d Y H:i",$file['filetime']) command to get the modification date of the file.
Any possibility to do this? Thanks in advance.
If something is unclear, just tell me. I'm new here, so might be hard to explain things correctly.
Maybe, it helps:
$datetimeA = strtotime($file1['filetime']);
$datetimeB = strtotime($file2['filetime']);
$interval = abs($datetimeA - $datetimeB);
$minutes = round($interval / 60);
if ($minutes > 5) {
//do some magic here
}
If $file['filetime'] is a timestamp already, then You can use it without calling strtotime().
With the DateTime class, it is done in a few lines :
$datetime1 = new DateTime('2009-10-13 10:00:00');
$datetime2 = new DateTime('2009-10-13 10:20:00');
$interval = $datetime1->diff($datetime2);
$yourIntervalle = $interval->format('%i minutes'));
i'd either directly use unix-timestamps or convert A and B to Unix Timestamps (e.g. using strtotime) and compare them based on your requirements.
if you have access to the file directly you could even use filemtime to directly get the last modified time as an unix timestamp.
Guess this is what you're looking for, if your problem is just to add 5 minutes:
$dateB = new DateTime('2014-05-06 14:26:00');
$interval = new DateInterval('PT5M');
$dateB->add($interval);
print_r($dateB);
PHPSandbox: http://sandbox.onlinephpfunctions.com/code/9f9a2ee40f09f953c796c9c2dd7e15ad62b45772
Also, look at DateInterval to understand a little more:
http://www.php.net/manual/en/dateinterval.construct.php
you can do like. if you want to minus 5 minutes from the date
$given_date = 'May 06 2014 14:28';
$date = new DateTime($given_date);
//subtract 5 minutes from the date
$new_date = $date->sub(new DateInterval('PT' . '5' . 'M'));
echo $new_date->format('F d Y H:i');
if you want to add 5 minutes then change
//add 5 minutes to the date
$new_date = $date->add(new DateInterval('PT' . '5' . 'M'));
First of all, i think you need to compare the two date/time by the method strtotime. With that you can compare the two date.
Then, you just need to make one or two insert in your database if i understand correctly with a If/Else method.
Hope it helps!

how to convert timestamp to date in codeigniter

I want to convert 1373892900000 to Monday 2013/07/15 8:55 AM in Codeigniter.
However, I keep receiving a totally different result by converting the timestamp using the function i have written, please note:I need to change the dates according to different timezones, that is why I want to write it this way:
public function time_convert($timestamp){
$this->load->helper('date');
date_default_timezone_set('UTC');
$daylight_saving = TRUE;
$timezone = "UM4"; //toronto or new york timezone
$time = gmt_to_local($timestamp, $timezone, $daylight_saving);
$final_time = standard_date('DATE_RFC822', $time);
return $final_time;
}
Result from the above function is: Sat, 08 Dec 06 01:40:00 +0000
And if I don't put date_default_timezone_set('UTC'); in the above function, I get this date instead Sat, 08 Dec 06 02:40:00 +0100. My codeigniter seems to default the timezone to Europe/Berlin.
Can anyone please help me correct any of the mistakes I might have made?
Why not just use PHP's date function?
public function time_convert($timestamp){
return date('l Y/m/d H:i', $timestamp);
}
For different timezones use a DateTime object:
public function time_convert($timestamp, $timezone = 'UTC'){
$datetime = new DateTime($timestamp, new DateTimeZone($timezone));
return $datetime->format('l Y/m/d H:i');
}
Think that should work. Note: I tihnk you need at least PHP version 5.20 for the TimeZone class.
<?php
$time_str=1373892900000;
echo gmdate("fill with your format", $time_str);
?>
your format = format your time in php, reading this page for details.
http://php.net/manual/en/function.date.php
http://php.net/manual/en/function.gmdate.php
Appears as though an invocation of standard_date with the DATE_ATOM format may sort you:
echo unix_to_human(time(), true, 'us'); # returns 2013-07-12 08:01:02 AM, for example
There are a whole host of other options for the format, enumerated on the linked page.
This how to covert timestamp to date very simple:
echo date('m/d/Y', 1299446702);
to convert timestamp to human readable format try this:
function unix_timestamp_to_human ($timestamp = "", $format = 'D d M Y - H:i:s')
{
if (empty($timestamp) || ! is_numeric($timestamp)) $timestamp = time();
return ($timestamp) ? date($format, $timestamp) : date($format, $timestamp);
}
$unix_time = "1251208071";
echo unix_timestamp_to_human($unix_time); //Return: Tue 25 Aug 2009 - 14:47:51
if you want to convert it to a format like this: 2008-07-17T09:24:17Z than use this method
<?php
$timestamp=1333699439;
echo gmdate("Y-m-d\TH:i:s\Z", $timestamp);
?>
for details about date:
http://php.net/manual/en/function.date.php
Your timestamp is coming from javascript on the client, I would guess, because it appears to be in milliseconds. php timestamps are in seconds. So to get the answer you want, first divide by 1000.
Showing the full year would have made the issue more obvious, as you would have seen the year as 45,506.

UTC time to time based by timezone offset

I am saving all the times in MySQL in UTC(0), so I could change them later while I'm showing the times for the users with different time zones, for saving into db, I use:
function get_utc(){
date_default_timezone_set('UTC');
return date("Y-m-d H:i:s");
}
$now = get_utc();
And now I want to convert those times into different timezones based by timezones offset, I am using this function:
function utc_and_timezone($utc_time, $offset) {
return date("Y-m-d H:i:s", strtotime($offset, strtotime($utc_time)));
}
So for example, if the UTC time is: 2013-01-30 21:06:29
Applying the +5 timezone on that time is easy to find:
$new_time = utc_and_timezone("2013-01-30 21:06:29", "+5 hours"); // Works Fine
It works JUST fine with offsets like 5,6 or other integers, BUT with some other like +3.5, +2.5 this is not working:
$new_time = utc_and_timezone("2013-01-30 21:06:29", "+5.5 hours"); // NOT WORKING
Anyone knows why?!
Any better solutions for making UTC times in different timezones...?
Thanks
SHORT QUESTION:
I want to show a UTC time like 2013-01-30 21:06:29 in +3.5 timezone, how is that possible?
On the PHP side, you can try:
$utc_time = '2013-01-30 21:06:29';
$offset = '3.5';
echo date("Y-m-d H:i:s", strtotime($utc_time) + (3600 * $offset) );
//Returns 2013-01-31 00:36:29
$utc_time = '2013-01-30 21:06:29';
$offset = '-5.5';
echo date("Y-m-d H:i:s", strtotime($utc_time) + (3600 * $offset) );
//Returns 2013-01-30 15:36:29
On the MySQL side, you can just use CONVERT_TZ:
SELECT CONVERT_TZ('2013-01-30 21:06:29','+00:00','+03:30');
//Returns January, 31 2013 00:56:29+0000
SELECT CONVERT_TZ('2013-01-30 21:06:29','+00:00','-05:50');
//Returns January, 30 2013 15:16:29+0000

check time for time difference in 24hr

In php i get the variable $date_time in this format -- 11-01-2010 20:48:25 . This time is GMT time. I have a 2 hour flexibility and if it exceeds 2 hours then i have to reject it. I am set in EST, but i want to do the check based on GMT only so that there is no errors in the time difference. How can i set to GMT in my php code and how do i check for the 2 hours flexible time difference? like for this example it is acceptable for any time between 11-01-2010 18:48:25 and 11-01-2010 22:48:25. Also will it be an issue if $date_time is 11-01-2010 23:48:23?
Clarification
I am doing a $date_time=$_GET['date_time'];. Then i need to check if this new $date_time if within 2 hours range of the current GMT time. if it is in the range, then i will proceed to execute that code, else i will show an error or do something else. I wanted to know how i am going to check this 2 hours range for this $date_time variable.
Here is a way how to convert your time format into a UNIX timestamp:
$date = strptime($date_time, "%m-%d-%Y %T");
$ut = mktime($date['tm_hour'], $date['tm_min'], $date['tm_sec'], 1 + $date['tm_mon'], $date['tm_mday'], 1900 + $date['tm_year']);
$now = time();
if($ut >= $now && $ut <= ($now + 7200)) { // 7200 = 2 * 60 * 60 seconds
// allowed
}
Reference: strptime, mktime, time.
Note: time() always returns the UNIX timestamp in UTC (regardless of time settings). So this assumes that the $date_time timestamp is a GMT time.
Working example (of course you have to provide a valid GMT time for $date_time).
Note 2: If the input time is not in GMT, you can set the timezone with date_default_timezone_set (affects mktime but not time).
Working example (change time and timezone accordingly)
If PHP >= 5.3 (you've got a seriously weird format BTW):
date_default_timezone_set('EST');
$inputtime = DateTime::createFromFormat('m-d-Y H:i:s','11-01-2010 20:48:25',new DateTimeZone("GMT"));
$diff = $inputtime->getTimestamp() - time();
if(abs($diff) > 7200){
//more then 2 hours difference.
}
If you run on PHP > 5.3, you can use DateTime for this :
$my_date = "11-01-2010 20:48:25";
$date = DateTime::createFromFormat('m-d-Y H:i:s', $my_date);
$date_lower = DateTime::createFromFormat('m-d-Y H:i:s', $my_date);
$date_upper = DateTime::createFromFormat('m-d-Y H:i:s', $my_date);
$date_lower->sub(new DateInterval('PT2H'));
$date_upper->add(new DateInterval('PT2H'));
var_dump($date >= $date_lower && $date <= $date_upper); // bool(true)
I find it more readable.
You can also use another timezone if necessary, check the third argument of createFromFormat.
I suggest you to never pass times and dates with format string. Just convert it later. You just pass the timestamp as a get variable and then you format it in the script.
It's the best solution and also the cleanest.
Then use the following code:
$flexibility = X seconds;
if ($date_time < time() - $flexibility or $date_time > time() + $flexibility)
{ /*Error*/ }

Categories