how to get date and time respecting user's timezone - php

I'm totally confused about php/mysql date/time functions.
My date column is timestamp - defalult value - current_timestamp.
date_default_timezone_set("Europe/Belgrade"); //my timezone
$stmt = $db->query("SELECT * FROM cinema order by date desc");
while($row = $stmt->fetch()){
$date = strtotime($row['date']);
$datea = date("d-m-y", $date);
$time = date("H:i", $date);
...
I'm getting the difference of -2 hours comparing to my local time.
How can I get the correct time (respecting my timezone), and if possible each user, whereever he is located on the globe, to get this data respecting his own timezone?

MySQL does not saves time zones at all. Depending for what you'd use the data stored, you should either always store the date-time value in "UTC" (this is like GMT, with no TZ offset at all) or in some cases you would like to store it with the offset already set. But for the second option, you should also store the TZ or the offset somewhere else (again MySQL date-time is unable to store this) in order to properly reconstruct the object from the DB.
For example, I usually add a created_at, updated_at fields in my db records and I store this in UTC, for this task I use PHP's gmdate('Y-m-d H:i:s')
Now, if you have to show this date-time in the user's TZ, you just have to create a DateTime object like so and change the TZ:
$createdAt = new DateTimeImmutable(
$row->created_at,
new DateTimeZone('UTC')
);
For the second case, where you could store the date-time with additional piece of data where you also save the TZ, you have to make sure to instantiate the DateTime object using the timezone constructor second argument to move the offset properly. So for a person from Argentina that will travel to Madrid, you might want to store the checkin date in the TZ of the destination (e.g. Madrid), but for displaying purposes, (e.g. want to know if might be able call in a normal time and let the family know that he/she arrived Ok) you later convert it to the origin tz:
$checkinAt = new DateTimeImmutable(
$row->checkin_at,
new DateTimeZone('Europe/Madrid')
);
$checkinAt->setTimezone('America/Argentina/Buenos_Aires');
To sum up:
You need to know how the date was stored, if you store all of it in UTC (e.g. no offset) then is simpler, but you might have issues when querying data if you need to access data assuming that have offset already.
MySQL does not stores TZ with its date-time value.
Make sure to instantiate the DateTime object using the proper timezone, PHP will use the default TZ if you don't pass any in the constructor. This is set on the php.ini and you can change it with this function date_default_timezone_set in your scripts.

you can do it pretty sweetly just in the sql query
CONVERT_TZ (dt, from_tz,to_tz)
http://www.w3resource.com/mysql/date-and-time-functions/mysql-convert_tz-function.php
$stmt = $db->query("SELECT *, CONVERT_TZ(date, "+00:00", "+01:00") FROM cinema order by date desc");
^ Assuming your database is UTC time and the time you are trying to convert to is "Europe/Belgrade".
First parameter is your datetime stamp, second is your database timezone and the third is your time you want it to convert to. If the timezone change is for the where/conditional part of the query you would put your from and to the other way around.

To get user or browser time. You must have their timezone, which you can get from Link.
Follow these steps:
download code and call it by function call
In first output you will see browser/user datetime, which you need to change accordingly(Ex: mm-dd-YY), using js bulit-in functions.
Put outputted value into one js variable, and pass that value to form hidden input fields
After form submission, capture that value as GET/POST to your database.
If you still fine hard time then, please let me know.

Related

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.

PHP UNIX Timestamp not iterating to the same value

I am facing a problem with unix timestamps, php and mysql and would be great if somebody could explain to me where I am going wrong or if I am not then why I am getting the figures that I am getting.
When I use jquery datepicker to pass the date in year-month-date format to php the hour and minutes have been set by default of 23:00:00 in the timestamp even though I am not passing this infromation in the request. So my question is where is this phantom 23:00:00 appearing from?
Workflow:
Using datepicker: datepicker -> php -> mysql = TIMESTAMP which has time set at 23:00:00.
Without using datepicker: php->mysql = TIMESTAMP with the correct hour and minutes.
Thanks for reading.
EDIT: PHP code as requested:
PHP code:
$setdatealpha = $_POST['datepickeralpha'];
$setdatealpha = strtotime($setdatealpha);
// With this, I am inserting into MySQL like so:
$sql = "INSERT INTO TABLE (DATE_FIELD) VALUES (?)";
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s',$setdatealpha);
$stmt->execute();
Now when I read the entered information back and convert it to date time format via date('Y-m-d',timestamp), the date entry correct and the time entry has the 23:00:00 value.
This does not occur if I do a standard converstion via strtotime (date);
Based off of the information currently available, I would suggest that you make sure each timestamp is in UTC. I always run into timezone issues.
For PHP, like: $current_timestamp = strtotime($date." UTC");
For jQuery datepicker I found this stackoverflow thread: How to obtain utc time in jQuery datetimepicker
Most likely, time zone.
First of all, let's clarify the context. strtotime() produces a Unix timestamp, which you apparently feed DATE_FIELD with. If that works, it means that the column is an INTEGER. In the case, you're doing something afterwards to display the date and you haven't shared that part—also, MySQL is innocent here because it doesn't even know what DATE_FIELD is meant to be date.
While strtotime() can be fed with a raw date, it needs to generate time as well. It can't do it unless it knows the time zone. Additionally, when you have an integer variable with a Unix timestamp and you want to display it as proper date you also need to know the time zone.
In both cases, if you don't provide it PHP will use a default value:
var_dump(date_default_timezone_get());
So you'll possibly want to set a known one with e.g. date_default_timezone_set(). However, your users may have a different time zone than you so yours would be meaningless to them. Since you prompt the user for a raw date (without time) it's possible that time is actually not relevant to the question. In such case, you may want to:
Make DATE_FIELD of DATE type.
Avoid strtotime() and similar stuff. You may want to use checkdate() instead.

How can i insert real time of an event into database using php mysqli?

I'm trying to add datetime for check record changes. I'm using datetime datatype in table.
`date_added` datetime DEFAULT '0000-00-00 00:00:00',
I use following php built-in function using for datetime column in the query
date("Y-m-d H:i:s");
Problem is that this function date("Y-m-d H:i:s"); giving me two different date and time when i check in same time on server.
Localhost Result
date("Y-m-d H:i:s"); == 2016-07-12 13:10:04
Server Result
date("Y-m-d H:i:s"); == 2016-07-12 05:08:07
So when i use TimeAgo function on date_added column it is giving me wrong time, I mean the server time. For example I add a record then function will return me Record Added 8 Hours Ago so its totally wrong. I would like to know how can i add real time of an event into database that i can show using TimeAgo() function.
Is there any way to do that without change the server timezone, because if I change the timezone then it will be showing correct time only for those who are in the same region but what will be get others? I think they will face same issue.
I wanted to develop something like Facebook DateTime Functionality.
Can any one guide me how can I achieve this kind functionality? I would like to appreciate. Thank You
Instead of fiddling with timezones, why not just do
ALTER TABLE `your_table`
CHANGE `date_added` `date_added`
TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
This will change your column from a DATE column to a TIMESTAMP column, converting all the dates to their respective UTC timestamps in the process.
When a new row is inserted, it will use the current timestamp as a value. Timestamps are always in UTC, so you don't have to change the timezone on your MySql server, nor supply the date when inserting a new row.
If you cannot or want not change your columns, you can also just select the timestamp via
SELECT UNIX_TIMESTAMP('date_added') FROM your_table;
For your TimeAgo, you can then just do
$now = new DateTime;
$dateAdded = new DateTime("#$yourTimestampFromDb");
$dateAdded->setTimezone($now->getTimezone());
$timeSinceAdded = $dateAdded->diff($now);
When you supply a timestamp to DateTime, it will always use UTC regardless of your default server timezone set. Consequently, you have to either convert $dateAdded to the default timezone (as shown above) or convert $timeSinceAdded to UTC.
To change the dateTime to the currently visiting user's timezone, you either
need to have this information in your database, e.g. because you are asking registered users to supply this information
or you determine it at runtime, usually by doing a GeoIP lookup on the visiting user's IP or by sending the DateTime Offset from the user's browser.
In any case, you then just change both DateTimes to that timezone. This is easily done via setTimezone().
The $timeSinceAdded will then be a DateInterval object, which you can use like this
echo $timeSinceAdded->format('%a total days');
Please refer to the links for further details, for instance on the available format modifiers.
If you're accessing the same database server from clients with different timezone settings, you could also insert and check the date/time fields in sql:
INSERT INTO my_table SET date_added = NOW();
and then also check with something like
SELECT * FROM my_table WHERE TIMESTAMPDIFF(SECOND, date_added, NOW()) > 3600;
to select rows that are older than 1 hour.
Your question is a bit ambiguous but i'll try to explain a workaround that i think should fix this issues.
If you allow other users to add or update your database then, you should be having some information about them, like which city/continent they are coming from. You might also have telephone contacts and more about them.
If it is true that you possess such information about your users in your database then use that information to detect and load their timezone when they log into your system.
You can have a table with all the timezones or create an array that will hold all the known timezones so that when you call
date_default_timezone_set('continent/city')
function you can dynamically change the parameters to suit the current users timezone and later use that to affect date added field.
Problem
TimeAgo/nicetime function uses strtotime() to convert your datetime field value to unix timestamp. You receive a number of seconds since January 1 1970 00:00:00 UTC until the date you passed as a string. Then time() function returns the number of seconds until now, and nicetime compares the difference. The problem is in strtotime, when we send to it the text like "2016-07-12 05:08:07", it has no idea what time zone that is in and how it should be converted to UTC, so it uses the best guess, often incorrect.
Quick Solution
Specify the time zone of your date that you pass into nicetime() function. Instead of doing this:
$date = '2016-07-04 17:45'; // get from database
print nicedate($date);
try this:
$date = '2016-07-04 17:45';
print nicedate($date . ' America/Denver');
// mind the gap --------^
That should fix it.
Before one blindly goes ahead and starts comparing times, or performing date / time calculations on values retrieved from a database, it is essential that we understand the individual database's configuration settings to ensure our calculations are correct.
It should be noted that the MySQL timezone variable's default setting is SYSTEM at MySQL startup. The SYSTEM value is obtained from the the operating system's GLOBAL time_zone environment variable.
MySQL's default timezone variable can be initialised to a different value at start-up by providing the following command line option:
--default-time-zone=timezone
Alternatively, if you are supplying the value in an options file, you should use the following syntax to set the variable:
--default-time-zone='timezone'
If you are a MySQL SUPER user, you can set the SYSTEM time_zone variable at runtime from the MYSQL> prompt using the following syntax:
SET GLOBAL time_zone=timezone;
MySQL also supports individual SESSION timezone values which defaults to the GLOBAL time_zone environment variable value. To change the session timezone value during a SESSION, use the following syntax:
SET time_zone=timezone;
In order to interrogate the existing MYSQL timezone setting values, you can execute the following SQL to obtain these values:
SELECT ##global.time_zone, ##session.time_zone;
It should be noted also that:
The current session time zone setting affects display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), and values stored in and retrieved from TIMESTAMP columns. Values for TIMESTAMP columns are converted from the current time zone to UTC for storage, and from UTC to the current client time zone for retrieval.
To obtain values in UTC time, use the UTC_DATE(), UTC_TIME() or UTC_TIMESTAMP() functions instead. To convert to another time zone, pass the value of the appropriate UTC function return to convert_tz(), which requires the zoneinfo tables to be generated (see below).
In your circumstances, if you DO NOT want to / CAN NOT change the SERVER time_zone value, you will have to explicitly set the individual SESSION timezone values for each client connection which will enable you to draw a line in the sand and have a known base from which you can convert and display a facebook user's post time into a viewer's local timezone.
To explicitly set the session timezone when connecting, issue the following command:
SET SESSION time_zone = '+10:00';
When you explicitly set the SESSION time_zone, and store a TIMESTAMP value, the server converts it from the client's time_zone to UTC and stores the UTC value (Internally the server stores a TIMESTAMP value). When you select data from the database, the opposite conversion takes place and provides the client with a UTC time in the client's timezone.
On the topic of data types and time zone's, in PHP you are better off using the DatTimeZone class if you would like to improve the accuracy of your date and time values by facilitating daylight saving aware dates and times.
As noted earlier, if your database is MySQL, you can load / generate the zoneinfo tables with the following command:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
* where root is the username to be substituted.
Performing the generation of the zoneinfo tables allows you to use the convert_tz() function which accurately converts dates and times from one time zone to another, like so:
select DATE_FORMAT(convert_tz(now(), 'UTC', 'Australia/Perth'), '%e/%c/%Y %H:%i') AS PERTH_TIME;
PERTH_TIME;
+-----------------+
| PERTH_TIME |
+-----------------+
| 19/7/2016 19:42 |
+-----------------+
Additionally, you can generate an array of UTC time zones programmatically by calling the static function listIdentifiers() in the PHP DateTimeZone class.
May the force be with you.

Can someone please clarify how MySQL's TIMESTAMP is used in conjunction with PHP's DateTime class?

I've been studying the differences in usage between MySQL's DATETIME and TIMESTAMP. It seems that it's pretty straight forward with DATETIME. I would use the following procedure:
Choose the default timezone for all dates, such as UTC.
Let user select a date from drop-down.
Create new PHP DateTime object with the chosen date, using the user's timezone settings, such as EST.
Convert the object to UTC, and insert into database.
On another page, retrieve datetime value and make a new DateTime object with it, using UTC timezone.
Convert object to user's local time (EST), and display to him.
Now, it seems that mysql's TIMESTAMP column type can help eliminate all of these conversions.
What would the above steps look like with the TIMESTAMP column type?
Would I need to do "SET time_zone = timezone;" in the beginning of each pageload to set the timezone to the location of the user?
Would it be easier to ONLY use one type of date column type per database? If not, it may require two different sets of functions to produce the right date.
Should TIMESTAMP only be used in columns not intended to be shown to the public (so as not to deal with formatting)? Like when a row was created, last edited, etc.
I have not tested any of this approach, but it seems pretty straightforward =)
You shouldn't need to convert dates, just set the time zone when you
read/write from dB to get everything right.
Yes, you will have to set right time zone after connection to dB is made.
You mean to only use datetime or timestamp? It really depends on how you intend to
use the columns. But there isn't a clear have to do.
Same as above, it isn't wrong formatting your data from the dB, with a timestamp you can return date style strings from the dB so no worries
Traditionally timestamp is associated like you mention, and datetime for other dates.
more on locale/time zone:
MYSQL set timezone in PHP code

PHP displaying stored time data, and storing time data while accounting for different timezones

I am creating this post, to get confirmation that i am understanding the process correctly, and also to get feedback on a few minor details on solving the issue of post times being displayed and stored correctly for users in various time-zones.
Storing the time
First step is getting the users timezone as a GMT offset format using a javascript function, and storing it in a session variable. For example, the $timezone variable will store GMT -4
$timezone=$_SESSION['time'];
Next, Once i have my users timezone. When the user makes a post, I store the post time in mysql database, I will need to store it as a UTC format. How do i do this? Currently when I store the time data. it is in the following way. My stamp field is datetime format, and i would like to leave it as such if possible.
INSERT INTO posts (stamp) VALUES (now())
What function do i use instead of now() to get the UTC format which will then be inserted into my database? I assume that I need to use a php function which will use the $timezone to produce the UTC date.
Displaying the time
Next, Once the UTC date is stored in the db. I need to display the data to the user based on the $timezone variable we set.
So when I display the time, I currently do
echo date('F d', strtotime($list1['stamp']));
Once i have stored the data as UTC time, this will display the UTC time, but i need to show the user the UTC offset for their timezone, so I will need to convert $list['stamp'] in UTC time to a the users timezone using $timezone. What function do i user for this?
tl:dr
This should be all I need to make this work. let me know if you see any suggestions, or items that i have not accounted for, and if you know what functions I need to use to convert the time to UTC to store in the database, and what function to use to convert the UTC time to display user, using the $timezone variable.
For inserting UTC time into the database:
INSERT INTO posts (stamp) VALUES (UTC_DATE())
UPDATE: This will only insert the YYYY-MM-DD into your database. If you need time as well, then use:
INSERT INTO posts (stamp) VALUES (UTC_TIMESTAMP())
Then for printing the date according to timezone:
$date = date_create($list1['stamp'], timezone_open($timezone)); //$timezone='Pacific/Nauru';
echo date_format($date, 'F d');
That should help get you started. Learn more about PHP's DateTime Class for Object Oriented Methods, and cleaner programming in general.

Categories