Displaying timezones without using UTC - php

I've been reading up on how to do this all morning, and the general consensus is this: store your timestamps in UTC and calculate the offset from there.
However, like most people, I am maintaining an existing codebase and I can't change the way we store our dates. At least, not in the allotted time frame.
So my question is, can I safely do something like this?
// this is my time zone
$timestamp = strtotime($timestampFromDatabase);
date_default_timezone_set('America/New York');
$tz = date_default_timezone_get();
// this is theoretically their timezone, which will eventually
// be taken from a session variable
date_default_timezone_set('Europe/Paris');
$offset = time() - $timestamp;
$timestamp -= $offset;
// now that I have the offset, display dates like this
date('r', $timestamp);
Some people have advised against doing date arithmetic, but is what I'm doing here wrong? Is there a better way? Are there pitfalls I need to watch out for? I'm particularly interested in what kind of bugs this method could produce, and if any, who will they affect?
My boss is the kind of guy that doesn't care if the bug only affects 1% of the user base.
Edit: Can I make this any clearer? I don't seem to have too many takers on this. Anyone? Even a vague suggestion or a link would be immensely helpful.

The short answer is that timezones are tricky to work with and no-one wants to tackle the difficult questions!
The longer, answer is this:
Firstly, you need to create a representation of your date, in their current timezones. The following are equivalent:
date_default_timezone_set('America/New York');
$date = new DateTime(null);
OR
$date = new DateTime(null, new DateTimeZone('America/New York'));
This gives you a date with zone set to America/New York. We can easily convert it to the user timezone, in this case Europe/Paris with the next line:
$date->setTimezone(new DateTimeZone('Europe/London'));
You can use the following line to get the date/time represented at any point.
echo $date->format('d/m/Y H:i:s');
I strongly recommend this over arithmetic, as the built in PHP functions have knowledge of daylight saving times and lots of complicated things that you won't get right.
My test script in full:
date_default_timezone_set('America/Belize');
$date = new DateTime(null);
echo $date->format('d/m/Y H:i:s') . '<br>';
$date->setTimezone(new DateTimeZone('Europe/London'));
echo $date->format('d/m/Y H:i:s') . '<br>';

Related

Setting PHP DateTime doesn't appear to be observing TimeZones

I'm fairly new to PHP so forgive me if this is a stupid mistake that I haven't spotted
I've run into a problem where in our current system where we currently used strtotime and it was returning our date an hour ahead than it actually was set. E.g 1:15pm became 2:15pm when I set the timezone to be European rather than GMT.
I read that strotime had this problem but I can't get it to observe a different timezone if I try and set it.
So I tried working with PHPs DateTime instead.
The user enters the time and they select it as 1:15PM however we want to store it as 13:15. So I did this:
$t = DateTime::createFromFormat('h:i A', $venue['startTime']);
$t_24 = $t->format('H:i:s');
Then I try and create my Date object
$d = DateTime::createFromFormat('d-m-Y H:i:s', $venue['startDay'] . ' ' . $t_24);
$d->setTimezone(new DateTimeZone('America/New_York'));
echo ' ' . $d->getTimestamp();
Trying to set the timezone after the object is set because apparently it doesn't work if you add the timezone as the third argument in createFromFormat
My computers time is currently observing European time currently GMT+1 because we're observing daylight savings time in the UK, I select the time set on the through our system as 1:15pm and because I've set the timezone I expect the timestamp outputted equivalent to 7:15am as it's six hours behind European time, however when I convert the timestamp 1500639300 it's still equal to 2:15 PM. Probably done something stupid but can't quite figure out what? Any help would be appreciated :)
Timestamps have no time zone - they are always in UTC time. If you want to save timezone related data use another format! For example save in H:i:s, as you need it.
you can use gmdate() Function for this
<?php $current_time = gmdate('Y-m-d H:i:s'); ?>
http://php.net/manual/en/function.gmdate.php

PHP Daylight Savings Time Issue

I have the following function that is used to get the correct time and is used for my website.
Unfortunately, It doesn't check for daylight savings time and is causing a time error. I was wondering if anyone would have a possible solution or help me out with my issue?
I am very new to PHP coding and am still getting my footing with it. It would be really helpful if someone would be able to help me with a way to have it automatically make the switch for in the future.
Here is the function:
function getDSTDifference() {
$timezone = date_default_timezone_get();
$newTZ = new DateTimeZone($timezone);
$trans = $newTZ->getTransitions();
$offset = $trans[0]['offset'] /60 /60;
return $offeset;
}
---EDIT---
To better clarify what I am trying to say:
I have a website that monitors call times. These call times become off by an hour during the switch between DST and Regular Time (and vice versa). For example this past weekend caused times to show up like this: -57:01:23. Instead of have the function the way that it is - where I would have to manually go in and uncomment/comment out the two lines of code every time DST and Regular Time switch, is there a possible solution to making the function be able to do this automatically? Kinda like a more permanent solution. To me it just seems like redundant coding to have to constantly revisit that function to make what seems like a simple change over and over again. Again, I have not done a lot of work with PHP code before, therefore I am not familiar with built in functions that can be used or if I would have to create this on my own. If anybody would have some information/help to go about this, it would be much appreciated.
function getDSTDifference() {
$timezone = date_default_timezone_get();
$NewTZ = new DateTimeZone($timezone);
$transition = $NewTZ->getTransitions();
$offset = $transition[0]['offset'] /60 /60;
//The following two lines need to be commented out when it is
//daylight savings time
//They need to be uncommented when Daylight Savings Time ends
$dst = $transition[0]['isdst'];
$offset = $offset - $dst;
return $offset;
}
Hopefully that makes more sense!
Thanks in advance for the help!
One possibility to calculate the difference between two given hours is to use DateTime::diff(). At the time of writing this answer there was a PHP bug and you had to convert to UTC before:
<?php
$zone = new DateTimeZone('Europe/Madrid');
$start = new DateTime('2013-03-31 1:59:00 ', $zone);
$end = new DateTime('2013-03-31 3:00:00', $zone);
// Workaround for bug #63953
// No longer required since PHP/5.6.0, PHP/5.5.8 or PHP/5.4.24
$start->setTimeZone(new DateTimeZone('UTC'));
$end->setTimeZone(new DateTimeZone('UTC'));
$difference = $start->diff($end);
echo $difference->format('%H:%I:%S');
... prints 00:01:00 because that's when DST started in Western Europe.
You can also use Unix timestamps, which represent a fixed moment in time thus do not depend on time zones:
<?php
$zone = new DateTimeZone('Europe/Madrid');
$start = new DateTime('2013-03-31 1:59:00 ', $zone);
$end = new DateTime('2013-03-31 3:00:00', $zone);
$difference = $end->format('U') - $start->format('U');
echo "$difference seconds";
... prints 60 seconds.
Edit #1: What do you mean? My snippet contains sample data so you can test it—in real code you'll use your real data. You can (and should) set the correct time zone as default so you don't need to specify it every time. But even if you don't, the server's time zone will never change—even if you decide to physically move the computer to another state or country several times a year you can still opt for a fixed time zone of your choice (your app's time zone can be different from your server's).
If you really want a solution that requires you to change the code manually twice a year (for whatever the reason, maybe to charge maintenance fees), you'd better skip date/time functions and use strings; otherwise you'll risk PHP doing the calculations for you.
Edit #2:
$start and $end represent your data. I chose sample data one minute before DST just to illustrate that the diff code works fine. It's the same as when you see <?php echo "Hello, World!"; ?> in a PHP tutorial: Hello, World! is sample data to illustrate how echo works but you don't have to use Hello, World! when you write your app.
To convert from GMT to EST with PHP you create a date that belongs to GMT:
$date = new DateTime('14:30', new DateTimeZone('GMT'));
echo 'GMT: ' . $date->format('r') . PHP_EOL;
// GMT: Thu, 07 Nov 2013 14:30:00 +0000
... and then switch to EST:
$date->setTimeZone(new DateTimeZone('EST'));
echo 'EST: ' . $date->format('r') . PHP_EOL;
// EST: Thu, 07 Nov 2013 09:30:00 -0500
However, if your original dates are in GMT, converting them to EST before substracting them does not provide any benefit.

Format Unix Timestamp with Timezone?

Lets say I've got my Unix Timestamp of 1373623247. Now I understand that the timestamps are just seconds since X. The issue I have is the formatting of it.
The server I use is hosted in Germany, however I am in the UK so the output is 12-07-13 12:01:01, when actually its only 11:01:01 here.
The code I am using is as below:
$date = 1373623247;
echo date("j-m-y h:i:s",$date);
What I did was use date_create and timezone as follows:
$date1 = date("j-m-y h:i:s",$date);
$dateobj = date_create("$date1", timezone_open('Europe/London'));
echo date_format($dateobj,"j-m-y h:i:s") . "\n";
The issue I now have is that it's actually adjusted the date to tomorrow, and hasn't altered the time!
You do not need to involve date at all:
$date = 1373623247;
$dateobj = date_create_from_format("U", $date);
date_timezone_set($dateobj, timezone_open('Europe/London'));
echo date_format($dateobj,"j-m-y h:i:s") . "\n";
This code converts the timestamp directly to a DateTime instance using the U format specifier. It's both shorter and cleaner to not work with date, as you don't need to worry about the server's default timezone at all.
Pro tip: date and strtotime get much coverage, and in certain cases are very convenient, but DateTime can do everything on its own and IMHO results in code that is much more maintainable.

Remove time part of a timestamp

How can I remove time part of a timestamp?
So for example turn 1310571061 to 1310565600 which is the plain date timestamp.
strtotime(date("Y-m-d", 1310571061));
That should do it for you.
In case you wanted a mathematical solution:
$time=1310571061;
echo floor($time/86400)*86400;
There are 86,400 seconds in 24 hours (which is the length of a typical day, but not all... see DST). Since our timestamps are in UTC, this shouldn't be a problem. You can divide that by the number of seconds in a day, drop the remainder, and multiply back out.
Using a DateTime object can be helpful, and also can make the code more readable...
$dt = new DateTime();
$dt->setTimestamp(1310571061);
echo $dt->format('Y-m-d, H:i:s') . "\r\n";
$dt->setTime(0, 0, 0);
echo $dt->format('Y-m-d, H:i:s');
Result...
2011-07-14, 03:31:01
2011-07-14, 00:00:00
The choice of whether to use raw timestamps or DateTime objects will depend a lot on the implementation needs, but generally speaking DateTime objects will go a long way towards reducing confusion and errors that can crop up especially around Timezone issues and Daylight Saving Time issues.
Try:
<?php
$ts = '1310571061';
echo strtotime(date('Y-m-d 00:00:00', $ts));
?>
$pubdate='2003-02-19T00:00:00.000-05:00';
$da = strtotime($pubdate);
echo $dat = date('Y-m-d', $da);
The answer is like :"2003-02-19"
Thank You
You could do:
$date = strotime(date("y/m/d", $timestamp));
This is what I usually do:
your_timestamp = pd.to_datetime(your_timestamp.strftime(format="%x"))
The function strftime will convert your_timestamp to a string without the time component. Then the function pd.to_datetime will convert it back to a Timestamp without the time component.

strtotime / 86400 not returning even number of days

I am having a strange result with PHP Version 5.3.1, can anyone explain the below result?
$secondsDiff = strtotime(date("2011-11-10")) - strtotime('2011-07-15');
return ($secondsDiff/86400);
it returns 117.958333333??
When I use dates closer together it generally works.
I had a look through the docs, but couldnt find any reference to this. Is this a known php bug that I just need to learn to live with or am I missing something very obvious?
This is probably due to a DST switch, which will increase or decrease the length of the period by an hour.
This could be fixed by rounding, or - more elegantly - by PHP 5.3's fancy new DateInterval class which can format periods as days and more.
Stolen from the manual:
<?php
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');
?>
Don't convert seconds into days by dividing them by 86400. It will work most of the time, sure, but in some circumstances it will return an ugly number. That is what is happening here. The usual culprit is a switch into or out of daylight savings time.
The slow way to do it is to use a loop and calls to mktime(); the modern way is to use the DateInterval class.
The strtotime() function uses the TZ environment variable. This means that when you convert that date, you end up with a timestamp that isn't exactly at midnight, unless you happen to have your timezone set up for GMT.
So, if you are in an area with daylight savings time, then a date in November will be an hour off than one in July. You can easily test this using the two dates you provided. On my server, one appears at 4:00AM, and the other at 5:00AM on their respective dates.
Another solution: Add UTC to the string as in
$datetime1 = new DateTime('2009-10-11 UTC');
$datetime2 = new DateTime('2009-10-13 UTC');

Categories