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
Related
So I've checked the list of supported time zones in PHP and I was wondering how could I include them in the date() function?
Thanks!
I don't want a default timezone, each user has their timezone stored in the database, I take that timezone of the user and use it. How? I know how to take it from the database, not how to use it, though.
For such task, you should really be using PHP's DateTime class. Please ignore all of the answers advising you to use date() or date_set_time_zone, it's simply bad and outdated.
I'll use pseudocode to demonstrate, so try to adjust the code to suit your needs.
Assuming that variable $tz contains string name of a valid time zone and variable $timestamp contains the timestamp you wish to format according to time zone, the code would look like this:
$tz = 'Europe/London';
$timestamp = time();
$dt = new DateTime("now", new DateTimeZone($tz)); //first argument "must" be a string
$dt->setTimestamp($timestamp); //adjust the object to correct timestamp
echo $dt->format('d.m.Y, H:i:s');
DateTime class is powerful, and to grasp all of its capabilities - you should devote some of your time reading about it at php.net. To answer your question fully - yes, you can adjust the time zone parameter dynamically (on each iteration while reading from db, you can create a new DateTimeZone() object).
If I understood correct,You need to set time zone first like:
date_default_timezone_set('UTC');
And than you can use date function:
// Prints something like: Monday 8th of August 2005 03:12:46 PM
echo date('l jS \of F Y h:i:s A');
The answer above caused me to jump through some hoops/gotchas, so just posting the cleaner code that worked for me:
$dt = new DateTime();
$dt->setTimezone(new DateTimeZone('America/New_York'));
$dt->setTimestamp(123456789);
echo $dt->format('F j, Y # G:i');
Use the DateTime class instead, as it supports timezones. The DateTime equivalent of date() is DateTime::format.
An extremely helpful wrapper for DateTime is Carbon - definitely give it a look.
You'll want to store in the database as UTC and convert on the application level.
It should like this:
date_default_timezone_set('America/New_York');
U can just add, timezone difference to unix timestamp.
Example for Moscow (UTC+3)
echo date('d.m.Y H:i:s', time() + 3 * 60 * 60);
Try this. You can pass either unix timestamp, or datetime string
public static function convertToTimezone($timestamp, $fromTimezone, $toTimezone, $format='Y-m-d H:i:s')
{
$datetime = is_numeric($timestamp) ?
DateTime::createFromFormat ('U' , $timestamp, new DateTimeZone($fromTimezone)) :
new DateTime($timestamp, new DateTimeZone($fromTimezone));
$datetime->setTimezone(new DateTimeZone($toTimezone));
return $datetime->format($format);
}
this works perfectly in 2019:
date('Y-m-d H:i:s',strtotime($date. ' '.$timezone));
I have created this very straightforward function, and it works like a charm:
function ts2time($timestamp,$timezone){ /* input: 1518404518,America/Los_Angeles */
$date = new DateTime(date("d F Y H:i:s",$timestamp));
$date->setTimezone(new DateTimeZone($timezone));
$rt=$date->format('M d, Y h:i:s a'); /* output: Feb 11, 2018 7:01:58 pm */
return $rt;
}
I have tried the answers based on the DateTime class. While they are working, I found a much simpler solution that makes a DateTime object timezone aware at the time of creation.
$dt = new DateTime("now", new DateTimeZone('Asia/Jakarta'));
echo $dt->format("Y-m-d H:i:s");
This returns the current local time in Jakarta, Indonesia.
Not mentioned above. You could also crate a DateTime object by providing a timestamp as string in the constructor with a leading # sign.
$dt = new DateTime('#123456789');
$dt->setTimezone(new DateTimeZone('America/New_York'));
echo $dt->format('F j, Y - G:i');
See the documentation about compound formats:
https://www.php.net/manual/en/datetime.formats.compound.php
Based on other answers I built a one-liner, where I suppose you need current date time. It's easy to adjust if you need a different timestamp.
$dt = (new DateTime("now", new DateTimeZone('Europe/Rome')))->format('d-m-Y_His');
If you use Team EJ's answer, using T in the format string for DateTime will display a three-letter abbreviation, but you can get the long name of the timezone like this:
$date = new DateTime('2/3/2022 02:11:17');
$date->setTimezone(new DateTimeZone('America/Chicago'));
echo "\n" . $date->format('Y-m-d h:i:s T');
/* Displays 2022-02-03 02:11:17 CST "; */
$t = $date->getTimezone();
echo "\nTimezone: " . $t->getName();
/* Displays Timezone: America/Chicago */
$now = new DateTime();
$now->format('d-m-Y H:i:s T')
Will output:
29-12-2021 12:38:15 UTC
I had a weird problem on a hosting. The timezone was set correctly, when I checked it with the following code.
echo ini_get('date.timezone');
However, the time it returned was UTC.
The solution was using the following code since the timezone was set correctly in the PHP configuration.
date_default_timezone_set(ini_get('date.timezone'));
You can replace database value in date_default_timezone_set function,
date_default_timezone_set(SOME_PHP_VARIABLE);
but just needs to take care of exact values relevant to the timezones.
I'm trying to retrieve metrics from Google My Business API.
However I cant figure out what to pass as a timestamp for the time periods.
The error I'm getting is this...
Invalid value at 'basic_request.time_range.end_time' (type.googleapis.com/google.protobuf.Timestamp),
Field 'endTime', Invalid data type for timestamp, value is 1606780800
My code is this
$time = new \Google_Service_MyBusiness_TimeRange;
$start = strtotime("2020-01-01");
$end = strtotime("2020-12-01");
$time->setStartTime($start);
$time->setEndTime($end);
In the class for the TimeRange it shows they simply must be timestamps
class Google_Service_MyBusiness_TimeRange extends \Google_Model
{
protected $internal_gapi_mappings = array( );
/* #params Unix Timestamps */
private $endTime;
private $startTime;
However... I was looking at this.
https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Timestamp
And it shows that you have to pass something on the lines of Timestamp(seconds, nanos).
So it seems like google wants an array of the seconds, and the nano seconds??
Heres other docs to help
https://developers.google.com/my-business/reference/rpc/google.mybusiness.v4#google.mybusiness.v4.TimeRange
Anyone run into this problem?
The documentation you link to says:
Range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
Suggesting that you should use a similar format.
$time = new \Google_Service_MyBusiness_TimeRange;
$start = \DateTime::createFromFormat(
"y-m-d H:i:s",
"2020-01-01 00:00:00",
new \DateTimeZone("UTC")
)
->format("Y-m-d\TH:i:s\Z");
$end = \DateTime::createFromFormat(
"y-m-d H:i:s",
"2020-11-30 23:59:59",
new \DateTimeZone("UTC")
)
->format("Y-m-d\TH:i:s\Z");
$time->setStartTime($start);
$time->setEndTime($end);
I wasn't able to find much about this library online, but what little there is does follow this format. "Z" at the end indicates UTC, and I've hard-coded it in my example. It should be able to get replaced with your local timezone, but you may have to try perhaps "O" or "P" in the format string.
Here is some working code:
Note, $startDate and $endDate are just strings passed in from a jQuery calendar, ex "12/27/2020".
The key here is to use DATE_ATOM, which produces a timestamp in the format 2020-12-27T13:22:12+00:00
$gmbStartDate = date(DATE_ATOM, strtotime($startDate . " 12:01 AM "));
$gmbEndDate = date(DATE_ATOM, strtotime($endDate . " 11:59 PM "));
$time = new Google_Service_MyBusiness_TimeRange();
$time->setStartTime($gmbStartDate);
$time->setEndTime($gmbEndDate);
$basicMetricsRequest->setTimeRange($time);
Note that the timestamps are expressed as UTC, so in this example, the insights may be slightly off based on the time zone for the business. If you want to get the insights for your time zone, you'll have to add/subtract the appropriate number of seconds for your timezone.
The date to be checked is as follows :
$submission_date = 12-25-2014; //The date in mm-dd-yyyy format that is to be tested against today's date
Now I want to echo the error message since the date contained in a variable $submission_date is a future date.
How should I do this efficiently and effectively using PHP?
Thanks in advance.
Many ways to do this (use DateTime::createFromFormat() to control exact format of input dates, for example) but perhaps the simplest that suits the example is:
$isFuture = (strtotime($submission_date) > strtotime($_POST['current_date']))
Note that OP changed the question. If desired date to test against is not in $_POST array, just replace strtotime($_POST['current_date']) with time() to use current system time.
To compare against current date, disregarding time of day, use:
$today = new DateTime(date("Y-m-d"));
// $today = new DateTime("today"); // better solution courtesy of Glavić
// see http://php.net/manual/en/datetime.formats.relative.php for more info
$today_timestamp = $today->getTimestamp();
If posted format is in m-d-Y, then you cannot convert it to unix timestamp directly with strtotime() function, because it will return false.
If you need to use strtotime() then change the input format to m/d/Y by simple str_replace().
On the other hand, you could use DateTime class, where you can directly compare objects:
$submission_date = DateTime::createFromFormat('!m-d-Y', $submission_date);
$today_date = new DateTime('today');
if ($submission_date > $today_date) {
echo "submission_date is in the future\n";
}
demo
With PHP DateTime you can check whether the input date is future or old w.r.to the todate.
$submission_date = DateTime::createFromFormat('m-d-Y', $submission_date);
$submission_date = $submission_date->format('Y-m-d');
$current_date = new DateTime('today');
$current_date = $current_date->format('Y-m-d');
if ($submission_date > $current_date)
{
echo "Future date";
}
else
{
echo "Old date";
}
I have a PHP date in a database, for example 8th August 2011. I have this date in a strtotime() format so I can display it as I please.
I need to adjust this date to make it 8th August 2013 (current year). What is the best way of doing this? So far, I've been racking my brains but to no avail.
Some of the answers you have so far have missed the point that you want to update any given date to the current year and have concentrated on turning 2011 into 2013, excluding the accepted answer. However, I feel that examples using the DateTime classes are always of use in these cases.
The accepted answer will result in a Notice:-
Notice: A non well formed numeric value encountered......
if your supplied date is the 29th February on a Leapyear, although it should still give the correct result.
Here is a generic function that will take any valid date and return the same date in the current year:-
/**
* #param String $dateString
* #return DateTime
*/
function updateDate($dateString){
$suppliedDate = new \DateTime($dateString);
$currentYear = (int)(new \DateTime())->format('Y');
return (new \DateTime())->setDate($currentYear, (int)$suppliedDate->format('m'), (int)$suppliedDate->format('d'));
}
For example:-
var_dump(updateDate('8th August 2011'));
See it working here and see the PHP manual for more information on the DateTime classes.
You don't say how you want to use the updated date, but DateTime is flexible enough to allow you to do with it as you wish. I would draw your attention to the DateTime::format() method as being particularly useful.
strtotime( date( 'd M ', $originaleDate ) . date( 'Y' ) );
This takes the day and month of the original time, adds the current year, and converts it to the new date.
You can also add the amount of seconds you want to add to the original timestamp. For 2 years this would be 63 113 852 seconds.
You could retrieve the timestamp of the same date two years later with strtotime() first parameter and then convert it in the format you want to display.
<?php
$date = "11/08/2011";
$time = strtotime($date);
$time_future = strtotime("+2 years", $time);
$future = date("d/m/Y", $time_future);
echo "NEW DATE : " . $future;
?>
You can for instance output it like this:
date('2013-m-d', strtotime($myTime))
Just like that... or use
$year = date('Y');
$myMonthDay = date('m-d', strtotime($myTime));
echo $year . '-' . $myMonthDay;
Use the date modify function Like this
$date = new DateTime('2011-08-08');
$date->modify('+2 years');
echo $date->format('Y-m-d') . "\n";
//will give "2013-08-08"
thanks for reading.
Just need to know how i convert datetime gotten from my sql tables in gmtime to datetime in user timezone.
the following is my code but doesn't seem to work..
//WHERE $post_arr[5] is date from sql
$user_date=convert_date_for_user($post_arr[5]);
function convert_date_for_user($date_time){
$user = JFactory::getUser();
$db = JFactory::getDBO();
$timezone=$user->getParam('timezone');
echo $tz_offset;
$user_date = JFactory::getDate($date_time,$timezone);
$user_date_str = $user_date->toUnix(true);
return $user_date_str;
}
It converts but I'm getting all the wrong time from the above code.
The simplest way to do it:
$useUserTimeZone = true;
JHtml::date($sqlGmtTimestamp , 'D F n, Y', $useUserTimeZone);
$sqlGmtTimestamp takes GMT timestamp/datetime
$useUserTimeZone is a flag to use user's timezone, otherwise server's timezone will be used.
more details here: http://docs.joomla.org/API16:JHtml/date
You don't specify your Joomla version but, did you try Joomla's JDate class directly?
// Get the User and their timezone
$user = JFactory::getUser();
$timeZone = $user->getParam('timezone', 'UTC');
// Create JDate object set to now in the users timezone.
$myDate = JDate::getInstance('now', $timeZone);
// Gets the date as UNIX time stamp.
$myDate->toUnix():
// For your example using a method
function convert_date_for_user($date_time)
{
// Get the User and their timezone
$user = JFactory::getUser();
$timeZone = $user->getParam('timezone', 'UTC');
// Create JDate object set to now in the users timezone.
$myDate = JDate::getInstance($date_time, $timeZone);
return $myDate->toUnix();
}
This is the function that works for me:-
//WHERE date_time is the format of the date taken directly from database(ie: 0000-00-00 00:00:00)
function convert_time_zone($date_time){
$user =& JFactory::getUser();
$db = JFactory::getDBO();
$timezone=$user->getParam('timezone','UTC');
$time_object = new DateTime($date_time, new DateTimeZone('UTC'));
$time_object->setTimezone(new DateTimeZone($timezone));
$user_datetime=$time_object->format('Y-m-d H:i:s');
//SELECT ONLY 1 line below
return $user_datetime; //WOULD RETURN DATETIME IN 0000-00-00 00:00:00
//OR
return $time_object->getTimestamp(); //WOULD RETURN DATETIME IN UNIX TIMESTAMP
}
Its a little out of the way as i was hoping to use functions included in the joomla API to do it. If anyone could provide a better solution please do. and i select it as the right answer.
With Joomla 2.5+ (i think), you can use the following code
echo JHtml::_('date', $input, $format, $tz, $gregorian);
$input can be one of the following values:
"now" for the current time (DEFAULT)
A date/time string in a format accepted by date()
$format can be one of the following values:
NULL to use the default locale based format (DEFAULT)
A date format specification string (see http://php.net/manual/en/function.date.php)
$tz can be one of the following values:
TRUE to use the user's time zone (DEFAULT). Note: If the user's time zone is not set then the global config time zone is used.
FALSE to use global config time zone
NULL for no conversion
A timezone string (eg: "America/Los_Angeles", see http://php.net/manual/en/timezones.php)
$gregorian can be one of the following values:
TRUE to use Gregorian calendar
FALSE to NOT use Gregorian calendar (DEFAULT)
Having tried all the given possible solutions here and not getting the date in the user's timezone (Joomla! v.3.9.14), here's my (proven) solution:
$oUser_TZ = JFactory::getUser()->getTimezone();
$aUser_tz = (array)$oUser_TZ; // almost sure this step is not that necessary
$full_date = JFactory::getDate('now', $aUser_tz['timezone']); // pretty sure $oUser_tz->timezone will work
// I had try to use $full_date->Format('Y-m-d H:i:s') but it was giving me the non-converted-to-wanted-timezone date, so
$date_converted = substr($full_date, 0, 19);
date_converted gives me the date in format Y-m-d H:i:s and in the wanted timezone.
Try This:
$date = JFactory::getDate(); // now - 2014-03-11 08:45:22
$date->setOffset(8); // UTC+8
echo $date->toMySQL(); // wrong - 2014-03-11 08:45:22
echo '<br />';
echo $date->toFormat(); // right - 2014-03-11 16:45:22
JHtml::date($post_arr[5]);
If you want a different format, use the second parameter:
JHtml::date($post_arr[5], DateTime::RFC2822);
Which is equivalent to:
1. Create a JDate object with an UTC date read from the database
2. Get the correct Time Zone in Jomla Global Configuration and User Configuration
3. Call setTimeZone() to convert your JDate object to user local time
4. Call format() to format the JDate object as a well formatted string