Timezone conversion in PHP with DateTime - php

I found some solutions recently and decided to go with this one so I created following method within one of my classes:
public static function date($format, $time = false, $from_timezone = false, $to_timezone = false) {
if (!$time) {
$time = time();
}
if (($from_timezone === $to_timezone) || (!$from_timezone || !$to_timezone)) {
return date($format, $time);
}
$from_tz = new DateTimeZone($from_timezone);
$to_tz = new DateTimeZone($to_timezone);
$dt = new DateTime();
$dt->setTimezone($from_tz);
$dt->setTimestamp($time);
$offset = $to_tz->getOffset($dt);
return date($format, $dt->format('U') + $offset);
}
Then I did a simple test - I converted datetime to some other timezone, and then convert the result back to the original timezone with expectations to get the original datetime.
$format = 'Y-m-d H:i:s';
$initialtime = '2013-06-13 12:00:00';
echo $initialtime;
echo '<br/>';
$convtime = TimezoneLib::date($format, strtotime($initialtime), 'Canada/Atlantic', 'Europe/Prague');
echo $convtime;
echo '<br/>';
echo TimezoneLib::date($format, strtotime($convtime), 'Europe/Prague', 'Canada/Atlantic');
die();
This is the output
2013-06-13 12:00:00 // Original
2013-06-13 14:00:00 // Converted
2013-06-13 11:00:00 // Converted to original timezone
Why dont they match? What am I missing? Thank you.
UPDATE
I am still unable to get matching dates even after removing strtotime. I found out that default timezone also affected DateTime objects. I came up with this:
<?php
class TimezoneLib {
public static $defaultSystemTimezone;
public static function init() {
self::$defaultSystemTimezone = date_default_timezone_get();
}
public static function date($format, $time = false, $from_timezone = false, $to_timezone = false) {
self::switchSystemTimezone($from_timezone);
if (!$time) {
$time = time();
}
if (($from_timezone === $to_timezone) || (!$from_timezone || !$to_timezone)) {
return date($format, $time);
}
$from_tz = new DateTimeZone($from_timezone);
$to_tz = new DateTimeZone($to_timezone);
$dt = new DateTime($time, $from_tz);
self::switchSystemTimezone($to_timezone);
$offset = $to_tz->getOffset($dt);
$convertedDate = date($format, $dt->format('U') + $offset);
self::restoreSystemTimezone();
return $convertedDate;
}
public static function switchSystemTimezone($timezone_identifier) {
return date_default_timezone_set($timezone_identifier);
}
public static function restoreSystemTimezone() {
return date_default_timezone_set(self::$defaultSystemTimezone);
}
}
TimezoneLib::init();
$format = 'Y-m-d H:i:s';
$initialtime = '2013-06-13 12:00:00';
echo $initialtime;
echo '<br/>';
$convtime = TimezoneLib::date($format, $initialtime, 'Canada/Atlantic', 'Europe/Prague');
echo $convtime;
echo '<br/>';
echo TimezoneLib::date($format, $convtime, 'Europe/Prague', 'Canada/Atlantic');
die();
With following output
2013-06-13 12:00:00
2013-06-13 19:00:00
2013-06-13 11:00:00

Create a new DateTime object instead than using strtotime:
$date = new DateTime('your_date_here', DateTimeZone object here);

Related

Retrieve date format and parse if needed in PHP

I've created this function when retrieving a date from database and echo in Italian format to screen:
function get_data_ita($date) {
if ($date == "")
return "";
$d = new DateTime($date);
return $d->format('d/m/Y');
}
where $date is mysql format like: 2017-12-31 14:00:00
Now, if I pass a correct format like: 2017-12-31 14:00:00 the function works.
But sometimes I need to use the SAME function, passing an already formatted date like: 30/12/2017. In this case, i get parsing error of course.
How can I check if date passed is already in Italian format, and if yes return the untouched date, if not, parse the date?
I need a function like:
function get_data_ita($date) {
if ( $date== ALREADY_IN_ITALIAN_FORMAT )
return $date;
if ($date == "")
return "";
$d = new DateTime($date);
return $d->format('d/m/Y');
}
echo get_data_ita("30/12/2017");
echo get_data_ita("2017-12-31 14:00:00");
ECHO:
30/12/2017
31/12/2017
UPDATE: I found solution myself:
function validateDate($date, $format = 'Y-m-d')
{
$d = DateTime::createFromFormat($format, $date);
return $d && $d->format($format) == $date;
}
function get_data_ita($datetime_db) {
if ( validateDate($datetime_db, 'd/m/Y') ) {
return $datetime_db;
}
if ($datetime_db == "")
return "";
$date = new DateTime($datetime_db);
return $date->format('d/m/Y');
}
Replace / to -
<?php
function get_data_ita($date) {
if ($date == ""){
return "";
}
$date = str_replace('/','-',$date);
$d = new DateTime($date);
return $d->format('d/m/Y');
}
echo get_data_ita("30/12/2017");
echo "\n";
echo get_data_ita("2017-12-31 14:00:00");
?>
Check demo : https://eval.in/918149
Strtotime returns false if the date is not a valid date format.
This works for your inputs but not if there are other date formats.
function get_data_ita($date) {
if ($date == "") return "";
If(strtotime($date) !== False){
$d = new DateTime($date);
}Else{
$d = DateTime::createFromFormat('d/m/Y', $date);
}
return $d->format('d/m/Y');
}
echo get_data_ita("30/12/2017");
echo get_data_ita("2017-12-31 14:00:00");
https://3v4l.org/kt5Vg

Calculating the php current time by timezone

Background
I am making some updated to a PHP application that is very old. In the application there was an error being thrown because the use of a depreciated function mktime(). I updated this function across the application with time() instead. Once I did this I noticed that when the local time for a user which is calculated by their zip code is displayed, it is one hour behind the actual local time.
I have tracked the time calculation to a function which is below. The time is passed into the value of, $client["localtime"]
Example Code
if (isset($time) && $time) {
$utc_str = gmdate("M d Y H:i:s", time());
$utc = strtotime($utc_str);
if (isset($tznames[ $time["timezone"] ])) {
$client["timezone"] = $tznames[ $time["timezone"] ];
} else {
$client["timezone"] = "Unknown";
}
if ($time["daylightsavings"] == "Y" && date("I")) {
$time["timezone"]--;
}
$client["localtime"] = date("g:ia", $utc - ($time["timezone"] * 3600));
} else {
$client["localtime"] = "Unknown";
$client["timezone"] = "Unknown";
}
Question
Why is this showing the local time for the client's timezone behind by 1 hour and what must I do to fix it?
if (isset($time) && $time) {
$utc_str = gmdate("M d Y H:i:s", time());
$utc = strtotime($utc_str);
if (isset($tznames[$time["timezone"]])) { $client["timezone"] = $tznames[$time["timezone"]]; }
else { $client["timezone"] = "Unknown"; }
if ($time["daylightsavings"] == "Y" && date("I")) { $time["timezone"]--; }
// print_r(($time["timezone"] * 3600).",".$client["timezone"].",".$time["timezone"].",".$utc_str.",".$utc);
$client["localtime"] = date("g:ia", $utc - ($time["timezone"] * 3600 - 3600));
} else { $client["localtime"] = "Unknown";
$client["timezone"] = "Unknown";}
Check the above code I have subtracted the 3600 from so that it show 1hour late please check if it will work
you can use this function
function convertTimeByTimezone($datetime,$timezone='Asia/Kolkata') {
$given = new DateTime($datetime, new DateTimeZone("UTC"));
$given->setTimezone(new DateTimeZone($timezone));
$output = $given->format("Y-m-d H:i:s");
return $output;
}
You can use this code:
$date = new DateTime("now", new DateTimeZone('Australia/Adelaide'));
echo 'Australia/Adelaide: '.$date->format('Y-m-d H:i:s');
$date1 = new DateTime("now", new DateTimeZone('America/Chicago'));
echo 'America/Chicago: '. $date1->format('Y-m-d H:i:s');

Can't return the current date

I've made a function to get the current date with a custom date format, this is the code:
function getTimestamp($dateFormat)
{
$dateFormat = "d-m-Y G:i:s.u";
$originalTime = microtime(true);
$micro = sprintf("%06d", ($originalTime - floor($originalTime)) * 1000000);
$date = new DateTime(date('d-m-Y H:i:s.'.$micro, $originalTime));
echo $date->format($dateFormat);
return $date->format($dateFormat);
}
the date returned is this:
05-02-2016 0:28:05.839051
but should be this instead:
05-02-2016 0:09:30.839051
what I did wrong?
Use this, it should solve your problem, set locale.
function getTimestamp($dateFormat)
{
$dateFormat = "d-m-Y G:i:s.u";
$originalTime = microtime(true);
$micro = sprintf("%06d", ($originalTime - floor($originalTime)) * 1000000);
$date = new DateTime(date('d-m-Y H:i:s.'.$micro, $originalTime));
$date->setTimezone(new DateTimeZone('Europe/Rome'));
echo $date->format($dateFormat);
return $date->format($dateFormat);
}
did modification to set time zone.
Thanks
Amit

check upcomming birthday in a week 2 week or in a month using php

how to check is birthday is in this week,2week,or in month i have used below code to check but it return wrong calculation.
public function CountDown($birthdate, $days=7)
{
list($y,$d,$m) = explode('/',$birthdate);
$today = time();
$event = mktime(0,0,0,$m,$d,$y);
$apart = $event - $today;
if ($apart >= -86400)
{
$myevent = $event;
}
else
{
$myevent = mktime(09,0,0,$m,$d,$y);
}
$countdown = round(($myevent - $today)/86400);
if ($countdown <= $days)
{
return true;
}
return false;
}
Try this:
function CountDown($birthdate, $days=7)
{
# create today DateTime object
$td = new DateTime('today');
# create birth DateTime object, from format Y/d/m
$bd = DateTime::createFromFormat('!Y/d/m', $birthdate);
# set current year to birthdate
$bd->setDate($td->format('Y'), $bd->format('m'), $bd->format('d'));
# if birthdate is still in the past, set it to new year
if ($td > $bd) $bd->modify('+1 year');
# calculate difference in days
$countdown = $bd->diff($td)->days;
# return true if day difference is within your range
return $countdown <= $days;
}
demo
This worked for me
class Birthday{
public function CountDown($birthdate, $days=7)
{
list($y,$d,$m) = explode('/',$birthdate);
$today = time();
$event = mktime(0,0,0,$m,$d,$y);
$apart = $event - $today;
if ($apart >= -86400)
{
$myevent = $event;
}
else
{
$myevent = mktime(09,0,0,$m,$d);
}
$countdown = round(($myevent - $today)/86400);
if (($countdown <= $days))
{
return true;
}
return false;
}
}
$bday = new Birthday;
$count = $bday->CountDown("1969/16/11"); //today is 2014/14/11
var_dump($count); //returns true.
I just removed the year from the mktime() in $myevent. This changed the answers to be accurate.
The other way that it was being done made $countdown to be a huge negative number.

Daylight Saving Time (DST) in CakePHP

I'm creating a web application using cakephp 1.2.6. There is a functionality that I need to save the time that user is entered in GMT format. I'm using below method to do this.
function convertDateTimeToGMT($dateTimeStr,$fromTimeZone, $format = 'Y-m-d H:i:s') {
if (empty($dateTimeStr))
return $dateTimeStr;
else if (empty($fromTimeZone))
return $dateTimeStr;
else {
// Inverse the + or minus. Decimal value should be passed
//$timeHelper = new TimeHelper();
$newTZ = -1 * $fromTimeZone;
return $this->format($format, $dateTimeStr, null, $newTZ) ;
}
}
function format($format = 'd-m-Y', $date, $invalid = false, $userOffset = null) {
$date = $this->fromString($date, $userOffset);
if ($date === false && $invalid !== false) {
return $invalid;
}
return date($format, $date);
}
function fromString($dateString, $userOffset = null) {
if (empty($dateString)) {
return false;
}
if (is_int($dateString) || is_numeric($dateString)) {
$date = intval($dateString);
} else {
$date = strtotime($dateString);
}
if ($userOffset !== null) {
return $this->convert($date, $userOffset);
}
return $date;
}
function convert($serverTime, $userOffset) {
$serverOffset = $this->serverOffset();
$gmtTime = $serverTime - $serverOffset;
$userTime = $gmtTime + $userOffset * (60*60);
return $userTime;
}
convertDateTimeToGMT($dateTimeStr,$fromTimeZone, $format = 'Y-m-d H:i:s') is the method that I'm calling in my code to pass the date time and time zone. I have a combo box of time zones and if user select time zone as "Pacific" it will pass the -8 as the value of $fromTimeZone. But because of the DST this can be changed.
So is there any way in cakephp to find the up to date time zone values automatically and convert the time to GMT?
Once you know the timezone of the user you can get its offset as follows:
$est_tz = new DateTimeZone('America/New_York');
$d = new DateTime("now", $est_tz);
$offset = $est_tz->getOffset($d);

Categories