In my application I'm trying to calculate the time left until midnight GMT (UK time). At the moment I'm doing this:
$now = new DateTime();
$timeToMidnight = $now->setTimezone(new DateTimeZone('Europe/London'))->diff(new DateTime('tomorrow'))->format('%h hours, %i minutes and %s seconds');
The code is working, however it seems to be one hour behind (using GMT -1). At the moment the time is 11:49PM and the output is this:
1 hours, 10 minutes and 36 seconds
I've double checked my php.ini and I also have that timezone set as GMT:
date.timezone = Europe/London
This is also confirmed by checking phpinfo().
What gives? Why isn't my application using the correct timezone?
I tested this on Linux PHP 5.5.5, with Europe/London set as the timezone in php.ini. I actually set the clock back four hours to do this, too. The minimal code I used to reproduce was:
$d = new DateTime('tomorrow');
echo $d->format('c e');
The (correct) output was:
2013-10-27T00:00:00+01:00 Europe/London
I am going to look for a bug in PHP or a bug in the timezone data. To find out which, we'll see what some other program makes of midnight in London tonight. Epoch Converter tells me this should have a Unix timestamp of 1382828400. To double check that timestamp, I ran in PHP:
$d = new DateTime('27-10-2013');
echo $d->format('U');
It also returned 1382828400. So, let's see what it's supposed to show...
TZ=Europe/London date --date="#1382828400" +%c
The output was:
Sun 27 Oct 2013 12:00:00 AM BST
Correct! So tzdata is fine. So let's look at PHP.
I ran your sample code, along with the date command, and got the following output:
1 hours, 29 minutes and 53 seconds
Sat Oct 26 21:30:07 UTC 2013
Sat Oct 26 22:30:07 BST 2013
This is, of course, correct.
I think at this point we have ruled out bugs in both tzdata and PHP, and need to look at configuration issues and programmer expectations.
First, as I noted previously, Europe/London is not UTC, which has no concept of summer time and thus does not change twice per year. Since it doesn't cause such problems, it's a best practice for servers to run on UTC, regardless of what time zone their users are in, and a best practice for programs to use UTC internally and then convert to/from local time zones for display and user input only.
My best guess is that your server's running PHP is actually set to use UTC and not Europe/London as its default time zone. This is the only configuration in which I could reproduce your issue. The results of that test were:
date.timezone = UTC
2 hours, 24 minutes and 36 seconds
Sat Oct 26 21:35:24 UTC 2013
Sat Oct 26 22:35:24 BST 2013
Going forward, you should work in UTC (and with Unix timestamps) wherever practical, and convert to local time as early in processing user input, and as late in displaying it, as you can. An edge case like this one, where summer time is about to end, may be an exception, but you have to be extra careful to ensure that each new DateTime object you construct has the correct time zone set when you construct it, and also be aware that they will have issues like this.
See also the huge and informative Daylight saving time and time zone best practices
Finally, to "fix" your code, let's do this:
$tz = new DateTimeZone('Europe/London');
$now = new DateTime('now', $tz);
$midnight = new DateTime('tomorrow', $tz);
$timeToMidnight = $now->diff($midnight);
echo $timeToMidnight->format('%h hours, %i minutes and %s seconds');
Related
I just want to check if time() returns a UTC/GMT timestamp or do I need to use date_default_timezone_set()?
time returns a UNIX timestamp, which is timezone independent. Since a UNIX timestamp denotes the seconds since 1970 UTC you could say it's UTC, but it really has no timezone.
To be really clear, a UNIX timestamp is the same value all over the world at any given time. At the time of writing it's 1296096875 in Tokyo, London and New York. To convert this into a "human readable" time, you need to specify which timezone you want to display it in. 1296096875 in Tokyo is 2011-01-27 11:54:35, in London it's 2011-01-27 02:54:35 and in New York it's 2011-01-26 21:54:35.
In effect you're usually dealing with (a mix of) these concepts when handling times:
absolute points in time, which I like to refer to as points in human history
local time, which I like to refer to as wall clock time
complete timestamps in any format which express an absolute point in human history
incomplete local wall clock time
Visualise time like this:
-------+-------------------+-------+--------+----------------+------>
| | | | |
Dinosaurs died Jesus born Y2K Mars colonised ???
(not to scale)
An absolute point on this line can be expressed as:
1296096875
Jan. 27 2011 02:54:35 Europe/London
Both formats express the same absolute point in time in different notations. The former is a simple counter which started roughly here:
start of UNIX epoch
|
-------+-------------------+------++--------+----------------+------>
| | | | |
Dinosaurs died Jesus born Y2K Mars colonised ???
The latter is a much more complicated but equally valid and expressive counter which started roughly here:
start of Gregorian calendar
|
-------+-------------------+-------+--------+----------------+------>
| | | | |
Dinosaurs died Jesus born Y2K Mars colonised ???
UNIX timestamps are simple. They're a counter which started at one specific point in time and which keeps increasing by 1 every second (for the official definition of what a second is). Imagine someone in London started a stopwatch at midnight Jan 1st 1970, which is still running. That's more or less what a UNIX timestamp is. Everybody uses the same value of that one stopwatch.
Human readable wall clock time is more complicated, and it's even more complicated by the fact that it's abbreviated and parts of it omitted in daily use. 02:54:35 means almost nothing on the timeline pictured above. Jan. 27 2011 02:54:35 is already a lot more specific, but could still mean a variety of different points on this line. "When the clock struck 02:54:35 on Jan. 27 2011 in London, Europe" is now finally an unambiguous absolute point on this line, because there's only one point in time at which this was true.
So, timezones are a "modifier" of "wall clock times" which are necessary to express a unique, absolute point in time using a calendar and hour/minute/second notation. Without a timezone a timestamp in such a format is ambiguous, because the clock struck 02:54:35 on Jan. 27 2011 in every country around the globe at different times.
A UNIX timestamp inherently does not have this problem.
To convert from a UNIX timestamp to a human readable wall clock time, you need to specify which timezone you'd like the time displayed in. To convert from wall clock time to a UNIX timestamp, you need to know which timezone that wall clock time is supposed to be in. You either have to include the timezone every single time with each such conversion, or you set the default timezone to be used with date_default_timezone_set.
Since PHP 5.1.0 (when the date/time functions were rewritten), every
call to a date/time function will generate a E_NOTICE if the timezone
isn't valid, and/or a E_WARNING message if using the system settings
or the TZ environment variable.
So in order to get a UTC timestamp you should check what the current timezone is and work off of that or just use:
$utc_str = gmdate("M d Y H:i:s", time());
$utc = strtotime($utc_str);
http://us3.php.net/time
"Returns the current time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)."
So I believe the answer to your question is yes.
From the documentation
Returns the current time measured in the number of seconds since the Unix Epoch (January 1 1970 00:00:00 GMT).
One of the comments claimed: "both time() and strtotime(gmdate("M d Y H:i:s", time())) return the same result"
Since I wasn't sure about that, I ran a test:
$now = strtotime(gmdate("Y-m-d H:i:s", time()));
$now2 = time();
echo ' now='.$now.' now2='.$now2.' diff='.($now - $now2);
Output was:
now=1536824036 now2=1536806036 diff=18000
Diff is 18000 seconds = 5 hours = the timezone offset for the server running the test.
The diffrence between 2 dates - current time and mysql time. This can be backdoored when user change his PC time and the code is Bypassing him from the diffrence check.
I've tried to use
mktime()
but its not working when my mysql date is 1451094007 (Sat, 26 Dec 2015 01:40:07 GMT) and real world time is for example 1451108407 (Sat, 26 Dec 2015 05:40:07 GMT) 4 hours later, and minimum difference is 10 hours user can still add some hours on him own PC and bypass time.
How can I get any world time which can't be manipulated?
You get all timezones using in the world store in array then run in loop
foreach($timezonearray as $timezone){
$time = new DateTime($timezone);
echo $time->format('Y-m-d H:i:s');
}
it will print result like this
http://www.timehubzone.com/worldclock
single way
$time = new DateTime('Africa/Abidjan');
echo $time->format('Y-m-d H:i:s');
you can get all time zones here
timezones list
You can use other services such as http://worldclockapi.com/
(see http://worldclockapi.com/api/json/utc/now)
Fetch the result and feed them to variable.
Basically, your application should use the server time where it's hosted (configured with server clock) and time() should have respected the server clock
I have the next problem. I have several PHP systems running in different Windows machine. Those systems use intensivelly the current time.
Right now, i configured php.ini and assigned it to a specific timezone. Also Windows is configure to the same timezone and everything works as expected.
However, in my country, the State decided to change the daylight saving time. So, sometimes, the admin changes the windows timezone and left unchanged the php timezone, creating a discordance in the system. Other times, is windows who changes automatically the timezone.
Is there are any way, from PHP, to obtain the current system time that ignores the timezone?.
update:
function time_zone_fix($timeGiven = "H:i:s")
{
$shell = new COM("WScript.Shell") or die("Requires Windows Scripting Host");
$time_bias = -($shell->RegRead("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\ActiveTimeBias")) / 60;
$timestamp_bias = 60 * 60 * $time_bias;
return gmdate($timeGiven, strtotime($timestamp_bias . " seconds"));
}
gives the current date and time no matter what timezone/dsl is specified.
However, creating a new COM inteface is anything but efficient.
gmdate('Y-m-d H:i:s');
changing the format to whatever you need. It returns the "timezone-less date-and-time". The gm stands for Greenwich Mean, as in GMT (Greenwich Mean Time). GMT has been superseded by UTC (Universal Time, Coordinated), so the function should really be called utcdate()...
But the most portable representation of time is the Unix timestamp, i.e., the number of seconds elapsed since 1970-01-01 00:00:00 UTC, ignoring leap seconds:
time();
The value of time() is also the default value for the second parameter of gmdate().
BTW, a leap second is scheduled for 2012-06-30 23:59:60
Note: In case you are asking for a way to get the time at a certain timezone but without the daylight saving time correction, you can do this:
gmdate('Y-m-d H:i:s', time() + 3600 * $h);
where $h is the offset in hours from UTC (a negative number in America), or, in case the offset is not a full number of hours:
gmdate('Y-m-d H:i:s', time() + 60 * $m);
where $m is the offset in minutes from UTC (e.g., 330 for IST, India Standard Time). A Unix timestamp with an added timezone offset doesn't make any sense by itself, though!
Last but not least, don't forget to synchronize your systems by means of NTP, the Network Time Protocol.
PHP Manual List of Supported Timezones:
... Here you'll find the complete list of timezones supported by PHP, which are meant to be used with e.g. date_default_timezone_set(). ...
And then this one: UTC (from this sub-page)
PHP in Windows, how to obtain the current system time that ignores the timezone?
I have the next problem. I have several PHP systems running in different Windows machine. Those systems use intensivelly the current time.
OK. So I have been trying to implement a timer. Now a very weird thing is happening and I can't understand why ?.
Basically I am trying to find the difference between the last access and the current time. I am storing the time of last access in the database. This value is according to the server time. But when I try the time() function of php it shows me values which are 5-6 hours behind the time that I have in the database.
For example: here is my code :
$t1= strtotime($played_row->timer); // Time from the database with CURRENT_TIMESTAMP
$t2= strtotime("now"); // Get the current time
It shows Year: 2012 Month: 01 Day: 21 - 05:28 pm for t2
and Year: 2012 Month: 01 Day: 21 - 10:28 pm for my timestamp values.
Can anyone tell my why is that ?
P.S: I am running the code on my computer itself.
At a guess I would say that your database and PHP are using two different timezone offsets.
Most likely this is a timezone issue: if you are in the Eastern timezone, you are 5 hours away from UTC right now. If one sytem is returning local time and another is returning UTC this is what you will see.
Try using date_default_timezone_set() to set the timezone in PHP that is used in your database.
date_default_timezone_set — Sets the default timezone used by all
date/time functions in a script
Alse see date_default_timezone_get() how to get ini-set timezone.
OK,
I have a problem. I'm setting up a site that will end up holding large amounts of client data records. Because the clients can export and import their data, I have to be able to maintain session based timezones with in the site and server.
Right now my server is set to GMT. When I run the date command on the shell I see, which is correct at time of posting.
Fri Mar 18 20:04:32 GMT 2011
Then when i do hwclock --show is gives me, again this is was correct.
Fri 18 Mar 2011 08:06:22 PM GMT
Now when i tell php to change it's timezone to GMT-4 (since that is my timezone factoring in DST)
date_default_timezone_set('Etc/GMT-4');
echo date("m/d/Y g:i:s A T");
I get 03/19/2011 00:11:35 AM GMT-5 Is is totally wrong in stead of taking 5 hours away it added 5 hours.
So then I did this:
date_default_timezone_set('Etc/GMT+4');
echo date("m/d/Y g:i:s A T");
I got 03/18/2011 4:14:56 PM GMT+4. Which is the correct time. MySQL does the same thing. It seems like both are wanting to invert the time adjustments. Am i missing something on the settings?
No I think you misunderstand the notation/syntax.
The idea is that you set + if the timezone you want to get to is west of prime meridian, and you set - it it is east of it. So it doesn't actually have anything to do with the number of hours you add or take away, rather, to go back to the example, GMT+4:
4 hours in countries that are west of Greenwich
Which is basically the eastern edge of the USA, who are a few hours behind us in England... thinking about it this way should make sense.