PHP/MySQL Timezone Clarification - php

I'm currently having an issue wrapping my brain around the notion of converting my MySQL time to a specific timezone, depending on the user's settings.
All of my MySQL times are stored in UTC time, in the following format:
2009-11-08 17:06:40
Once I query the time, I'm not quite sure how to convert it to the appropriate timezone using PHP.
Thus, in the example above, I'd like to display:
2009-11-08 09:06:40
Here's what I currently have (which probably needs to be fixed):
$sql = 'SELECT date FROM mytable';
require("connection.php");
$result = mysql_db_query($DBname,$sql,$link);
while($row = mysql_fetch_assoc($result)) {
$dt_obj = new DateTime($row['date']);
$dt_obj->setTimezone(new DateTimeZone('PST'));
echo $dt_obj;
echo "<br>";
}
First off, I get the following error:
Catchable fatal error: Object of class DateTime could not be converted to string
Secondly, I am confused as to whethere I'm setting it up properly to display the time in the correct timezone anyway (in this case, PST).
Any suggestions on how to do this would be greatly appreciated. Thanks!
UPDATE:
I took GZipp's advice, and modified the code to look like:
$dt_obj->setTimezone(new DateTimeZone('America/Los_Angeles'));
echo $dt_obj->format('Y-m-d H:i:s');
However, it's displaying my time (using the example from above) as:
2009-11-08 15:06:40
Any ideas on what would be causing this?

I think this is what you're after;
$dt_obj = new DateTime($row['date']);
$dt_obj->setTimezone(new DateTimeZone('America/Los_Angeles'));
echo $dt_obj->format('Y-m-d H:i:s');
Use the List of Supported Timezones.
Update to edited question: To ensure that PHP sees the time from the database as UTC time, do something like this:
$row['time'] = '2009-11-08 09:06:40';
$dt_obj = new DateTime($row['time'], new DateTimeZone('UTC'));
echo 'UTC: ' . $dt_obj->format('Y-m-d H:i:s') . '<br />'; // UTC: 2009-11-08 09:06:40
$dt_obj->setTimezone(new DateTimeZone('America/Los_Angeles'));
echo 'Los Angeles: ' . $dt_obj->format('Y-m-d H:i:s'); // Los Angeles: 2009-11-08 01:06:40

I may be wrong, but it looks like it's complaining about your echo $dt_obj; statement. You might try echoing the result of DateTime::format();
EDIT: For your new question I would guess that your default format is set to PST already, so when the new date is created it's create with that timezone, thereby setting the timezone changes nothing. You might check and see if that's the case. You also might look at date_default_timezone_set('<tz>');

Related

DateTime object declaration breaks script on PHP 5.4.16

While editing the php file it shows DateTime is not a valid method, plus when I try to use this it stops loading the rest of the page, do I have to implement something?
My goal is to check either if the difference between those variables is more than 3 minutes.
Can I output the difference just in minutes?
$arr["etime"] comes from a mysql query in the format of Y-m-d H:i:s.
$etime = $arr["etime"];
$datenow = date('Y-m-d H:i:s');
$datetimenow = new DateTime($datenow);
$datetimee = new DateTime($etime);
$datedifference = $datetimee->diff($datetimenow);
echo $datedifference->format("%H:%I:%S");
If I just put $date = new DateTime('2000-01-01'); it doesn't load the rest of the page after this.
If I put $datetimenow = new DateTime(); the rest of the page won't load.
Using exception handling, I received:
PHP Fatal error: Uncaught exception 'Exception'
with message:
'DateTime::__construct(): It is not safe to rely on the system's
timezone settings. You are required to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select your timezone.'
You will only need to check the output object values generated from diff(): (Demo)
$etime = '2017-07-10 16:59:04';
$timezone=new DateTimeZone("Australia/Melbourne"); // declare whatever your timezone is
$datetimee=new DateTime($etime,$timezone); // resultset datetime
$datetimenow=new DateTime("now",$timezone); // current datetime
$diff=$datetimee->diff($datetimenow);
//var_export($diff);
if($diff->i>=3 ||$diff->h>0 || $diff->d>0 || $diff->m>0 || $diff->y>0){
echo "Difference is 3 minutes or more";
}else{
echo "Difference is not yet 3 minutes";
}
If you are still experiencing issues with the DateTime class, it may be time to revert to good-ol' strtotime(). It provides a much simpler bit of code anyhow:
if(strtotime('now')-strtotime($etime)>179){ // assuming now is always bigger than etime
echo "Difference is 3 minutes or more";
}else{
echo "Difference is not yet 3 minutes";
}

Convert User Submitted Date To UTC

I'm trying to figure out how to accept a date/time from a form, which is consequently in the user's timezone, and change it to UTC before inserting it into the database. For some reason, no amount of searching has netted me an answer.
My form will POST whatever date is selected by the user to my code, so I expect to be able to do something like this. Note: the $userDate may be relative to any number of timezones based on user's location
$userDate = $_POST['user_date'] // 2014-05-15 16:37:23
I anticipate using Date().getTimezoneOffset() on my form to also submit the users UTC offset (as detailed here).
$userOffset = $_POST['user_offset']
Then before inserting the date into my database, I would like to convert it to UTC -- but I am stumped on how to do that with PHP (I'm actually using Laravel so if you know of a way using Carbon, that would be even easier, but I couldn't find it in their docs).
I've been half tempted to manually parse the offset and convert it to number of seconds and add or subtract it to strtotime() output of the $userDate and then convert it back into a date format using date() -- but there has to be a better way!
What am I missing here? Does PHP have a function I just don't know about that lets me do something like:
$userDate = '2014-05-15 16:37:23';
$userOffset = '+04:00';
$utcDate = date_apply_offset($userDate, $userOffset);
echo $utcDate; // Outputs: 2014-05-15 20:37:23
Or am I making this harder than it has to be?
EDIT
Based on the solution provided by #vascowhite, I went with the following (added into question to improve answers for those seeking guidance)
I ended up using a function from moment.js since I was already using it to convert UTC to user's timezone on display.
HTML:
<input id="user_offset" type="hidden" name="user_offset" value="">
Javascript:
var offset = moment().format('ZZ');
$('#user_offset').val(offset);
PHP (in a custom date class):
class MyDate {
/**
* Convert Date to UTC
*
* #param string $date Any date parsable with strtotime()
* #param string $offset UTC offset of date
*/
public static function toUTC($date, $offset = '+0:00')
{
if ($timestamp = strtotime($date) && ! empty($offset) )
{
$newDate = date('Y-m-d H:i:s', $timestamp);
$newDate = new \DateTime($date . ' ' . $offset);
$newDate->setTimezone(new DateTimeZone('UTC'));
$date = $newDate->format('Y-m-d H:i:s');
}
return $date;
}
}
// To convert
$userDate = trim($_POST['user_offset']);
$userOffset = trim($_POST['user_date']);
$utc = MyDate::toUTC($userDate, $userOffset)
That class method isn't perfect, and in the event something goes wrong, it just returns the date back -- when really it should throw an exception.
This is a simple task with the DateTime classes:-
$userDate = '2014-05-15 16:37:23';
$userOffset = '+04:00';
$date = new \DateTime($userDate . ' ' . $userOffset);
var_dump($date);
$date->setTimezone(new \DateTimeZone('UTC'));
var_dump($date);
You can then format the date as you wish for output eg:-
echo $date->format('Y-m-d H:i:s');
or:-
$utcDate = $date->format('Y-m-d H:i:s');
echo $utcDate; // Outputs: 2014-05-15 20:37:23
See it working.
If you are doing any work with dates and times in PHP it is worth taking the time to become familiar with these extremely useful classes.
For all sorts of date/time manipulations you can make use of moment.php
For your example all what is needed are two lines of code:
$m = new \Moment\Moment('2014-05-15 16:37:23', '+0400');
echo $m->setTimezone('UTC')->format(); // 2014-05-15T12:37:23+0000
There is much more which helps to deal with date/time issues: https://github.com/fightbulc/moment.php
Cheers

DateTime input convert between timezones in PHP

I have an input box that grabs local time
date_default_timezone_set('America/Los_Angeles');
echo "<input type='datetime-local' name='fromDate' class='dates'>";
When I enter 12-31-2014 10:00:00 PM in the input
echo $_POST['fromDate'];
Response: 2014-12-31T22:00:00
$test = new DateTime($_POST['fromDate']);
echo $test;
I get 2014-12-31T22:00:00 America/Los_Angeles
Then when I convert
$from_dateGMT = new DateTime($_POST['fromDate'], new DateTimeZone('Europe/Paris'));
$from_date = $from_dateGMT->format('Y-m-d\TH:i:s');
echo $from_date;
I get 2014-12-31T22:12:00 UTC, which is the same time listed above and should be adding 8 hours.
What am I doing wrong?
I don't deal with dates/times in PHP ever, so this is a learning experience for me.
Perhaps this will work
$test = new DateTime($_POST['fromDate'], new DateTimeZone('America/Los_Angeles'));
$test->setTimezone(new DateTimeZone('Europe/Paris'));
echo $test->format('Y-m-d\TH:i:s');
At least that is how it is done in php manual here: http://us2.php.net/manual/en/datetime.settimezone.php

Why isn't DateTime::sub working as expected?

Thanks to the answers to this question, I've managed to only output a list dates from my MySQL database that are in the future (ie after today) using PHP. However, what if I wanted to set 'today' back a little; in other words, if I want a date not to appear on the list of dates a week in advance?
I've attempted to use DateTime::sub using the following code, but it kills my script (I just get a blank screen - if I comment out the DateTime::sub line, it works again. I still haven't worked out how to get PDO to echo error details):
$dateToday = new DateTime('now');
$dateToday -> sub(new DateInterval('P7D'));
do{
$dateCompare = new DateTime($row['date']);
if ($dateCompare > $dateToday){
echo '<p>'.$dateCompare -> format('Y-m-d').'</p>';
} else {
echo '<p>FALSE</p>';
}
}while ($row = $stmt->fetch(PDO::FETCH_ASSOC));
Any ideas?
You code works just fine for me, I imagine it's a problem with this line:
$dateCompare = new DateTime($row['date']);
What format is the $row's date in?
I'd recommend using
$date = DateTime::createFromFormat('The format your dates are in', $row['date']);
See http://www.php.net/manual/en/function.date.php for possible date formats
e.g. Y-m-d would parse 2012-10-28
If you have an older version of PHP, you could try this "low tech" solution by comparing as strings.
// Assuming your mysql is Y-m-d
$dateToday = date('Y-m-d')
do{
if ($row['date'] > $dateToday){
echo '<p>'.$dateCompare -> format('Y-m-d').'</p>';
} else {
echo '<p>FALSE</p>';
}
while...

Properly Update A Timestamp's Timezone

I'm using the LastFM API to extract a user's recently listened-to tracks (http://www.last.fm/api/show/user.getRecentTracks) and am struggling to shift the timestamp to match my preferred timezone.
I've used date_default_timezone_set at the beginning of the code, but that seems to be ignored when I use strtotime. I'm using strtotime so that I can reformat the styling of the date as Last.FM provides it.
I've figured out how to manually offset to the correct time, via $date - 14400, but I'd like to understand what I'm missing and make the adjustment in the correct way.
Code follows. Greatly appreciate any assistance.
<?php date_default_timezone_set('America/New York'); ?>
<?php $xml = simplexml_load_file("http://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=rj&api_key=b25b959554ed76058ac220b7b2e0a026");
echo '<ul>';
foreach($xml->recenttracks->track as $track) {
$title = $track->name;
$date = $track->date;
$date = strtotime($date);
$date = date("F jS, g:i a e", $date);
$string = '<li>'.$title.' - '.$date.'</li>';
echo $string;}
echo '</ul>';
?>
The problem is that the default timezone you set is used for both the incoming and outgoing translation.
To solve, use PHP timezone functions, and flip it about when reading / writing the time:
$oDateTime = new DateTime($track->date, new DateTimeZone(UTC'));
echo $oDateTime->format('F jS, g:i a e') . "\n"; // For debug: Will give the same back at you.
$oDateTime->setTimezone(new DateTimeZone('America/New York'));
$date = $oDateTime->format('Y-m-d H:i:sP') . "\n"; // Will give the converted date
(You can also do it with date_timesone_set, but this looks neater).

Categories