Accepting international datetime input in php - php

I'm currently adding support for internationalisation to a system written in PHP. All dates are now stored as UTC, and displayed according to individual user localisation preferences.
However when a user inputs a date time (such as to specify a certain time window), the date time they input gets interpreted as a UTC datetime, not their local datetime. For the internationalisation to be complete the system needs to assume that a datetime entered by the user refers to their local time.
How do I convert a date string (ie 'YYYY-MM-DD HH:MM') into a unix timestamp for the correct localisation?
Further Clarification -
All dates in database = UTC Timestamps
All HTML Pages display users local time (as defined in their settings)
HTML form has date that defaults to current local time
PHP must treat that date time as local not UTC
PHP must convert this local date timestring into UTC timestamp

Assuming you know the timezone of the user, which he presumably chose in the preferences somewhere:
$timezone = new DateTimeZone($usersTimezone);
$datetime = new DateTime('2012-01-18 20:00:00', $timezone);
echo $datetime->getTimestamp();
This requires a recent version of PHP with DateTime.

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

Any disadvantage using SET time_zone in MySQL PHP

I am using timestamp fields in my databases and my PHP software has its own time management system based on users timezone. I want to use timestamp fields for certain kind of data (created or modified when) and also be able to use te DEFAULT CURRENT_TIMESTAMP for the columns.
Is there any disadvantage setting the timezone to UTC using, SET time_zone = '+00:00', each time the session is created. I have four separate databases which the software uses and currently, I am setting the current timezone to UTC.
I don't want to use DATETIME as they are larger in size and also I won't be able to use DEFAULT CURRENT_TIMESTAMP as the timezone of the server might have an offset.
You should not use SET time_zone if your backend already uses all the logic into converting user's timezone correctly, because you're wasting resources unnecessarily. The UTC timezone should be into the metadata of the DB, where always the DB transactions will work with them.
By the way, TIMESTAMP columns always will be stored in UTC, so you don't need to setting that, unless your columns are datetime (not the case, i think).
When you insert a TIMESTAMP value, MySQL converts it from your
connection’s time zone to UTC for storage. When you query a TIMESTAMP
value, MySQL converts the UTC value back to your connection’s time
zone. Notice that this conversion does not occur for other temporal
data types such as DATETIME.
So you have two options:
Set the timezone in your transactions working with time in your sql;
Working with unix timezones into backend and only showing the correct converted time in the frontend to user.
I prefer the second one.
When dealing with date/time for entry date and/or modified date, it is better to use normal VARCHAR with the length of around 200 (or any other value that fits the full date) in order to store the full date and process your date/time in your PHP script. This gives you the flexibility to view your time based on the timezone defined in your PHP code. Click here to see available timezones in PHP.
You can also format the date/time in any possible format you want by simply using the date_format of PHP.
I have given a reference code below.
//This is the way you define your timezone in PHP code
date_default_timezone_set('Asia/Beirut');
//You can capture the date/time by using the below code. This will store "2017-05-28 23:55:34"
$date_time_registered = date('Y-m-d H:i:s');
//Retrieve the date/time and re-format it as you require. Below code will output "May", full month.
$retrieve_month_only = date_create($row['your_store_date_time']);
$retrieve_month_formatted = date_format($retrieve_month_only, 'F');
echo $retrieve_month_formatted;
You can refer to this link to find out about PHP date/time formatting.

Render date from date field in correct timezone?

Im have a field with date time type. I see in database is always saved other timezone than my default.
When node content is rendered, date looks fine, but when i trying to get node from code i cant render date in correct timezone.
$node->field_customtime->getValue()
I have array of values with standard timezone, when i dump value, the time is wrong.
So i was trying to do it like that:
$value = $node->field_customtime->getValue();
$value = $value[0]['value'];
$date = new \DateTime($value);
$date = $date->getTimestamp();
echo \Drupal::service('date.formatter')->format($date);
And there is still raw date from database (wrong).
I dont know how to correct display date from custom date field. I see in the form correct date (i.e. 11:00 european time) but in database is 10:00. On node page is correct 11:00 so drupal convert it somehow, but how??
I will assume you are using MySQL?
If so then unless you are saving a timestamp the timezone does not matter. It should be saved exactly how you sent it.
If it is a timestamp then the date is automatically converted into UTC for storage and then converted back into whatever timezone you have set in the mysql configuration.
MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.)
What you need to check first is how you are saving the date. Are you storing a timestamp?
If not you need to check how the data is saved and see if anything is happening to the date before inserted into the database.
Unfortunately I do not know much about Drupal but after a quick google I have found out that Drupal 7 happens to have a few ways of handling the datetime. It is quite possible that this may apply for Drupal 8 and you simply need to adjust a configuration.
https://drupal.stackexchange.com/questions/3613/the-differences-between-date-time-zone-handling

PHP & MySQL Timezones whilst supporting user-defined timezones

I'm working on something where the user can select their own timezone and the software will be able to be used by others on their sites as well but I want to make sure that the timezone within the database is always set to UTC.
Now I know how you set the default timezone for PHP, such as:
date_default_timezone_set('Australia/Sydney');
...but I'm not sure how to make sure MySQL is using UTC? ...and even once you have made sure it is using UTC I guess you would have to convert your PHP dates/times into UTC before passing it to the database?
I guess I am wondering about many different date formats such as TIMESTAMP, DATETIME & even UNIX EPOCH integer timestamps which would simply be stored as a int datatype for example.
Then there is the whole retrieving dates/times from the DB and converting it to the respective timezone and lastly how does DST come into all of this?
I know there is a lot of similar questions out there, but I guess none really answered all my questions.
MySQL's data type timestamp stores the dates in UTC. For this to work properly, MySQL uses server's time zone and does the date conversion. It converts the date from servers's current time zone to UTC for storage. This implies that the database server should never change its time zone for this feature to work properly.
When you send the data to such a database, you send the UTC time as well. The easiest way to do this is to format a result of time() according to what MySQL wants (m-d-Y H:i:s).
In PHP, when you format the date for insertion to MySQL, it's the best to use DateTime class. It lets you offset the date with the time zone information, meaning that you don't have to use date_default_timezone_set function - that can lead to mistakes.
An example of DateTime in action:
$date = '1.12.2015 13:37:37'; // Format is day.month.year hour:minute:second
// We create DateTime from custom date format, for the person who resides in Australia/Sydney time zone
$dt = DateTime::createFromFormat('d.m.Y H:i:s', $date, new DateTimeZone('Australia/Sydney');
// Now we change the date's time zone into UTC, and we can insert it into MySQL
$dt->setTimeZone(new DateTimeZone('UTC'));
// This is the formatted date-string that can be safely inserted into MySQL
$date_string_for_mysql = $dt->format('m-d-Y H:i:s');
Alternatively, you can use int type in MySQL for timestamp storage and insert result of time() but this has a huge disadvantage of not being able to use date-related functions.
for current session of mysql you can try something like
SET time_zone = timezonename;
for more details you can also look into this answer https://dba.stackexchange.com/questions/20217/mysql-set-utc-time-as-default-timestamp

Change timezone without changing the value of a DateTime object

Here's the scenario - I have the default timezone in PHP set to UTC. All but one date/time that I work with are set to the current UTC time; when displayed later on, I set the timezone for that particular user and the date comes out in their timezone. Works great.
Except I have one date/time that the user can enter on a form. It comes in as "YYYY-MM-DD HH:MM" in 24 hour time (example: "2014-09-18 17:00"). The user is naturally setting this time in their timezone, not UTC.
If I create a new DateTime object with the input value, it saves in UTC, so when displayed later it's off by several hours (depending on the original timezone). If I set the timezone on the new object, it alters the value, assuming, again, that the input value was UTC.
I've done some Googling but have found nothing in regards to PHP (several answers for C# exist that I've found). Is this possible with the DateTime object (or with Carbon)? Am I stuck with doing a manual addition/subtraction of hours based on the users current timezone to place it in UTC first?
You must set timezone when creating DateTime object, and not when it is already created; then change DateTime object to UTC timezone and save it to you db:
# create DateTime based on user timezone
$dt = new DateTime('2014-09-18 17:00', new DateTimezone('Australia/Sydney'));
# change time to UTC timezone
$dt->setTimezone(new DateTimezone('UTC'));

Categories