Date Changing Due to Timezone Setting - php

The date I store in mysql looks fine when viewing the database, but when I am viewing the date it is always behind a day.
The mysql data type is "date".
I am getting the date column from mysql using UNIX_TIMESTAMP.
I am displaying the date using php's date() function.
I am using bluehost and configured php.ini to use Los Angeles time zone.
Example: I create a new article and key in 2013-05-08. It gets stored as a date type in mysql showing 2013-05-18. But when I go to view it later it shows 2013-05-07.
The timestamp is 1367992800, which is Wed, 08 May 2013 06:00:00 GMT in GMT, but in my timezone Tuesday, May 07, 2013 11:00:00 PM.
How do I display the originally intended date of 2013-05-18? I do not want to change my timezone to another since Los Angeles is my correct time zone and for all my other methods where we need to record a timestamp, it is accurate.

If you want your date to be independent on timezone you should store it in a column that does not transform the value. So the date column type you've chosen is quite appropriate.
The problem comes when you try get that date in UNIX TIMESTAMP. UNIX TIMESTAMP is an amount of seconds since 01.01.1970 in GMT. It means that mysql converts your date into timestamp in GMT using it's timezone settings.
PHP date function also depends on php timezone settings and converts timestamp into date in the current timezone.
To get date from MySQL without converting it into current timezone just do not fetch it using UNIX_TIEMSTAMP function. Get it as is or using DATE_FORMAT function.

You should use the DateTime object.
$timezone = new DateTimeZone('Europe/London');
$date = new DateTime();
$date->setTimestamp($timestamp);
$date->setTimezone($timezone);
echo $date->format('Y-m-d H:i:s');

Related

Trying to get Carbon timestamps in different timezones

We run a Laravel app with MySQL DB. The DB consists of many entries relating to different pojects. The idea is that each project has its own timezone and outputs relevant entries with their dates formatted accordingly. Thus, in order to be able to change timezones and for compatibility sake, all entries are stored in UTC timezone (app default timezone is set to UTC as well).
The problem is that, for instance, we need to get today's entries, but in project's timezone, not UTC. We use Carbon, but it only formats the date for output and still compares them in UTC timezone.
For example, there is an entry made on December 7, 22.32 in UTC. But according to Europe/Moscow, it was made on December 8, 01.32, and it should be considered as today's entry for a project with Europe/Moscow timezone. Still, even with Moscow timezone given, Carbon considers it as yesterday's entry (according to UTC). We use whereDate in the query:
whereDate( 'created_at', Carbon::now($project->timezone)->startOfDay() )
The problem is that Carbon makes no difference between Carbon::now('UTC') and Carbon::now('Europe/Moscow'). It gives zero if you compare them:
$tz1 = Carbon::now('UTC');
$tz2 = Carbon::now('Europe/Moscow');
echo tz1->diffInHours(tz2) //0
What do I miss? How should I do it properly?
$tz1 and $tz2 have timezone info with them, and both contain information of now() time. That's why there is no difference. Change the timezone data to make them sane timezone after retrieving using shiftTimezone().
so
$tz1 = Carbon::now('UTC');
$tz2 = Carbon::now('Europe/Moscow')->shiftTimezone('UTC');
echo tz1->diffInHours(tz2) //should be appropriate

Correctly converting to timezone from UTC in MySQL database with PHP

I see that a stored date value in phpmyadmin is 2020-03-03. In PHP, I set the default timezone to UTC and the user's timezone to America/New_York:
date_default_timezone_set('UTC');
$userTimeZone = new DateTimeZone('America/New_York');
I retrieve my date from the database, set the timezone on the date, and make it into a string. It now equals a day earlier. (03-02-2020)
$dateNeeded = new DateTime($row['dateNeeded']);
$dateNeeded->setTimeZone($userTimeZone);
$dateNeededStr = $dateNeeded->format('m-d-Y');
What did I do incorrectly here?
It is not incorrect. Your date is stored without the time component, which means when you put it in a DateTime constructor, it will be created as midnight ($dateNeeded = new DateTime($row['dateNeeded']) will have the value of 2020-03-03 00:00:00.
That's in UTC timezone because you defined it so at the start. So when you change the timezone, it will move back (as New York is UTC - 5) and gain the value of 2020-03-02 19:00:00.
Since you're only outputting the date in your format (and not the time), it comes out as a day early.
Dont use date_default_timezone_set('UTC'); because MySQL server will use server timezone not UTC,
In example,
Your server time zone is GMT +2
And you set your server timezone to GMT +0;
Then you read your date on database which stored on GMT + 2 time zone
When you try to convert it to other timezone, e.g. GMT + 5,
It will shift 7 hour not 5 hour

Showing datetimes with different time zones in order according to user's timezone

I have 2 stores in different countries ( Let's say USA and Japan )
And a user using my application in Germany GMT +2
Two stores give me order dates according to its timezone
The store in the USA is located in LA GMT -7
The store in JAPAN is located in Tokyo GMT+9
Let's assume two orders sold at the same time
I want to show users the orders in order according to German timezone
My question is how should I store order dates in mysql (timestamp (int) or datetime) and how can I convert those dates to user's timezone
--Edit--
to those who want to convert timestamps to datetime with timezones
$timestamp = 1554280893 ;
$datetimeFormat = 'Y-m-d H:i:s';
$date = new DateTime("America/New_York");
$date->setTimestamp($timestamp);
$utc=new DateTime($date->format($datetimeFormat),new DateTimeZone("America/New_York"));
$utc->setTimezone(new DateTimeZone("UTC"));
echo $utc->format("Y-m-d H:i:s");
I convert all timestamps to UTC format and store in db. Then I order all data based on user's timezone by using Mysql's CONVERT_TZ() function
UTC is a better format to save the date and time in mysql. Always show this according to the user's zone.
First: Convert the time before saving in the MySQL.
Second:
Use CAST by (in your mysql query)
SELECT CAST(getdate() AS date);
Hope this will be resolved using mysql date and time functions.
For more info please take a look to this:
mysql date and time functions
It will be better to save datetime in UTC and display it as per the user's timezone. Convert datetime in SQL query with this CONVERT_TZ(orderDate,'+00:00','+02:00')

Storing dates and times in UTC and converting them local time in PHP/MySQL

I wanted to ask if this was going to work, before I went on a full fledged refactor of how i handle dates and times.
To frame my question, here's my problem...
I store "actions" taken by the user in a history table. These actions have a timestamp on them. Users can be from all over the world, and hence have different timezones. I want to display the items in the history and show the timestamps in one's local timezone.
Also, I know I can use datetime fields and simply store UTC time formats, but I'm opting to use timestamp so i can set a default to current time.
Will this work for my problem?
My server time zone will be Los Angeles
Store timestamps as a timestamp in MySQL. My understanding is that timestamp is always stored as UTC. Records will be stored by default as creation_date OR i will explicitly set UTC_TIMESTAMP(). Effictively, all records in the db will be UTC.
When a user logs in I will grab their timezone (I store this in the db as a user setting).
For this example, lets say this person is in New York.
Here's where my question is. Will either of these work?
a) Grab the history data. All timestamps will automatically be converted from UTC to Los Angeles time. Foreach history item, convert the Los Angeles timestamp to New York timestamp and echo.
OR
b) Set the php timezone "date_default_timezone_set" to New York. Grab the history data. All timestamps are STILL in Los Angeles time by server is still Los Angeles time. Foreach history item, just echo the timestamp because the "date_default_timezone_set" will automatically convert the Los Angeles timestamp to New York.
Will option 4b work? Is there a better way to convert from the Los Angeles time to the New York time?
Is there a better way to do this in general?
You are correct, Unix timestamps are always in UTC. If you store the timestamps in your database in UTC, all you need to do to output it in local time is change the timezone in PHP to the timezone local to the user. You don't need to do any conversion on the timestamps.
<?php
$timeStampFromDatabase = 1325448000; // 01 Jan 2012 20:00:00 GMT
date_default_timezone_set('America/Los_Angeles');
echo date('r', $timeStampFromDatabase); // Sun, 01 Jan 2012 12:00:00 -0800
date_default_timezone_set('Asia/Hong_Kong');
echo date('r', $timeStampFromDatabase); // Mon, 02 Jan 2012 04:00:00 +0800
You can change your timezone on the fly and continue to output timestamps in a date format and they will be "converted" based on the set timezone in PHP. It is very easy, you don't need to do any special handling, and it doesn't matter where you set the timezone, as long as you do it before you output dates, but you can read them prior to setting the timezone.
Unfortunately, "date_default_timezone_set" was not working the way I thought it would. As per the previous example, it would work if the dates I was working with were already in unix timestamp format. However, they were formatted in "Y-m-d H:i:s" and the only thing that would change was the GMT offset, which obviously doesnt work.
After a few hours of fidgeting, here's how I was able to handle time conversions.
$datetime = new DateTime($date_to_convert);
$usertimezone = new DateTimeZone($_SESSION['timezone']); //each user has their own timezone i store in a session (i.e. - "Americas/Los_Angeles")
$datetime->setTimezone($usertimezone);
echo $datetime->format("Y-m-d H:i:s");
I suppose that I could have done the following as well:
Pseudo code
strtotime($datetime)
date_default_timezone_set($user_timezone)
echo date(format, $datetime)
the above, i think, would force the date function to handle it's logic in the given $user_timezone. in hindsight, i would have to translate every $datetime -> unix_timestamp -> $datetime_converted, which doesnt sound to be much better than what i chose to do.
Always store your timestamps in the database as UTC. This is a timezone and daylight savings independent point in time time. To display this back to the user in their timezone, simply do:
$users_timezone = 'Europe/London'; // See PHP documentation for names that can be used.
$date = new DateTime();
$date->setTimestamp($timestamp_from_database);
$date->setTimezone(new DateTimeZone($users_timezone));
echo $date->format("H:ia jS F Y");
By default, Unix timestamps are always in UTC. If we store the timestamps in our database in UTC, we just need to use the following PHP script:
<?php
$TZ_UTC = new DateTimeZone('UTC'); //-->Database Timezone;
$TZ_LOCAL = new DateTimeZone('America/New_York'); //-->Expected Local Timezone from user settings;
//--Example Database Query--
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
//---If we want to show UTC timezone directy----
echo $row['action_timestamp'];
//---If we want to show LOCAL timezone from user settings----
$dateObj = new DateTime($row['action_timestamp'], $TZ_UTC);
$dateObj->setTimezone($TZ_LOCAL); //--> Here is the conversion!
echo $dateObj->format("Y-m-d H:i:s T");
}
?>

PHP: Is timezone data somehow embeded into Timestamps?

date_default_timezone_set("Asia/Singapore"); // UTC +8
$dt = new DateTime();
$dt->setTimestamp(DateTime::createFromFormat('u', gmdate('u'))->getTimestamp());
echo $dt->getTimezone()->getName(); // Asia/Singapore
echo $dt->format('d M Y H:i:s'); // Correct local time
$dt->setTimezone(new DateTimeZone('UTC'));
echo $dt->format('d M Y H:i:s'); // Correct UTC Time
die;
I am wondering if timestamps contain timezone data. On line 3 you see that I used gmdate() which should give me UTC/GMT time. But when I get the timezone & formatted datetime, they are in localtime. I didn't set timezones in my DateTime object yet, gave it a UTC timestamp. It somehow knew to convert to localtime. Which makes me wonder if Timezone data are included in timestamps
setTimestamp accepts the timestamp in GMT 0 and you passed it in GMT, because of gmdate('u'). DateTime object takes your current timezone by default.
After that - you have properly set timestamp and current timezone, that is why DateTime object formats the date for Singapore.
Which makes me wonder if Timezone data are included in timestamps
No. Timestamp stores just amount of seconds since unix-epoch.
Timestamps are interpreted according to the interpreters timezone.
So no, they are standard and do not contain timezone data within themselves.
your example proves it, as you change the timezone, so does your result.
If the timezone data was embedded, the result would not change.

Categories