Converting from UTC in PHP using a variable timezome - php

I store timestamps on my server using a simple timestamp in SQL. When I pull down that timestamp, I run it through the following function in order to format the time.
How do I add to the following function in order to convert $timestamp into whatever timezone the user is querying from?
// Returns the formatted time
function displayDate($timestamp)
{
$secAgo = time() - $timestamp;
// 1 day
if ($secAgo < 86400)
return date('h:i:A', $timestamp);
// 1 week
if ($secAgo < (86400 * 7))
return date('l', $timestamp);
// older than 1 week
return date('m/t/y', $timestamp);
}

If you have timezone name to change, you can use something like:
$date = new DateTime(date('Y-m-d H:i:s', $timestamp), new DateTimeZone('UTC'));
$date->setTimezone(new DateTimeZone('Asia/Vladivostok'));
return $date->format('m/t/y');
Where Asia/Vladivostok is the user's custom timezone.

#zerkms's method is the best way to convert timestamps to any timezone.
But if you do that every time you need to display a time, it may have a significant performance hit because you're setting up and tearing down a timezone object every time. There's a convenient shortcut, if all the timestamps on the page are going to be in the same timezone. (Which is usually the case, because users don't change timezones in the middle of an HTTP request.)
Somewhere outside of the function, do:
date_default_timezone_set('America/New_York'); // or any other timezone
It's probably a good idea to tie this into one of your session management functions, so that the same user always gets the same timezone.
Once you do this, date() will automatically start using the correct timezone, assuming that $timestamp represents a Unix timestamp. It will also automatically correct for daylight saving time. So there's no need to change anything in that function.
Use timezone_identifiers_list() to retrieve a list of valid timezones.

Related

Why is the difference between timestamp unix time and time() incorrect?

I'm trying do execute a php script with cron after 4 hours after saving an record in database. My problem here is not with cron, all here works fine(I'm sure of this because I'm receiving test mails from daemon cron every 4 hours as it should).
The problem is when I calculate the difference between the timestamp, converted to unix, and the current time and then execute some script.
But the diff bewtween these two times are adding 3 hours more to them and I don't know why but my script executes after 7 hours, instead of 4 hours. Can anyone help me please?
My code looks like this:
<?php
require_once('some-path/wp-load.php');
global $wpdb;
$constant= 4*3600;
$table = 'notifications';
$data = $wpdb->get_results("SELECT * FROM $table WHERE status = 'pending'");
$time = time();
foreach ($data as $r){
$temp_data = strtotime($r->date_created);
if ($time - $temp_data > $constant){
$email = $r->email;
$message = 'test';
$subject = 'test';
$headers = 'From: test <test#test.com>' . "\r\n";
$headers .= 'Content-type: text/html; charset=utf-8' . "\r\n";
$mail_client = wp_mail($email, $subject, $message, $headers);
if($mail_client){
$wpdb->update($tabel, array('status' => 'sent'), array('id_raport'=>$r->id_raport), array('%s'), array('%d'));
}
}
}
Example of date from database Using strtotime(): 1458814621, Directly from database "2016-03-24 10:17:01"
Now, I know I can do something like this to get the real localtime:
date_default_timezone_set('Europe/Bucharest');
$date = date('m/d/Y h:i:s a', time());
$time = strtotime($date);
Update.
But this returns the same thing as the time() method.
Now, I know I can do something like this to get the real localtime:
date_default_timezone_set('Europe/Bucharest');
$date = date('m/d/Y h:i:s a', time());
$time = strtotime($date);
A UNIX timestamp is not "local". A UNIX timestamp is the same all over the world. What you're doing in this code is merely converting a timestamp (time()) to a human readable format, and then reinterpreting it into a timestamp; the result is identical to the original time() value (or at least it should be!).
A human readable date/time format, such as you receive from MySQL (2016-03-24 10:17:01) is incomplete without a timezone. There are more than 24 different absolute points in time at which it is "2016-03-24 10:17:01" somewhere in the world. That timestamp by itself doesn't mean very much.
When you convert it into a UNIX timestamp using strtotime, it must take in additional information to convert such an ambiguous relative time format into an absolute point in time. That information comes from date_default_timezone_set, or whatever is set equivalently in your php.ini.
Your problem almost certainly just boils down to the timezone PHP assumes when doing strtotime not being the same timezone as what your MySQL datetime string is actually for. E.g., if your MySQL datetime expresses the time for UTC, but strtotime assumes Bucharest as the timezone to use, you'll see a difference of a few hours in the resulting absolute point in time.
Simply set/use the correct timezone in your PHP code; think about/be aware/decide on what timezone your MySQL dates are actually stored in.
Also see Does PHP time() return a GMT/UTC Timestamp?
The value returned by time() (a timestamp) is the number of seconds since Jan 1, 1970, 00:00:00 UTC. It is an absolute value.
The value you retrieve from the database (2016-03-24 10:17:01) is a relative value. It can represent different timestamps, depending on what time zone you use.
How to use the DateTime and DateTimeZone classes:
// Timestamp generated from PHP code
// Current time
$date1 = new DateTime(); // it uses the default timezone set in php.ini
// or by a previous call to date_default_timezone_set()
// be more specific
$date2 = new DateTime('now', new DateTimeZone('US/Eastern'));
// $date1 and $date2 represent the same moment in time ("now")
echo(($date1 == $date2) ? 'Yes' : 'No'); // It displays "Yes"
// Display them as timestamps
echo($date1->format('U')); // 1458816551
echo($date2->format('U')); // also 1458816551
// Display $date1 as human-readable format:
echo($date1->format('Y-m-d H:i:s e'));
// It displays: 2016-03-24 12:49:11 Europe/Bucharest
// Change $date1 to use the same timezone as $date2
$date1->setTimezone(new DateTimeZone('US/Eastern'));
echo($date1->format('Y-m-d H:i:s e'));
// Now it displays: 2016-03-24 06:49:11 US/Eastern
// It provides easy ways to generate another date:
$date3 = clone $date1; // create a duplicate
$date3->add(new DateInterval('P2D')); // modify the duplicate
// $date3 is 2 days in the future
echo($date3->format('Y-m-d H:i:s e'));
// It displays: 2016-03-26 06:49:11 US/Eastern
// Get the difference between $date3 and $date1
$diff = $date3->diff($date1)
// you get the difference in date components (days, hours, minutes etc).
print_r($diff);
A date-time value you extract from the database is incomplete. It lacks the timezone. If you stored the value in the database in the past then you should know what timezone it uses. If you get the datetime from the database using SELECT NOW() then the timezone is the default timezone used by the server. It is stored in the system_time_zone server variable and can be queried with SELECT ##system_time_zone
The query:
SELECT NOW() AS now, ##system_time_zone AS tz
returns the local date and time and the timezone used by the MySQL server.
You can use them to create a DateTime object to work with, as in the example code provided above.
As a general rule, always use a single time for the values you store as datetime in the database. I suggest using UTC because everything is relative to it and it doesn't observe DST. Or you can use columns of type TIMESTAMP instead (absolute timestamp do not care about timezones and DST) but they are more difficult to handle.

Get time at midnight(00:00:00) from a date

I am trying to convert a date to a timestamp at the exact midnight point.
To do this, I am using the following little function.
function converttotimestamp($date)
{
$date = str_replace('/', '-', $date);
$date = $date.' 00:00:00';
$date = DateTime::createFromFormat('m-d-Y H:i:s',$date);
return $date->getTimestamp();
}
So as you can see, I am attaching a midnight time at the end.
I tried using this as shown below
echo converttotimestamp('7/22/2014');
So as you would expect when you run this in a unix converter, you would get 1405987200.
But In my case it returns 1405976400 whicj translates to Mon, 21 Jul 2014 21:00:00.
Oh. I am in Kenya.
The reason you may be seeing a different time returned than the one you were expecting is likely because you haven't considered the relevant timezones. There are a couple different ways you can set the timezone. You can set it during runtime:
http://php.net/manual/en/function.date-default-timezone-set.php
You can set it in your PHP config file:
http://php.net/manual/en/datetime.configuration.php#ini.date.timezone
Or you can set the timezone of your DateTime object:
http://php.net/manual/en/datetime.settimezone.php
Whenever you are converting between dates, you must consider the relevant timezone, as this is the only way for the system to determine how to switch between date formats, make comparisions and output specific dates and times. For example, if you want to convert a date and time to a timestamp, the system must know the timezone of the input date and time so it can convert properly. Take a look at strtotime:
http://us2.php.net/manual/en/function.strtotime.php
Unix timestamps are GMT timezone, so make sure you convert your datetimes accordingly. HTH.

PHP Adding and Subtracting Time to a given timestamp

I get a timestamp from mysql like
2012-04-12 16:42:33
in PHP how can i subtract hours, or basically how can i change timezone (-3 hours)?
You should use PHP's DateTime. You can check out the supported formats and then create a new object:
$date=new DateTime("2012-04-12 16:42:33");
This object also supports changing timezones and other conversions. Setting a new timezone (from PHP manual):
$date->setTimezone(new DateTimeZone('Pacific/Chatham'));
strtotime('-3 hours', strtotime('2012-04-12 16:42:33'));
http://php.net/manual/en/function.strtotime.php
Changing timezones is technically a bit more tricky, since the way your timestamp is formatted, we don't know what timezone the original is in. So, this code should suffice.
$hours = 3;
$time_old = "2012-04-12 16:42:33";
$time_new = strtotime($time_old);
$time_new = $time_new - (60 * $hours);
date($time_new);
This will allow you to dynamically change the hours by changing $hours.

advice with php date and timestamps

We have a battle system where people can pick a match time to challenge another player. To create a match the user needs to pick a date. Currently a user picks the day, hour, minute, and pm/am from a dropdown list. If the user selects 5/20/2012 # 1PM, the system adds the hours and minutes from the start of the day. Here's a quick sample to get a better understanding of what I'm talking about:
$time = strtotime('today', $inputdate);
$time = $time + $hours + $minutes;
the value of $hours changes if the users selects AM or PM. It's pretty basic:
Everything was working fine until people started have timezone issues. For example, if player A creates a match at 1:PM, then player B will see the match starts at 1:PM, but he/she will have different timezones!
The problem is that I don't know the problem :/
I don't know how to fix the timezone issue. I have been creating functions in the hopes that everything will fall together, but no luck.
What I have:
User profiles have a timezone options.
A function that gets the raw timestamp and returns the formatted time based on the user's timezone.
A function that gets a timestamp and converts it to another timestamp
based on the user's timezone.
I'm lost and I can't seem to fix the issue, I can code, but right now I'm not thinking logical. I took me one hour to write this and try to explain it how I could, since I myself don't know how to make it work. Some advice is appreciated.
I need a function to convert a timestamp to UTC-5:
function input_date($timestamp)
{
global $vbulletin;
$timestamp = (int)$timestamp;
if (strlen((string)$timestamp) == 10)
{
$hour = 3600.00;
$offset = $vbulletin->userinfo['timezoneoffset'];//sample -8
$ds = (int)$vbulletin->userinfo['dstonoff'];//DST
$fluff = $hour*($offset+5.00);
$timestamp = $timestamp+$fluff+($ds*$hour);
return $timestamp;//return timestamp in UTC-5 format..
}
else
{
return 0;
}
}
Essentially everything in the database should be stored using a single timezone, preferably one which is not affected by DST. The standard option here is UTC.
If you know the user's timezone by its name, you can use that to generate your time:
// Player A creates match at 1PM Europe/London
$timezone = 'Europe/London';
$localTime = '2012-03-01 13:00:00';
// work out UNIX timestamp using that timezone (making it timezone independent)
date_default_timezone_set($timezone);
$timestamp = strtotime($localTime);
// store $timestamp in the database
// Player B views the timestamp with timezone America/Los_Angeles
$timezone = 'America/Los_Angeles';
date_default_timezone_set($timezone);
var_dump(date('c', $timestamp)); // see manual for more output formats
If you have the timezones stored as their abbreviations (e.g. "CET", "GMT"), then use timezone_name_from_abbr to get the correct timezone name.

PHP timezone function not working

I'm creating a forum, which also stores the time a post was sent, and I need to convert that into the user's timezone.
Now, the MySQL DataBase stores the time with UTC_TIMESTAMP() (in a column with the DATETIME type), and I created a little function from the code on http://www.ultramegatech.com/blog/2009/04/working-with-time-zones-in-php/ to convert the time to the user's timezone. This is the function:
function convertTZ($timestamp, $tz='UTC', $format='d-m-Y H:i:s') {
// timestamp to convert
$timestamp = strtotime($timestamp);
// the time formatting to use
$format = $format;
// the time zone provided
$tz = $tz;
// create the DateTimeZone object for later
$dtzone = new DateTimeZone($tz);
// first convert the timestamp into an RFC 2822 formatted date
$time = date('r', $timestamp);
// now create the DateTime object for this time
$dtime = new DateTime($time);
// convert this to the user's timezone using the DateTimeZone object
$dtime->setTimeZone($dtzone);
// print the time using your preferred format
$time = $dtime->format($format);
return $time;
}
And I made a test page at http://assets.momo40k.ch/timezones.php.
Now, when I insert a post into the DataBase at, say, 11:50 in my timezone (which is Europe/Rome), it inserts 09:50 in UTC, wich is correct, according to some online timezone converters.
But when I try to convert it back to Europe/Rome with the convertTZ() function, it returns 09:50, as if Europe/Rome is UTC. If I try converting it to a GMT+2:00 timezone, it returns 10:50. Can anyone fugure out why this is?
P.S: I'm not using the CONVERT_TZ() SQL function because my server does not support named timezones, so this function is my workaround.
Make sure your stored timestamps are UTC:
$date = new DateTime($timestamp, new DateTimeZone("UTC"));
$date->format(DATE_W3C); // does it gives the expected result ?
BTW your function can be simplified to this:
function convertTZ($timestamp, $tz='UTC', $format='d-m-Y H:i:s') {
$dtime = new DateTime($timestamp, new DateTimeZone("UTC"))
$dtime->setTimezone(new DateTimeZone("UTC"));
return $dtime->format($format);
}
MySQL always stores TIMESTAMP fields in UTC internally (that's the definition of a unix timestamp, in fact). So when you SELECT or UPDATE/INSERT/REPLACE, the time you get or set is always in the MySQL server's local time zone.
So a common mistake is to store UTC_TIMESTAMP(), which MySQL interprets as a local time and so the current time gets double-converted to UTC when it stores it internally in the field as a unix TIMESTAMP.

Categories