How to get human friendly format time zone offset (PHP) - php

Help me to decide this task, please. (PHP, Symfony)
What I have:
List of time zone like
"Europe/Riga"
"Europe/Rome"
"Europe/Samara"
"Europe/San_Marino"
"Europe/Sarajevo"
In result I want to see:
(+00:00) Riga
(+01:30) Rome
(+03:00) Samara
(-01:00) San_Marino
(+05:00) Sarajevo
What I did:
$timeZoneIdentifierList = DateTimeZone::listIdentifiers();
$timeZoneUtc = new DateTimeZone('UTC');
$nowByUtc = new DateTime('now', $timeZoneUtc);
foreach ($timeZoneIdentifierList as $timeZoneIdentifier) {
$dateTimezoneItem = new DateTimeZone($timeZoneIdentifier);
$timeZone = $dateTimezoneItem->getOffset($nowByUtc);
$humanFriendlyOffset = $timeZone / 3600;
}
And if I dump $humanFriendlyOffset I get only digital value like this: 0, 1, -7, 2, 1.5
Question:
Is something prepared method in PHP/Symfony to convert
1 -> +01:00,
-7 -> -07:00,
2 -> +02:00,
1.5 -> +01:30
May be exist more easy way?

This solution creates a new DateTime object for each time zone.
$tzArr = ["Europe/Riga",
"Europe/Rome",
"Europe/Samara",
"Europe/San_Marino",
"Europe/Sarajevo",
"UTC"];
foreach($tzArr as $tz){
$dt = date_create('Now',new DateTimeZone($tz));
$formatTz = $dt->format('\(P\) e');
echo $formatTz."<br>\n";
}
Output:
(+02:00) Europe/Riga
(+01:00) Europe/Rome
(+04:00) Europe/Samara
(+01:00) Europe/San_Marino
(+01:00) Europe/Sarajevo
(+00:00) UTC
With a preg_replace the continent can be hidden and an output can be achieved exactly as desired.
foreach($tzArr as $tz){
$dt = date_create('Now',new DateTimeZone($tz));
$loc = preg_replace('~^[a-z]+/~i','', $dt->format('e'));
$formatTz = $dt->format('\(P\) ').$loc;
echo $formatTz."<br>\n";
}
Output:
(+02:00) Riga
(+01:00) Rome
(+04:00) Samara
(+01:00) San_Marino
(+01:00) Sarajevo
(+00:00) UTC

You can use the P formatter from DateTimeInterface::format to get a friendly timezone offset, but that's on a DateTime object, not a DateTimeZone object. So you could create a DateTime object, then explicitly set its timezone to the one you want, then get its offset. Something like this
$dt = new DateTime();
foreach (DateTimeZone::listIdentifiers() as $tz) {
$dt->setTimeZone(new DateTimeZone($tz));
printf("(%s) %s\n", $dt->format('P'), $tz);
}
Output:
(+00:00) Africa/Abidjan
(+00:00) Africa/Accra
(+03:00) Africa/Addis_Ababa
(+01:00) Africa/Algiers
(+03:00) Africa/Asmara
(+00:00) Africa/Bamako
(+01:00) Africa/Bangui
(+00:00) Africa/Banjul
(+00:00) Africa/Bissau

Related

How to convert datetime from one time to another by timezone abbreviation in PHP

I'm getting date time in below format:
2018-04-13 09:19:53 EDT
this needs to be converted into PST or IST.
I want a function to convert given datetime into required datetime.
function convertdatetimes(datetime,current_timezone_abbrevation,required_timezone_abbrevation)
ex convertdatetimes(2018-04-13 09:19:53,EDT,PDT)
Please help.
Try this:
function convertDateTimes($dateTime, $fromTz, $toTz, $format = 'Y-m-d H:i:s') {
$fromTz = new DateTimeZone($fromTz);
$dateTime = new DateTime($dateTime, $fromTz);
$toTz = new DateTimeZone($toTz);
$dateTime->setTimeZone($toTz);
return $dateTime->format($format);
}
Sample usage:
$dateTime = '2018-04-13 09:19:53';
$fromTz = 'EDT';
$toTz = 'PDT';
echo "Input: $dateTime EDT <br>";
echo 'Output: ', convertDateTimes($dateTime, $fromTz, $toTz), " $toTz";
Output:
Input: 2018-04-13 09:19:53 EDT
Output: 2018-04-13 06:19:53 PDT

Converting UTC to CST in php

I want to convert a UTC time to CST using PHP. After googling I got a function
function date_convert($dt, $tz1, $df1, $tz2, $df2) {
// create DateTime object
$d = DateTime::createFromFormat($df1, $dt, new DateTimeZone($tz1));
// convert timezone
$d->setTimeZone(new DateTimeZone($tz2));
// convert dateformat
return $d->format($df2);
}
echo date_convert('2018-05-29 11:44:00', 'UTC', 'Y-m-d H:i:s', 'CST', 'Y-m-d H:i:s');
The output is
2018-05-29 05:44:00
But when I tried converting 2018-05-29 11:44:00 to UTC using online converter, I got the result as 05/29/2018 6:44 AM, which is 1 hour more than what the function returns.
Can anyone help me to find the correct output? Thanks in advance.
I can't explain it, but it only seems to happen with EST/CST, even with changing it to a D.
$n = new DateTime(); // 'date' => '2018-05-29 09:45:01.000000' America/New_York
$n->setTimeZone(new DateTimeZone('UTC')); // 'date' => '2018-05-29 13:45:01.000000'
$n->setTimeZone(new DateTimeZone('EDT')); // 'date' => '2018-05-29 08:45:01.000000'
But if you use a place instead of a timezone, it works well:
$n->setTimeZone(new DateTimeZone('America/New_York')); // 'date' => '2018-05-29 09:45:37.000000'
$n->setTimeZone(new DateTimeZone('America/Chicago')); // 'date' => '2018-05-29 08:45:37.000000'
I'd suggest using a place such as America/Chicago instead.
Try this;
function date_convert($time, $oldTZ, $newTZ, $format) {
// create old time
$d = new \DateTime($time, new \DateTimeZone($oldTZ));
// convert to new tz
$d->setTimezone(new \DateTimeZone($newTZ));
// output with new format
return $d->format($format);
}
echo date_convert('2018-05-29 11:44:00', 'UTC', 'CST', 'Y-m-d H:i:s');
Output:
2018-05-29 05:44:00
CST is UTC-06, php works well

Creating timestamp for 5/13/2014 # 3pm

I have an application that needs to send a UTC timestamp in order for it to work correctly. In my application a user can have any number of timezones. So if they pick 3pm and their timezone is America/New_York, it is a different 3pm than if it was America/Chicago.
I need to figure out a way to change the date into the right UTC timestamp. I know I can use date_default_timezone_set("UTC")...but I don't think will work correctly.
I think I need to calculate a difference between UTC and regular timezone, but I am not sure. Any advice is welcomes.
date_default_timezone_set("UTC");
echo strtotime('5/13/2014 3:00 PM');
1399993200
date_default_timezone_set("America/New_York");
echo strtotime('5/13/2014 3:00 PM');
1400007600
As you can tell these 2 values are different.
EDIT: Here is what my code looks like. It doesn't seem to work correctly as the application doesn't show the event in the right time.
$previous_timezone = date_default_timezone_get();
date_default_timezone_set("UTC");
$aceroute_schedule = $this->sale_lib->get_send_to_aceroute_schedule();
if (($start_time = strtotime($aceroute_schedule['aceroute_schedule_date']. ' '.$aceroute_schedule['aceroute_schedule_time_start'])) !== FALSE)
{
//Append 000 as as string for 32 bit systems
$start_epoch = $start_time.'000';
$end_epoch = strtotime('+ '.$aceroute_schedule['aceroute_duration'].' minutes', $start_time).'000';
}
else //Default to current time + 1 hour
{
//Append 000 as as string for 32 bit systems
$start_epoch = time().'000';
$end_epoch = strtotime('+1 hour', time()).'000';
}
$event->start_epoch = $start_epoch;
$event->end_epoch = $end_epoch;
Update:
This will now create a DateTime object in the user's DateTimeZone ('America/New_York'). And then it will set that object's timezone to UTC. To get the timestamp (or other string representations of date), use ::format().
# Create NY date
$NY = new DateTimeZone("America/New_York");
$NYdate = new DateTime('5/13/2014 3:00 PM', $NY);
# Set timezone to UTC
$UTC = new DateTimeZone("UTC");
$UTCdate = $NYdate->setTimezone($UTC);
# Get timestamp (PHP 5.2 compatible)
$timezone = $UTCdate->format('U');
var_dump($timezone); // a string containing UNIX timestamp
First I create 2 DateTime objects based off of their respective DateTimeZone objects. Then we can either use OOP ::diff() to get another object containing information about the time difference. Or we can use simple integers representing the difference in seconds from ::getTimestamp.
$date = '5/13/2014 3:00 PM';
# Create NY date
$NY = new DateTimeZone("America/New_York");
$NYdate = new DateTime($date, $NY);
# Create UTC date
$UTC = new DateTimeZone("UTC");
$UTCdate = new DateTime($date, $UTC);
# Find difference object
$diff = $NYdate->diff($UTCdate);
var_dump($diff); // a DateInterval object containing time difference info
# Find difference in seconds
$diff = $NYdate->getTimestamp() - $UTCdate->getTimestamp();
var_dump($diff); // an integer containing time difference in seconds
Links:
DateTimeZone
DateTime
DateInterval
Example in http://www.php.net/manual/en/datetime.settimezone.php
$date = new DateTime('2000-01-01', new DateTimeZone('Pacific/Nauru'));
echo $date->format('Y-m-d H:i:sP') . "\n";
$date->setTimezone(new DateTimeZone('Pacific/Chatham'));
echo $date->format('Y-m-d H:i:sP') . "\n";
The first line creates a DateTIme object, using the timezone Pacific/Nauru.
You can then change the timezone using setTimezone as shown in line 4, and the output will be modified accordingly.
note: the default timezone (if you don't specify it in the 2nd parameter in line 1) is the one set in your php.ini file, which you can modify (at runtime) with date_default_timezone_set("America/New_York")
note2: the 1st parameter in line 1, is equivalent to the 1st parameter of the strtotime function.
note3: the format method takes the same format parameter as date (http://www.php.net/manual/en/function.date.php)

DateTime class if not displaying the correct data

I am using DateTime class for the first time to convert between different time zones.
Here is what I have
$USER_TIME_ZONE = new DateTimeZone('America/Los_Angeles');
$UTC = new DateTimeZone('UTC');
$schedule_date = new DateTime($call['triggerOn'], $USER_TIME_ZONE);
echo $schedule_date->format('m/d/Y h:i A');
$schedule_date = new DateTime($call['triggerOn'], $UTC);
echo $schedule_date->format('m/d/Y h:i A');
Here is how I am going through my result and trying to convert them
foreach ( $activities AS $call){
$USER_TIME_ZONE = new DateTimeZone('America/Los_Angeles');
$UTC = new DateTimeZone('UTC');
$schedule_date = new DateTime($call['triggerOn'], $UTC);
echo $schedule_date->format('m/d/Y h:i A');
}
The following are value for $call['triggerOn']
2013-02-27 18:00:37
2013-02-02 01:11:07
2013-01-10 17:12:14
2013-02-27 22:29:42
2013-02-27 22:28:38
2013-02-25 21:53:12
2013-02-14 14:35:48
2012-12-13 14:03:16
2013-03-04 19:04:20
2013-03-01 18:52:48
2013-03-05 15:46:56
2013-03-11 15:26:17
2013-02-07 18:17:30
2013-03-05 18:04:25
Both of my outputs are the same! I don't understand why. Is there a configuration that I need to do on the server side as I have PHP running on Windows Server 2008 R2.
Thank you for your help and time.
The DateTime::format() method is returning the time in the timezone the data was created in. There's no conversion going on. Thus your output times are going to be the same as your input times regardless of the timezone you pass in. You can verify this by adding an 'e' to the format parameter. You will see that in the first case the timezone is America/Los_Angeles and in the second it is UTC.
You're probably trying to convert the time between timezones, right? In order to do that just create a single new DateTime object in one timezone, call the setTimezone method with the second timezone, and then format the result.
All of this assumes that the $call['triggerOn'] value is neither a timestamp nor a value with the timezone identified. In that case the second parameter of the DateTime constructor is ignored.
Knowing the value of $call['triggerOn'] would help, but would this work:
$USER_TIME_ZONE = 'America/Los_Angeles';
$UTC = 'UTC';
$schedule_date = new DateTime( $call['triggerOn'], $USER_TIME_ZONE );
echo $schedule_date->format( 'm/d/Y h:i A' );
$schedule_date = new DateTime( $call['triggerOn'], $UTC );
echo $schedule_date->format( 'm/d/Y h:i A' );
Basically, instead of creating new DateTime objects to use as parameters for other new DateTime objects, what if you just use the timezone string instead? Does that work?

Convert UTC offset to timezone or date

A head scratcher for you.
I am grabbing geo IP data from IPInfoDB's API and it returns a timezone offset from UTC including DST (if currently reflected).
For example, I live in EST (-5) and currently it's DST, so the geo IP API returns (-04:00) as the offset.
This is wonderful since DST is a freaking headache. But to my surprise, it caused another headache.
I load this data in PHP to be passed via AJAX to the application. I would like to have the live local time of the IP address on the app.
I have that all set perfectly, but I am going crazy trying to figure out how to set the PHP timezone to match the offset so I can just grab the current hours date('H'); and minutes date('i'); to pass to via AJAX.
I am unsure if there is a specific function that can just give me the current hours and minutes based on that offset or if there is a practical way to set the timezone based on the offset (which will have DST already applied if is in effect).
I've been searching and searching Google to find an answer to this, but what I am doing is more specific since DST is already applied.
I found one function on PHP.net that seems to do the trick (it works for my timezone and returns the correct time) although for other timezones such as PST, it's returning 1 hour later than it should be even though the offset is correct (-07:00 with DST).
The timezone returned from the function is Chile/EasterIsland which I have a feeling is the cause. If I could, I would make this only work for the USA, but I do need it to be worldwide.
This is the function I have now. Please excuse the extremely messy code. I have been playing around with tons of things over the last few hours trying to figure out a solution.
Most of the functionality was found online.
function offsetToTZ($offset) {
switch((string) $offset) {
case '-04:30' : return 'America/Caracas'; break;
case '-03:30' : return 'Canada/Newfoundland'; break;
case '+03:30' : return 'Asia/Tehran'; break;
case '+04:30' : return 'Asia/Kabul'; break;
case '+05:30' : return 'Asia/Kolkata'; break;
case '+05:45' : return 'Asia/Kathmandu'; break;
case '+09:30' : return 'Australia/Darwin'; break;
}
$offset = (int) str_replace(array('0',0,':00',00,'30',30,'45',45,':','+'),'', (string) $offset);
$offset = $offset*60*60;
$abbrarray = timezone_abbreviations_list();
foreach ($abbrarray as $abbr) {
foreach($abbr as $city) {
if($city['offset'] == $offset) {
return $city['timezone_id'];
}
}
}
return false;
}
I included the switch/case for certain timezones that are :30 and :45 out there. There may be a way to include that also without the need of the switch/case.
NOTE: The offsets are always returned as such +00:00 or -00:00 from the geo IP API.
I would appreciate any help or a point in the right direction. I'm not very novice with PHP, but offsets are a new story for me. Thanks!
It can be done quite simply, by turning the offset into seconds and passing it to timezone_name_from_abbr:
<?php
$offset = '-7:00';
// Calculate seconds from offset
list($hours, $minutes) = explode(':', $offset);
$seconds = $hours * 60 * 60 + $minutes * 60;
// Get timezone name from seconds
$tz = timezone_name_from_abbr('', $seconds, 1);
// Workaround for bug #44780
if($tz === false) $tz = timezone_name_from_abbr('', $seconds, 0);
// Set timezone
date_default_timezone_set($tz);
echo $tz . ': ' . date('r');
Demo
The third parameter of timezone_name_from_abbr controls whether to adjust for daylight saving time or not.
Bug #44780:
timezone_name_from_abbr() will return false on some time zone
offsets. In particular - Hawaii, which has a -10 from GMT offset, -36000
seconds.
References:
timezone_name_from_abbr
date_default_timezone_set
date
date_default_timezone_set('UTC');
$timezones = array();
foreach (DateTimeZone::listAbbreviations() as $key => $array)
{
$timezones = array_merge($timezones, $array);
}
$utc = new DateTimeZone('UTC');
$timezone_offset = '+02:00'; # 2H
$sign = substr($timezone_offset, 0, 1) == '+'? '': '-';
$offset = substr($timezone_offset, 1, 2) . 'H' . substr($timezone_offset, 4, 2) . 'M';
$operation = $sign == ''? 'add': 'sub';
$start = new DateTime('', $utc);
$date = new DateTime('', $utc);
$date->{$operation}(new DateInterval("PT{$offset}"));
$offset = $start->diff($date)->format('%r') . ($start->diff($date)->h * 3600 + $start->diff($date)->m * 60 + $start->diff($date)->s); # 7200 (2H)
echo $offset, PHP_EOL;
echo $date->format('Y-m-d H:i:s'), PHP_EOL;
foreach($timezones as $timezone)
{
if($timezone['offset'] == $offset)
{
echo $timezone['timezone_id'], PHP_EOL;
}
}
I might have misunderstood you in some parts, but I hope it helps, if you could be more specific, I might be more helpful.
For Chile I get:
-25200 (-7h)
2012-08-07 18:05:24 (current time 2012-08-08 01:05:24)
Chile/EasterIsland
Output of the example above:
7200
2012-08-08 02:49:56
Europe/London
Europe/Belfast
Europe/Gibraltar
Europe/Guernsey
Europe/Isle_of_Man
Europe/Jersey
GB
Africa/Khartoum
Africa/Blantyre
Africa/Bujumbura
Africa/Gaborone
Africa/Harare
Africa/Kigali
Africa/Lubumbashi
Africa/Lusaka
Africa/Maputo
Africa/Windhoek
Europe/Berlin
Africa/Algiers
Africa/Ceuta
Africa/Tripoli
Africa/Tunis
Arctic/Longyearbyen
Atlantic/Jan_Mayen
CET
Europe/Amsterdam
Europe/Andorra
Europe/Athens
Europe/Belgrade
Europe/Bratislava
Europe/Brussels
Europe/Budapest
Europe/Chisinau
Europe/Copenhagen
Europe/Gibraltar
Europe/Kaliningrad
Europe/Kiev
Europe/Lisbon
Europe/Ljubljana
Europe/Luxembourg
Europe/Madrid
Europe/Malta
Europe/Minsk
Europe/Monaco
Europe/Oslo
Europe/Paris
Europe/Podgorica
Europe/Prague
Europe/Riga
Europe/Rome
Europe/San_Marino
Europe/Sarajevo
Europe/Simferopol
Europe/Skopje
Europe/Sofia
Europe/Stockholm
Europe/Tallinn
Europe/Tirane
Europe/Tiraspol
Europe/Uzhgorod
Europe/Vaduz
Europe/Vatican
Europe/Vienna
Europe/Vilnius
Europe/Warsaw
Europe/Zagreb
Europe/Zaporozhye
Europe/Zurich
WET
Europe/Kaliningrad
Europe/Helsinki
Africa/Cairo
Africa/Tripoli
Asia/Amman
Asia/Beirut
Asia/Damascus
Asia/Gaza
Asia/Istanbul
Asia/Nicosia
EET
Europe/Athens
Europe/Bucharest
Europe/Chisinau
Europe/Istanbul
Europe/Kaliningrad
Europe/Kiev
Europe/Mariehamn
Europe/Minsk
Europe/Moscow
Europe/Nicosia
Europe/Riga
Europe/Simferopol
Europe/Sofia
Europe/Tallinn
Europe/Tiraspol
Europe/Uzhgorod
Europe/Vilnius
Europe/Warsaw
Europe/Zaporozhye
Asia/Jerusalem
Asia/Gaza
Asia/Tel_Aviv
MET
Africa/Johannesburg
Africa/Maseru
Africa/Mbabane
Africa/Windhoek
Africa/Windhoek
Africa/Ndjamena
Europe/Lisbon
Europe/Madrid
Europe/Monaco
Europe/Paris
WET
Europe/Luxembourg
Which nails my timezone.
$UTC_offset = '+03:00';
$date = new \DateTime('now', 'UTC');
var_dump($date);
$timezone = new \DateTimeZone(str_replace(':', '', $UTC_offset));
$date->setTimezone($timezone);
var_dump($date);
Results:
class DateTime#205 (3) {
public $date =>
string(26) "2015-01-20 06:00:00.000000"
public $timezone_type =>
int(3)
public $timezone =>
string(3) "UTC"
}
class DateTime#205 (3) {
public $date =>
string(26) "2015-01-20 09:00:00.000000"
public $timezone_type =>
int(1)
public $timezone =>
string(6) "+03:00"
}
It is unadvised to map time zone offsets back to a time zone identifier. Many time zones share the same offset.
Even within a single country, this is problematic. Consider that in the United States, the -5 offset is used by both Central Standard Time (America/Chicago) and Eastern Daylight Time (America/New_York) at different times of the year.
Also consider that there are times where BOTH of those time zones use -5 at the same time. For example, Sunday November 3rd 2013 at 1:00 AM in UTC-5 could be either in CDT or EST. You'd have no way to distinguish just by -5 which time zone it was.
Details here.
Nowadays the DateTimeZone constructor can explicitly accept a UTC offset, which I understand you have.
So just:
$timeZone = new DateTimeZone('+0100');
Documentation:
http://php.net/manual/en/datetimezone.construct.php
Note: per that documentation link, this new constructor usage has been available since PHP version 5.5.10.
You might want to have a look at DateTime PHP extension (it's enabled & included by default in all PHP versions >= 5.2.0, unless it was specifically disabled at compile time).
It does everything you need here quite well.
You can use GMT time also and convert it to your requirement afterwards
<?php
echo gmdate("M d Y H:i:s", mktime(0, 0, 0, 1, 1, 1998));
?>
GMT refers Greenwich Mean Time which is common all over the world.
This work for me:
function Get_Offset_Date($Offset, $Unixtime = false, $Date_Format = 'Y.m.d,H:i')
{
try
{
$date = new DateTime("now",new DateTimeZone($Offset));
if($Unixtime)
{
$date->setTimestamp($Unixtime);
}
$Unixtime = $date->getTimestamp();
return $date->format($Date_Format);
}
catch(Exception $e)
{
return false;
}
}
To use it just call this to get current time:
echo Get_Offset_Date('+2:00');
And this for get Offset date (input is unixtime)
echo Get_Offset_Date('+2:00',1524783867);

Categories