Edit: This function does work in PHP, it isn't working for me within the CakePHP framework which I didn't think relevant when originally posting.
This function takes a string formatted date/time and a local timezone (e.g. 'America/New_York'). It supposed to return time converted to the local timezone. Currently, it does not change.
I pass it: '2011-01-16 04:57:00', 'America/New_York' and I get back the same time I pass in.
function getLocalfromGMT($datetime_gmt, $local_timezone){
$ts_gmt = strtotime($datetime_gmt.' GMT');
$tz = getenv('TZ');
// next two lines seem to do no conversion
putenv("TZ=$local_timezone");
$ret = date('Y-m-j H:i:s',$ts_gmt);
putenv("TZ=$tz");
return $ret;
}
I've seen the references to the new methods for default_timezone_get/set. I'm not currently interested in using that method because I'd like this code to work with older versions of PHP.
Apparently, in CakePHP, if you're using date_default_timezone_set() in your config file, which we are, the TZ environment variable setting method does not work. So, the new version, which seems to work perfectly is:
function __getTimezone(){
if(function_exists('date_default_timezone_get')){
return date_default_timezone_get();
}else{
return getenv('TZ');
}
}
function __setTimezone($tz){
if(function_exists('date_default_timezone_set')){
date_default_timezone_set($tz);
}else{
putenv('TZ='.$tz);
}
}
// pass datetime_utc in a standard format that strtotime() will accept
// pass local_timezone as a string like "America/New_York"
// Local time is returned in YYYY-MM-DD HH:MM:SS format
function getLocalfromUTC($datetime_utc, $local_timezone){
$ts_utc = strtotime($datetime_utc.' GMT');
$tz = $this->__getTimezone();
$this->__setTimezone($local_timezone);
$ret = date('Y-m-j H:i:s',$ts_utc);
$this->__setTimezone($tz);
return $ret;
}
how about this
<?php
// I am using the convention (assumption) of "07/04/2004 14:45"
$processdate = "07/04/2004 14:45";
// gmttolocal is a function
// i am passing it 2 parameters:
// 1)the date in the above format and
// 2)time difference as a number; -5 in our case (GMT to CDT)
echo gmttolocal($processdate,-5);
function gmttolocal($mydate,$mydifference)
{
// trying to seperate date and time
$datetime = explode(" ",$mydate);
// trying to seperate different elements in a date
$dateexplode = explode("/",$datetime[0]);
// trying to seperate different elements in time
$timeexplode = explode(":",$datetime[1]);
// getting the unix datetime stamp
$unixdatetime = mktime($timeexplode[0]+$mydifference,$timeexplode[1],0,$dateexplode[0],$dateexplode[1],$dateexplode[2]);
// return the local date
return date("m/d/Y H:i",$unixdatetime));
}
?>
Related
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
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
I need a method that gets two strings that represents a DateTime (in the MySql syntax) and returns the time difference between them.
Then I need to compare that time to 3 seconds so I could block a Brute Force attack on my server.
I've messed a lot with Google and I managed to get the string representation of the DateTime object, but I can't manage to convert and compare them.
$time_str1 = '2011-09-10 19:59:23'; // first string datetime from DB
$time_str2 = '2011-09-10 19:59:24'; // second string datetime from DB
// first DateTime object created based on the MySQL datetime format
$dt1 = DateTime::createFromFormat('Y-m-d H:i:s', $time_str1);
// second DateTime object created based on the MySQL datetime format
$dt2 = DateTime::createFromFormat('Y-m-d H:i:s', $time_str2);
// difference comparison to check if at least 3 seconds have passed
if ( ($dt2->format('U') - $dt1->format('U')) > 3) {
echo 'Ok, no brute force'; // yes, three seconds have passed
} else{
echo 'We got you newbie'; // nope, three second haven't passed
}
$diffInSeconds = $dateTimeLater->format('U') - $dateTimeFirst->format('U');
strtotime( $timeStr ) which will convert to the amount of seconds since epoch http://en.wikipedia.org/wiki/Unix_epoch . Then you can just use standard mathematical operators. Be warned, strtotime can be inaccurate sometimes. To convert back, date("m-d-Y H:i:s", $time)
Heres an alternative method using a session, no need to query a db for a timestamp:
<?php
session_start();
function post_check($limit){
//Check for first time
if(isset($_SESSION['post_check'])){
//Check for count on failed
if(isset($_SESSION['post_check_count'])){
//If fail count is more then 3 block till user closes down browser
if($_SESSION['post_check_count']>$limit){
die('Too many requsets to the server, please close down your browesr and try again.');
}
}else{
//Set for count on failed
$_SESSION['post_check_count']=0;
}
//Check (time-limit) against timestamp held in session
if(($_SESSION['post_check']+$limit)<=time()){
//Update timestamp
$_SESSION['post_check']=time();
//Ok
return true;
}else{
//Update Fail count
$_SESSION['post_check_count']++;
//Fail
return false;
}
}else{
//Set for first time
$_SESSION['post_check']=time();
return true;
}
}
//Pretty self explanitry here
if(post_check('3')===true){
echo 'Allowed: handle post stuff here';
}else{
echo'Too many requests within given time limit do nothing';
}
?>
On the MySQL side:
SELECT UNIX_TIMESTAMP(my_time) FROM my_table
On the PHP side, you then have UNIX timestamps in seconds, which you can compare.
I have a cakePHP application that is pulling data from two different databases, which store dates and times in their data from different timezones. One database's timezone is Europe/Berlin, and the other's is Australia/Sydney. To make things more complicated, the application is hosted on a server in the US, and times must be presented to the end user in their local timezone.
It's easy enough to tell which database I have to access, and so I set the appropriate timezone (using date_default_timezone_set()) in my beforeFind so that the query is sent with a date in the correct timezone.
My problem is then converting the dates in the afterFind to the timezone of the user. I'm passing this timezone through as a named parameter, and to access this in the model I'm using Configure::write() and Configure.read(). This works fine.
The problem is that it seems to be applying my timezone conversion multiple times. For example, if I'm querying the Australia/Sydney database from Australia/Perth the time should be two hours behind, but it's coming out as six hours behind. I tried echoing the times from my function before and after converting them, and each conversion was working correctly, but it was converting the times more than once, and I can't figure out why.
The methods I am currently using (in my AppModel) to convert from one timezone to another is as follows:
function afterFind($results, $primary){
// Only bother converting if the local timezone is set.
if(Configure::read('TIMEZONE'))
$this->replaceDateRecursive($results);
return $results;
}
function replaceDateRecursive(&$results){
$local_timezone = Configure::read('TIMEZONE');
foreach($results as $key => &$value){
if(is_array($value)){
$this->replaceDateRecursive($value);
}
else if(strtotime($value) !== false){
$from_timezone = 'Europe/Berlin';
if(/* using the Australia/Sydney database */)
$from_timezone = 'Australia/Sydney';
$value = $this->convertDate($value, $from_timezone, $local_timezone, 'Y-m-d H:i:s');
}
}
}
function convertDate($value, $from_timezone, $to_timezone, $format = 'Y-m-d H:i:s'){
date_default_timezone_set($from_timezone);
$value = date('Y-m-d H:i:s e', strtotime($value));
date_default_timezone_set($to_timezone);
$value = date($format, strtotime($value));
return $value;
}
So does anyone have any ideas as to why the conversion is happening multiple times? Or does anyone have a better method for converting the dates? I'm obviously doing something wrong, I'm just stuck as to what that is.
I worked out a solution. I didn't really understand what the $primary parameter in the afterFind was for until now. So to fix my code above, all I have to do is change the if in the afterFind to the following:
function afterFind($results, $primary){
// Only bother converting if these are the primary results and the local timezone is set.
if($primary && Configure::read('TIMEZONE'))
$this->replaceDateRecursive($results);
return $results;
}
As a side note, I am no longer using the date_default_timezone_set() function to do the timezone conversion, either. My convertDate function has changed as follows:
function convertDate($value, $from_timezone, $to_timezone, $format = 'Y-m-d H:i:s'){
$dateTime = new DateTime($value, new DateTimeZone($from_timezone));
$dateTime->setTimezone(new DateTimeZone($to_timezone));
$value = $dateTime->format($format);
return $value;
}
What I want to do is make a script on the server read a text file, sort it, then output it to a javascript object (probably via JSON). The text file in question looks something like this:
13/09/2009,17/09/2009,Arbitrary dates
14/09/2009,18/09/2009,Some random comment
14/09/2010,18/12/2010,A comment to the dates
14/09/2010,18/09/2010,A subset of another date
14/09/2001,18/09/2002,The oldest date
The php to handle the filereading looks like this:
function loadDates()
{
$dateFile = fopen("dates.txt", "rt");
$dates = array();
if($dateFile)
{
flock($dateFile,LOCK_SH);
$i = 0;
while(!feof($dateFile))
{
$text = fgets($dateFile);
if($text !== FALSE)
{
$i++;
$arr = explode(",",$text,3);
//actual storage
$dates[$i]['start'] = strtotime($arr[0]);
$dates[$i]['end'] = strtotime($arr[1]);
$dates[$i]['comment'] = $arr[2];
}
}
fclose($dateFile);
//sort by start date, then by end date
foreach($dates as $key => $item)
{
$start[$key] = $item['start'];
$end[$key] = $item['end'];
}
array_multisort($start, SORT_ASC, $end, SORT_ASC, $dates);
return $dates;
}
else
{
return FALSE;
}
}
However, that stores unix timesstamps in the start and end dates. I would use the DateTime class, but I'm currently restricted to PHP 4.4. Ideally, I'd like to store the dates in a format that:
Can be compared numerically
Are human readable (allowing human editing of dates.txt)
Are consistently formatted (ie "01-01-1900" is converted to "01/01/1900")
Can be converted to a javascript Date object
How would I go about storing the dates so they satify these restrictions?
The safest is to use UNIX timestamps
in javascript, you can use
var mydate = new Date();
mydate.getTime(); //timestamp
mydate.setTime(your_timestamp); //set using timestamp
in php the date function takes the timestamp as second parameter.
see http://jp.php.net/manual/en/function.date.php
and https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Date
EDIT:
Also see strftime http://jp.php.net/manual/en/function.strftime.php
EDIT:
Note: the javascript function takes milliseconds, and the php functions use seconds. divide the output of the javascript by 1000 or use something like the following:
Date.prototype.getTimeInSeconds = function() {
return this.getTime()/1000;
}
var mydate = new Date();
mydate.getTimeInSeconds(); //PHP-compatible timestamp
Store the dates thus:
19991231 = Dec. 31, 1999
20000704 = July 4, 2000
Human readable, definitely sortable, and you can make a JavaScript function for the conversion.
I will provide you with a hack from my deranged mind:
(this assumes that x is that date in yyyymmdd form)
new Date((x-(x%10000))%9999,(((x%10000)-(x%100))%99)-1,x%100)