PHP & MySQL: Converting Stored TIMESTAMP into User's Local Timezone - php

So I have a site with a comments feature where the timestamp of the comment is stored in a MySQL database. From what I understand, the timestamp is converted to UTC when stored, then converted back to the default timezone when retrieved. In my case, my server is in the Central Daylight Time timezone (CDT).
I have a plan to get the timezone from each user via entry form. I just wanted to know how to convert the TIMESTAMP value into the user's timezone.
First, would I convert from UTC to local timezone? Or CDT to local timezone?
Secondly, how would I go about doing that in PHP? Would I just do:
$userTimezone = new DateTimeZone($userSubmittedTimezoneString);
$myDateTime = new DateTime($storedTimestamp, $userTimezone);
...or is that not correct?

Date/time/datetime values are stored in MySQL as you supply them. I.e. if you INSERT the string 2012-04-17 12:03:23 into a DATETIME column, that's the value that will be stored. It will be converted internally into a timestamp which may or may not be accurate (see below), but when you query for the value again, you'll get the same value back out; the roundtrip is transparent.
Problems may occur if you try to do time calculations inside SQL. I.e. any operation that requires SQL to take the timezone and/or the server time into account. For example, using NOW(). For any of those operations, the timezone and/or server time should be set correctly. See Time Zone Problems.
If that doesn't concern you and you only need to do calculations in PHP, you only need to make sure you know from which timezone to which timezone you want to convert. For that purpose it can be convenient to standardize all times to UTC, but it is not necessary, as timezone conversions from any timezone to any other timezone work just as well, as long as you're clear about which timezone you're converting from and to.
date_default_timezone_set('Asia/Tokyo'); // your reference timezone here
$date = date('Y-m-d H:i:s');
/* INSERT $date INTO database */;
$date = /* SELECT date FROM database */;
$usersTimezone = new DateTimeZone('America/Vancouver');
$l10nDate = new DateTime($date);
$l10nDate->setTimeZone($usersTimezone);
echo $l10nDate->format('Y-m-d H:i:s');

There is no reliable way to get the user's timezone. Timezone information is not sent in HTTP headers. The best that you could do is either:
Match the IP address againsta geographic database
-or-
Use Javascript to get the time set on the user's computer and either send that to the server (AJAX) or make the time string on the client.

$timezone = new DateTimeZone('America/Vancouver');
$date = new DateTime(date('m/d/Y h:i:s a', time()));
$date->setTimeZone($timezone);
echo $date->format('l F j Y g:i:s A')."\n";
Replace new DateTime(date('m/d/Y h:i:s a', time())); with new DateTime("UTC Time");
You can create a new DateTimeZone() object for each user input.

The way to do it is by using javascript. I think the best way to do it is by storing the users GMT into his cookies, and retrieving it on the PHP process form.
<script language="javascript">
function TimeZoneCookie()
{
var u_gmt = (-(new Date().getTimezoneOffset()))/60;
var o_date = new Date("December 31, 2025");
var v_cookie_date = o_date.toGMTString();
var str_cookie = "utimezone="+u_gmt;
str_cookie += ";expires=" + v_cookie_date;
document.cookie=str_cookie;
}
//---------------------
TimeZoneCookie();
</script>
u_gmt explained:
Date().getTimezoneOffset() returns the offset to GMT-0 in minutes
Since getTimezoneOffset() will return the offset to GMT-0 and not from GMT-0 we'll need to turn it around. How? simple, just by knowing that -*-=+ & -*+=-. If you know basic math, you already know this principle.
As I said in step 1 getTimezoneOffset() will return the offset in minutes, so we just divide it by 60, so we can get the gmt offset format.
Result: (-(new Date().getTimezoneOffset()))/60
Now retrieve the cookie in PHP:
<?php
$user_timezone = $_COOKIE['utimezone'];
?>

Related

Converting a date from local timezone to UTC

I have a Laravel-based app that is used by people from various parts of the US.
I am capturing a timestamp in Javascript when the user takes a specific action, and then I am submitting that timestamp as form data, for the Laravel/PHP to process.
The timestamp that I am capture in Javascript is in typical "YYYY-MM-DD HH:MM:SS" format.
I have the timezone the user is in stored in a database.
I basically want to take that timestamp, and convert it to UTC time, so that all timestamps in the database are UTC.
That is where I am struggling.
I have the following PHP code:
$defaultTime = request('submitted-time-stamp'); //In this case, we'll say 2022-12-21 12:01:01
$defaultTZ = $user->time_zone; //Translates to America/Denver
$utcTime = new DateTime($defaultTime);
$convertedTime = $utcTime1->setTimeZone(new DateTimeZone('UTC'));
$formattedTime = $convertedTime->format("Y-m-d H:i:s");
echo $formattedTime;
This code – it isn't producing any errors per sé... but it is showing the wrong time. It's showing the time that it went in as, not the time converted to UTC.
Basically, if I submit "2022-12-21 12:01:01" as the time, the converted time SHOULD be "2022-12-21 19:01:01", but it's still just echoing out "2022-12-21 12:01:01".
What am I missing here?
setTimezone() changes the timezone of the object from whatever default it was created with. I.e., it means, "convert from the existing timezone to this new timezone." It does not mean, "interpret the time as if it were in this timezone." If the original string didn't contain some sort of timezone identifier, then that default is whatever your PHP config says.
$when = new DateTime('2022-12-21 12:01:01');
echo $when->getTimeZone()->getName();
This will be the same as:
echo date_default_timezone_get();
Which is probably not what you want unless all your users are in the same timezone as your server.
In order to create a DateTime object in a specific known timezone that is not the same as your server's default, you'll need one of two things -- either a timezone representation in the input string:
$when = new DateTime('2022-12-21 12:01:01 America/New_York');
Or an explicit default timezone passed as a second parameter to the DateTime constructor:
$userDefaultTzStr = 'America/New_York'; // read this value from the database
$defaultTz = new DateTimeZone($userDefaultTzStr);
$when = new DateTime('2022-12-21 12:01:01', $defaultTz);
This latter method is (probably) preferred. If the input string contains any sort of timezone identifier, that will be used and the second parameter will be ignored. But if the input string does not contain any sort of timezone identifier, then the string will be interpreted as if it were in the indicated timezone.
Using Carbon it's very trivial.
use Carbon\Carbon;
$date = Carbon::create(request('submitted-time-stamp'), $user->time_zone);
$date->tz('UTC');
echo $date->format('Y-m-d H:i:s');
It should be the same thing with Laravel's Date facade.
use Illuminate\Support\Facades\Date;
$date = Date::create(request('submitted-time-stamp'), $user->time_zone);
$date->tz('UTC');
echo $date->format('Y-m-d H:i:s');

How to show a Unix-time in a local time format

I have a php variable say $expTime (which has a unixtime say-1359683953) . I want to display this variable on the client side(in a proper time format according to his local time) . I am so confused between the UTC ,GMT , DST all that things. Can anyone suggest a solution for this using php or javascript please.
when I am using echo date('h:i M d/y',$expTime) it is showing me a wrong time.
How I am saving the time to database:
var exp_day= parseInt($("#exp_day").val());
var exp_hrs= parseInt($("#exp_hrs").val());
var exp_min= parseInt($("#exp_min").val());
var exp_time = (exp_day*24*60*60) + (exp_hrs*60*60) + (exp_min*60) ;
then I posted the exp_time using ajax to a php file -
$expTime = time() + $_POST["exp_time"];
What I am retrieving from the database is $expTime . This $expTime I want to display it on the all the clients system according to there local time zone (also by making sure the day light saving)
Use DateTime with timezones:
$datetime = new DateTime('#1359683953');
echo $datetime->format('h:i M d/y') . "<br>";
$datetime->setTimezone(new DateTimeZone('America/Los_Angeles'));
echo $datetime->format('h:i M d/y');
See it in action
UNIX time values are usually UTC seconds since epoch. Javascript time values are UTC milliseconds since the same epoch. The ECMA-262 Date.prototype.toString method automatically generates a string representing the local time and takes account of daylight saving if it applies.
You can also use Date methods to create your own formatted string, they also return local time and date values. There are also UTC methods if you want to work in UTC.
To do this on the client, just provide a UTC time value from the server and then all you need in javascript is:
var timeValue = 1359683953; // assume seconds
var date = new Date(timeValue * 1000); // convert time value to milliseconds
alert(date); // Fri 01 Feb 2013 11:59:13 GMT+1000

PHP: How to return local time from database

I store the dates in my database in DATETIME type, looking as: Y-m-d H:i:s
What I want to achieve is to return the date from the database in the local time of the user. For example, if the user is in France, I will return his timezone. Is it possible to achieve this without storing the timezone of the user? Or if it is possible somehow else, and the storing format in the database needs to be changed, then I can do that. But, I am trying to achieve this without storing the user's timezone.
Store times in UTC in the database, and then do the timezone localization in your application. You will need to know the user's timezone, though.
Well, the only way I can think of doing it without asking the user for their timezone is this:
<p>The time is: <span id="time" data="<?php echo strtotime($time_from_db); ?>"></span></p>
<script type="text/javascript">
(function () {
var t = document.getElementById('time'), d = new Date();
d.setTime(t.getAttribute("data"));
t.innerHTML = d;
})();
</script>
This passes the datetime as a timestamp, which JS then applies locale (including timezone) to.
If you store dates in GMT, then you can present them to the user on their timezones.
EDIT:
date_default_timezone_set('UTC');
$today = getdate();
print_r($today);
Check this: php convert datetime to UTC
and this: Convert UTC dates to local time in PHP
and this: http://www.php.net/manual/en/function.gmdate.php

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.

Converting from UTC in PHP using a variable timezome

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.

Categories