strtotime is different with timezone - php

Seems I don't quite understand much the function strtotime. My case is I would like to compare the current time (now) with a specific time on specific timezone
For example the specific time is "this Monday at 14:00:00" at the timezone "America/New_York":
$specificTime = strtotime("monday this week 14:00:00 America/New_York");
My current code is:
$now = strtotime("now America/New_York");
if ($now > $specificTime) {
//do something
}
But I have figured it out that $now above is 6 hours ahead with current time. The number 6 I guess from offset -05:00 of America/New_York, plus with 1 hour daylight saving.
it should remove timezone out of $now, it will work correctly:
$now = strtotime("now");
if ($now > $specificTime) {
//do something
}
Could someone give the explain why strtotime("now America/New_York") is 6 hours ahead with strtotime("now), why they are not equivalent? really confused.
P.S: I am on GMT+07:00.

Simple debugging:
<?php
$now = strtotime("now America/New_York");
echo date('r', $now);
// Thu, 28 Nov 2013 16:39:51 +0100
... shows that such command is doing this:
Calculate local time in my default time zone (10:39:51 +0100)
Return timestamp that corresponds to 10:39:51 in New York time (-0500)
Doing date manipulation with strings is terribly complicated. Just imagine you'd try to do math with string functions: strtofloat('one plus square root of half hundred')—there'd be plenty of room for mistakes. So my advise is to keep it simple and only use with simple expressions when there's some benefit, such as strtotime('+1 day').
If you need to work with different time zones, I suggest you use proper DateTime objects. If you choose to work with Unix timestamps, forget about time zones: Unix timestamps do not have time zone information at all.

You can use DateTime for this. I believe settings a timezone in strtotime is not valid.
$specificTime = new DateTime("monday this week 14:00:00", new DateTimeZone("America/New_York")));
$now = new DateTime("now", new DateTimeZone("America/New_York"));
You can then compare unix timestamp with this:
if ($now->getTimestamp() > $specificTime->getTimestamp()) {
// do something ...
}

There is time offset between each timezone.
strtotime() function will return the Unix timestamp according the timezone.
It will use the default time zone unless a time zone is specified in that parameter.
The default time zone it the return value of date_default_timezone_get();
Look the code below:
<?php
// UTC
echo date_default_timezone_get(), "\n";
// 2013-11-28 14:41:37
echo date('Y-m-d H:i:s', strtotime("now America/New_York")), "\n";
// 2013-11-28 09:41:37
echo date('Y-m-d H:i:s', strtotime("now")), "\n";

Related

Add variable string to datetime eg. 2 weeks

is it possible to add a variable string like '2 day, 2 weeks or even 4 hours' to a date time in PHP.
For example:
I have a date time like this: '2017-08-02 12:00'
now the user choose an interval like '4 hours or 2 weeks'
now the user choice should be added to the date time.
Is this possible?
I don't want the whole code, maybe just an advice how to do that.
thanks
Yes, use
$userDate = strtotime('2017-08-02 12:00:00');
echo date('Y-m-d H:i:s', strtotime('+4 hours', $userDate));
to get date after 4 hours
Example
Explanation
strtotime converts about any English textual datetime description into a Unix timestamp. Most commonly it's used with actual date string or with difference string. E.g. +5 months, 'next Monday' and so on. It will return Unix timestamp - integer that represents how much seconds there is after 1970-01-01 (1970-01-01 00:00:00 is 0, 1970-01-01 00:01:00 is 60 and so on).
So in strtotime('2017-08-02 12:00:00') we convert date to integer for later use.
strtotime('+4 hours', $userDate) - here we use our date as "now" parameter (by default it's time()) and requesting to return timestamp after 4 hours.
echo date('Y-m-d H:i:s', ...); - date accepts format and Unix timestamp to convert from integer back to human readable text.
May be you are looking for this:
http://php.net/manual/en/datetime.modify.php
$date = new DateTime('2006-12-12');
$date->modify('+1 day');
echo $date->format('Y-m-d');
For a datetime you can use the add method but you have to put in the correct code for the amount to add.
$my_date = new DateTime();
$addition = 4;
$my_new_date = $my_date->add(new DateInterval("P${addition}D"));
echo $my_new_date->format('Y-m-d H:i:s');
Where addition is your variable that you want to add.

PHP DateTime converting issue

I have an issue with converting DateTime from Moscow timezone to New York timezone. Here is my test script:
$year = 2015;
$month = 3;
$tzMoscow = new DateTimeZone('Europe/Moscow');
$tzNewYork = new DateTimeZone('America/New_York');
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzMoscow);
echo $startDate->format('Y-m-d H:i:s')."\n"; // 2015-03-01 16:16:05
$startDate = DateTime::createFromFormat('Y-n-d', "$year-$month-01", $tzNewYork);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 09:16:05
$startDate->setTimezone($tzMoscow);
echo $startDate->format('Y-m-d H:i:s') . "\n"; // 2015-03-01 17:16:05
Third output is incorrect, time should be 16:16:05. Am I doing something wrong or is this a bug in php?
I think I've got it. The problem is that you're not specifying a time of day, so createFromFormat is using "the current system time":
If format does not contain the character ! then portions of the generated time which are not specified in format will be set to the current system time.
Now what does it mean to use "the current system time" to create a time in the New York time zone, when that time zone has changed UTC offset between the specified date (March 1st) and the current date (March 14th)? It was UTC-5 on March 1st, and it's now UTC-4 due to daylight saving time.
I believe PHP is taking the current time of day in the specified time zone (9:16 at the time you ran that code) and then using that as the time of day on the specified date. So we end up with March 1st 2015, 09:16 New York time - or March 1st, 14:16 UTC, which is indeed March 1st 17:16 Moscow time.
That's not the same as the current time of day in Moscow at the time that you ran the code, which was 16:16.
Basically, you should try not to do this - or expect problems like this to happen. Think about what time of day you're really trying to represent, bearing in mind that within a particular time zone, offsets change over time. I can't really advise you on what your code should be, because we don't know what you're trying to achieve - but using the current time of day for a different date can definitely cause this problem.
I also believe this is an issue of DST, changing in New York time zone on 8th of March. I extended your date formats to Y-m-d H:i:s U I to include the unix timestamp and the DST value.
The output is now as following:
2015-03-01 19:07:17 1425222437 0
2015-03-01 11:07:17 1425226037 0
2015-03-01 20:07:17 1425226037 0
As you can see, the unix timestamp is already different between both created DateTime objects.
Now when I specify a concrete time as
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzMoscow);
as well as
$startDate = DateTime::createFromFormat('Y-n-d H:i', "$year-$month-01 00:00", $tzNewYork);
the output changes to:
2015-03-01 00:00:00 1425153600 0
2015-03-01 00:00:00 1425186000 0
2015-03-01 09:00:00 1425186000 0
On the other hand, if I change $month to 4 (where New York uses DST), I get the following output:
2015-04-01 19:08:35 1427900915 0
2015-04-01 11:08:35 1427900915 1
2015-04-01 19:08:35 1427900915 0
What do these results mean?
The conversion between New York and Moscow time zone works correct in all cases, as you can judge from the unix timestamp being identical. Also, "2015-03-01 00:00" are obviously different timestamps for Moscow and New York, because they depend on the concrete time zone.
So I think your code is correct and there is no bug in php. However, the "current" times in New York and Moscow differ due to the DST switch between 1st of March and today (14th of March).
So while Jon's answer already explained the theory (I don't want all the credit, he was first), maybe someone will still find some concrete examples useful.
You can use this function, for change between timezones
function changeTimezone($time, $currentTimezone, $timezoneRequired, $FormtsTime = 'Y-m-d h:i:s')
{
$dayLightFlag = false;
$dayLgtSecCurrent = $dayLgtSecReq = 0;
$system_timezone = date_default_timezone_get();
$local_timezone = $currentTimezone;
date_default_timezone_set($local_timezone);
$local = date($FormtsTime);
date_default_timezone_set("GMT");
$gmt = date($FormtsTime);
$require_timezone = $timezoneRequired;
date_default_timezone_set($require_timezone);
$required = date($FormtsTime);
date_default_timezone_set($system_timezone);
$diff1 = (strtotime($gmt) - strtotime($local));
$diff2 = (strtotime($required) - strtotime($gmt));
$date = new DateTime($time);
$date->modify("+$diff1 seconds");
$date->modify("+$diff2 seconds");
if ($dayLightFlag) {
$final_diff = $dayLgtSecCurrent + $dayLgtSecReq;
$date->modify("$final_diff seconds");
}
$timestamp = $date->format($FormtsTime);
return $timestamp;
}

PHP - Local vs UTC Time Comparison with Timezone Offset

Given a variable unix timestamp and a fixed timezone offset in seconds, how can you tell if local time is past 8am.
For example, take the following variables:
$timestamp = time();
$timezone_offset = -21600; //i think that's -8hrs for pacific time
if(date("H", $timestamp + $timezone_offset) >= 8){
// do something
}
Assuming you consider even a millisecond past 8:00:00 is "past 8am".
You set your timezone in PHP using date_default_timezone_set() and then use PHP's datetime functions like date or DateTime object to check the time according to the set timezone. PHP will do the right thing for you and adjust the time to the specified timezone.
$timestamp = 1354794201;
date_default_timezone_set("UTC"); // set time zone to UTC
if (date("H", $timestamp) >= 8) { // check to see if it's past 8am in UTC
echo "This time stamp is past 8 AM in " . date_default_timezone_get() . "\n";
}
date_default_timezone_set("America/New_York"); // change time zone
if (date("H", $timestamp) >= 8) { // Check to see if it's past 8am in EST
echo "This time stamp is past 8 AM in " . date_default_timezone_get() . "\n";
}
Output from this code
/* This time stamp is past 8 AM in UTC */
You can do the same thing with DateTime as well...
$timestamp = 1354794201;
$date = new DateTime("#{$timestamp}"); // create the DateTime object using a Unix timestamp
$date->setTimeZone(new DateTimeZone("UTC")); // set time zone to UTC
if ($date->format("H") >= 8) { // check to see if it's past 8am in UTC
echo "This time stamp is past 8 AM in {$date->getTimezone()->getName()}\n";
}
$date->setTimeZone(new DateTimeZone("America/New_York")); // change time zone
if ($date->format("H") >= 8) { // Check to see if it's past 8am in EST
echo "This time stamp is past 8 AM in {$date->getTimezone()->getName()}\n";
}
Output from the above code is also...
/* This time stamp is past 8 AM in UTC */
Unix time is time zone agnostic. That's the point of using Unix time as a transport layer. You never have to worry about time zones until it comes time to translate your time stamp from Unix time to a formatted date.

There is a simple way to get unix time range of a day if given a random timestamp from that day?

There is a simple way to get unix time range of a day if given a random timestamp from that day ?
I have a date like 1345547471 which is "Tue, 21 Aug 2012 11:11:11 GMT"
There is a php function that can receive a timestamp like this and return a 00:00 hours timestamp and a 23:59 hours timestamp of that day ?
Thank you.
Sure, DateTime can do that:
$time = 1345547471;
$date = new DateTime;
// $date->setTimezone( new DateTimeZone( "America/New_York")); // Can set TZ here if needed
$date->setTimestamp( $time);
Now, you can set the time to whatever you want:
$date->setTime( 0, 0, 0); // 0h 0m 0s
And grab the resulting UNIX Timestamp:
$timestamp = $date->getTimestamp();
Same thing for the next use-case:
$date->setTime( 23, 59, 0);
$timestamp = $date->getTimestamp();
It is important to note that DateTime will properly handle cases of daylight savings time and local time discontinuities.
You can use the mod (gives the remainder after a division) PHP function like this to get the first second of a Unix timestamp (ie, today 0:00:00)
$var=time()-(time()%86400);
Then with this unix timstamp, you can add 86399 to get the last second of the day.
Edit: This doesn't account for dalylight savings.
$ts = 1345547471;
$ts_00_00 = mktime(0,0,0, date("m", $ts), date("d",$ts), date("Y",$ts);
$ts_23_59 = mktime(23,59,59, date("m", $ts), date("d",$ts), date("Y",$ts);
Documentation:
http://php.net/manual/en/function.date.php
http://php.net/manual/en/function.mktime.php
If you are using PHP >= 5.3.0 Then you can use this...
Check out for this.
http://www.php.net/manual/en/datetime.createfromformat.php
This is similar to Fluffeh's answer, but accounts for daylight savings time. This is based on the server's time zone.
//Get time range for today
$start = strtotime(date("Y-m-d")." 00:00:00");
$end = strtotime(date("Y-m-d")." 23:59:59");
//Show our date in a human-readable format for troubleshooting
echo date(DATE_RFC1036,$start)."<br>".date(DATE_RFC1036,$end);
If you want to specify a custom timezone instead of the server timezine, you can add it to like so:
//Get time range for today
$start = strtotime(date("Y-m-d")." 00:00:00 -0500");
$end = strtotime(date("Y-m-d")." 23:59:59 -0500");
//Show our date in a human-readable format for troubleshooting
echo date(DATE_RFC1036,$start)."<br>".date(DATE_RFC1036,$end);
Link to working Sample

Generate start and ending datetimes in UTC based on a PST date

I am taking in a parameter that is a date in PST timezone which will be in the format of "YYYY-MM-DD" (e.g. "2011-08-15"). This parameter is optional. I have 2 questions that I've been struggling with.
I need to calculate the start and end datetime in UTC for this date.
So if the inputted date is 2011-08-15, I want to get the start and end datetimes:
2011-08-15 07:00:00
2011-08-15 06:59:59
(These are essentially the beginning and end of day)
Second, is to handle the case when the date is not passed in. I want to default to the current PST date them and start from there. So if the current datetime is 2011-08-01 10:00:00, I want to get the same start and end datetimes similar to the first scenario except it's based on the inputted date.
2011-08-01 07:00:00
2011-08-01 06:59:59
I've been pulling my hair out dealing with date and datetime conversions. I'm sure I'm missing something super straightforward.
Parse the date and assume PST timezone:
$date = new DateTime("2011-08-15", new DateTimeZone("PST"));
Change the timezone to UTC: (this does the all conversions for you)
$date->setTimeZone(new DateTimeZone("UTC"));
Calculate start and end. Start is our $date and end is $date + 1 day
$start = $date;
$end = clone $date;
$end->modify("+1 day"); // now $end is $start + 1 day
Print start/end:
printf("start: %s, end: %s\n", $start->format('Y-m-d H:i:s'), $end->format('Y-m-d Hi:s'));
// this prints start: 2011-08-15 07:00:00, end: 2011-08-16 07:00:00
For the last part of your questions, you can easily compare two dates:
if ($date > new DateTime()) { // if $date is after now
// do something
}
So you could do something like that:
if ($date > new DateTime()) {
$date->setTimeZone(new DateTimeZone("UTC"));
}
If you don't much like the OO syntax you could also use the function aliases:
$date = date_create(...);
date_format($date, ...);
date_modify($date, ...);
// ...
Use setTimezone function
Working example (I'm not in PST timezone, so I have to set it explicitly)
$date_input = "20011-09-15";
//$date_input = null; //That will emulate no-input case
date_default_timezone_set("America/Los_Angeles"); //if you are in PST, you don't need this line
$date_start = new DateTime($date_input);
$date_end = new DateTime($date_input);
$date_end->modify("+1 day");
/*$date_start->setTimezone(new DateTimeZone("America/Los_Angeles"));
$date_end->setTimezone(new DateTimeZone("America/Los_Angeles"));*/
//end of date is equal to start of the next day.
//But, if you need something like 2011-08-11 23:59:59 add $date_end->modify('-1 second')
$date_start->setTime(0,0,0);
$date_end->setTime(0,0,0);
echo "Date Start PST:".$date_start->format("Y-m-d H:i:s")."<br/>";
echo "Date End PST:".$date_end->format("Y-m-d H:i:s")."<br/>";
//UTC is equal to London time. Almost :)
$date_start->setTimezone(new DateTimeZone ('Europe/London'));
$date_end->setTimezone(new DateTimeZone ('Europe/London'));
echo "Date Start UTC:".$date_start->format("Y-m-d H:i:s")."<br/>";
echo "Date End UTC:".$date_end->format("Y-m-d H:i:s")."<br/>";

Categories