Get time zone offset between two timezones for a given duration - php

I wanted to know if there is a way to get the time zone offset for a given date range between two timezones for a given duration.
getTimezoneOffset(startDate,endDate,timezone1,timezone2){
...missing magic to go here...
}
should return the time zone offset which is valid for the a given duration. However if the offset changes, it should return the date range for which it's valid.
So I am looking at something like this:
getTimezoneOFfset("march 9 12 am", "march 15 12 am", "UTC", "US/NEW_YORK")
return value something like this
timezoneoffset[0]["range"]=[march 9 12am to march 11 2 am]
timezoneoffset[0]["offset"]=5
timezoneoffset[1]["range"]=[march 9 2 am to march 15 12 am]
timezoneoffset[1]["offset"]=4
I just don't want to calculate timezone offsets for every scheduled item for the given range. Was looking if there is some way to get a direct lookup for offsets if it's going to change.
I am working with PHP, but a solution in any language will be appreciated.
MySQL solution will also work as it will be more optimized to do this in MySQL.

Assuming that you have a newer version of php (5.2.0+) the DateTimeZone class is part of the PHP core and will let you use the getOffset() function to make these calculations. It will let you pass in a dateTime object and specify a timezone. If you do this for both your dates you should be able to calculate all of the pieces you're looking to grab. To use an example from php.net:
// Create two timezone objects, one for Taipei (Taiwan) and one for
// Tokyo (Japan)
$dateTimeZoneTaipei = new DateTimeZone("Asia/Taipei");
$dateTimeZoneJapan = new DateTimeZone("Asia/Tokyo");
// Create two DateTime objects that will contain the same Unix timestamp, but
// have different timezones attached to them.
$dateTimeTaipei = new DateTime(mktime([the date in question]), $dateTimeZoneTaipei);
$dateTimeJapan = new DateTime(mktime([the date in question]), $dateTimeZoneJapan);
// Calculate the GMT offset for the date/time contained in the $dateTimeTaipei
// object, but using the timezone rules as defined for Tokyo
// ($dateTimeZoneJapan).
$timeOffset = $dateTimeZoneJapan->getOffset($dateTimeTaipei);
// Should show int(32400) (for dates after Sat Sep 8 01:00:00 1951 JST).
print("Number of seconds Japan is ahead of GMT at the specific time: ");
var_dump($timeOffset);
print("<br />Number of seconds Taipei is ahead of GMT at the specific time: ");
var_dump($dateTimeZoneTaipei->getOffset($dateTimeTaipei));
print("<br />Number of seconds Japan is ahead of Taipei at the specific time: ");
var_dump($dateTimeZoneJapan->getOffset($dateTimeTaipei)
-$dateTimeZoneTaipei->getOffset($dateTimeTaipei));

This working for me:
function Get_Timezone_Offset($remote_tz, $origin_tz = null)
{
if($origin_tz === null)
{
if(!is_string($origin_tz = date_default_timezone_get())) {
return false;
}
}
$origin_dtz = new DateTimeZone($origin_tz);
$remote_dtz = new DateTimeZone($remote_tz);
$origin_dt = new DateTime("now", $origin_dtz);
$remote_dt = new DateTime("now", $remote_dtz);
$offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt);
return $offset;
}
To use it
echo Get_Timezone_Offset('America/New_York', 'Europe/Stockholm');
Source:
http://php.net/manual/en/function.timezone-offset-get.php

I think PHP's DateTimeZone::getTransitions method can get you there. It has a procedural alias, timezone_transitions_get().
public array DateTimeZone::getTransitions (
[ int $timestamp_begin [, int $timestamp_end ]] )
This method returns all "transitions" from one time zone offset value to another, for that timezone, in a given time range.
For your purposes, you will want to create DateTimeZone objects for each of your time zones, call DateTimeZone::getTransitions for your date range to get an array of transitions for that time zone, then merge and sort the two arrays of transitions. This will give you the equivalent of the timezoneoffset[] array you seek.
Something like:
getTimezoneOffset(startDate,endDate,timezone1,timezone2){
DT1 = DateTimeZone( timezone1 );
transitions1 = DT1->getTransitions( startDate,endDate );
DT2 = DateTimeZone( timezone2 );
transitions1 = DT2->getTransitions( startDate,endDate );
timezoneoffset[] = // merge and sort (transitions1, transitions2)
}
The format of the transitions array isn't well documented. The method documentation shows some example entries:
Array
(
...
[1] => Array
(
[ts] => -1691964000
[time] => 1916-05-21T02:00:00+0000
[offset] => 3600
[isdst] => 1
[abbr] => BST
)
[2] => Array
(
[ts] => -1680472800
[time] => 1916-10-01T02:00:00+0000
[offset] => 0
[isdst] =>
[abbr] => GMT
)
...
)
I speculate that: ts refers to a PHP timestamp in epoch seconds, as returned by time(), giving the instant in time at which the offset changes to the value in this record. time refers to the same instant, as a formatted string date-time. offset is the timezone's offset in seconds from UTC, as of the instant time/ts, forward to the next transition. isdst is 1 if the offset refers to a daylight savings time offset, 0 otherwise. abbr is a string abbreviation for the time zone. If anyone has solid information about this data structure, it would be a kindness to add it to the documentation.

Related

PHP: Get timezone identifier offset from UTC

I know \DateTimeZone::listIdentifiers() returns all timezone identifiers, but how can I retrieve their actual offset from UTC?
There is method getoffset
<?php
// Create two timezone objects, one for Taipei (Taiwan) and one for
// Tokyo (Japan)
$dateTimeZoneTaipei = new DateTimeZone("Asia/Taipei");
$dateTimeZoneJapan = new DateTimeZone("Asia/Tokyo");
// Create two DateTime objects that will contain the same Unix timestamp, but
// have different timezones attached to them.
$dateTimeTaipei = new DateTime("now", $dateTimeZoneTaipei);
$dateTimeJapan = new DateTime("now", $dateTimeZoneJapan);
// Calculate the GMT offset for the date/time contained in the $dateTimeTaipei
// object, but using the timezone rules as defined for Tokyo
// ($dateTimeZoneJapan).
$timeOffset = $dateTimeZoneJapan->getOffset($dateTimeTaipei);
// Should show int(32400) (for dates after Sat Sep 8 01:00:00 1951 JST).
var_dump($timeOffset);
?>
You can build an associative array mapping timezones and their offset using the getOffset method of DateTime instance.
getOffset returns the difference in seconds of a date evaluated in the time zone of the provided datetime argument (in our example, this is the current time in utc), and the same datetime as evaluated in the local time zone.
$utcNow = new DateTime('now', (new DateTimeZone('UTC')));
$identOffset = array_map(
function ($ident) use ($utcNow) {
$localTimeZone = new DateTimeZone($ident);
$offset = $localTimeZone->getOffset($utcNow);
return [$ident => $offset] ;
},
DateTimeZone::listIdentifiers()
);
$identOffset = array_merge(...$identOffset);
var_dump($identOffset);
If you are using https://carbon.nesbot.com/
// You will get timezone offset as string
Carbon::now('Asia/Kathmandu')->getOffsetString(); // +05:45

DateTimeZone only handles offsets in one direction

I am attempting to retrieve a date that is not in GMT and convert it to GMT. To do this, I am creating two time zones (one GMT and one non-GMT) and attempting to get the offset between them. However, the offset is only correct in one direction. For this specific example, I am trying to compare GMT +4 to GMT. I expect to get 4hrs (14400 seconds) when I compare the the GMT timezone to the GMT+4 timezone, and -4hrs (-14400 seconds) when I compare the GMT+4 timezone to GMT. However, when comparing the later I'm getting 0... Here is what I have
$default_timezone = new DateTimeZone(drupal_get_user_timezone());
$default_reg_date = new DateTime($reg_date_string, $default_timezone);
$gmt_timezone = new DateTimeZone('UTC');
$gmt_reg_date = new DateTime($reg_date_string, $gmt_timezone);
// Returns as 14400
$default_gmt_offset = $default_timezone->getOffset($gmt_reg_date);
// Returns as 0
$gmt_default_offset = $gmt_timezone->getOffset($default_reg_date);
Why can't I get the right number, what am I doing wrong? Does retrieving the offset only work one way?
Note: in this specific example, drupal_get_user_timezone() is returning GMT+4
From the PHP documentation :
This function returns the offset to GMT for the date/time specified in the datetime parameter. The GMT offset is calculated with the timezone information contained in the DateTimeZone object being used.
The function works with 2 logics steps :
Convert the date into the timezone on which the function is applied
Get the offset from GMT
So calling this function on new DateTimeZone('UTC') will always returns 0
If you want to convert a date into UTC, you can use the setTimeZone function :
$date_string = '2020-05-01 09:11:00' ;
$date = new DateTime($date_string, new DateTimeZone('Europe/Brussels'));
echo $date->format('c') ; // 2020-05-01T09:11:00+02:00
$date->setTimeZone(new DateTimeZone('UTC'));
echo $date->format('c') ; // 2020-05-01T07:11:00+00:00

PHP date time zone conversion - days

I have date conversion issue: The goal is to determine an "order by date" for a book, this should be 13 days prior to the book's "release date", which is in EST. The "order by date" should display the 13 day time frame plus any time diff between the user's time and EST (New York) time. So in my function below, I'm getting the release date, NYC time, user's time and trying to do order_by_date = release_date - ( (nyc/user local time diff) + 13 days). It seemed to be working, but after testing this out with multiple release dates, I'm consistently returning a 14 day difference, not a 13 day one... My main question is why would the function below output a date that is 14 days before a release date and not 13 days? I've tried echoing each time variable and each one looks normal (i.e. for a user in NYC, the time diff is 0, but for someone on PST it's 3hour diff), I wonder if the formatting is having an effect on the value? Thanks for any input:
function get_order_by_date( ) {
$release_date = '26-02-2019 00:00:00'
$ny_timezone = new \DateTimeZone( 'America/New_York' );
$gmt_timezone = new \DateTimeZone( 'GMT' );
$user_date_time = new \DateTime( $release_date, $gmt_timezone );
$offset = $ny_timezone->getOffset( $user_date_time );
$my_interval = \DateInterval::createFromDateString( (string) $offset . 'seconds' );
$user_date_time->add( $my_interval );
$result = $user_date_time->format( 'd-m-Y H:i:s' );
$order_by_date = date( 'F jS', strtotime( $result . ' - 13 days' ) );
return $order_by_date;
}
It might be easier to see why we get a certain date as a result if we simplify the process a little. If I understand correctly the function needs to take the release date and do two things to it:
Shift 13 days prior to it
Set it to the user's timezone
If we start with the release date in the release timezone, making those modifications is more straightforward.
For the purposes of the answer I'm returning the result in a format that includes the time so we can see exactly where those modifications put the result, but you can use whatever format is needed.
<?php
function get_order_by_date(string $release_date, string $user_timezone)
{
$release_timezone = new \DateTimeZone( 'America/New_York' );
$user_timezone = new \DateTimeZone($user_timezone);
// start with the release date in NY time
$orderby_date = new \DateTime($release_date, $release_timezone);
// 13 days prior
$orderby_date->modify('-13 days');
// shift to the user's timezone
$orderby_date->setTimezone($user_timezone);
return $orderby_date->format('Y-m-d H:i:s');
}
Using the date in your example, 26-02-2019 00:00:00 moving thirteen days before would give you 13-02-2019 00:00:00.
At that time in NY, the time in LA would be three hours earlier, so the result would be in the previous day
echo get_order_by_date('26-02-2019 00:00:00', 'America/Los_Angeles'); // 2019-02-12 21:00:00
And the time in GMT would be five hours later, so the result would be in the same day
echo get_order_by_date('26-02-2019 00:00:00', 'GMT'); // 2019-02-13 05:00:00

PHP UNIX TIME STAMP

I have a date calendar in my php form which gives me date '19-05-2014'. I should compare this date to database time-modified (1400481271) exactly.
When converted '19-05-2014' to UNIX TIME STAMP, but I get the result as 1397858400 which was a wrong time stamp.
id userid timemodified
370 23 1400481271
329 24 1427771915
333 30 1428309816
332 32 1428303307
327 33 1427689703
328 34 1427710711
<?php
if ( preg_match('/^(?P<day>\d+)[-\/](?P<month>\d+)[-\/](?P<year>\d+)$/', '19-05-2014', $matches) )
{
$timestamp = mktime(0, 0, 0, ( $matches['month'] - 1 ), $matches['day'], $matches['year']);
echo $timestamp;
}
?>
The date you are trying to match is, converted to timestamp:
1400457600
If you got a different value you converted it wrong (maybe switched day and month or something similar).
It is, however, while close, still not identical to the given value 1400481271 in your database.
The reason for this becomes clear if you convert it back to a readable date:
05/19/2014 # 6:34am (UTC) 1400481271
For comparison, the given date:
05/19/2014 # 12:00am (UTC) 1400457600
As you can see there is a difference because it's the same date, but a different time.
The easiest way would be to retrieve only the date portion from the database.
You can do this in your SQL query like this:
SELECT DATE( FROM_UNIXTIME( timemodified ) ) AS modified
This will return 2014-05-19, which you can easily compare with your string.
Or, if you can even retrieve it in the same format you get it, so you don't need to rewrite your date with regex:
SELECT DATE_FORMAT( FROM_UNIXTIME( timemodified ), '%d-%m-%Y' ) AS modified
This will return 19-05-2014 for 1400481271.

How to get a Unix Timestamp from a specific date - PHP?

The Unix Time Stamp generated by my MKTIME is not generating correctly
(European format)
Date Submitted: 15/02/2014 19:00
Unix Code: 1392508800
This returned date is: 16/02/2014 00:00:00
Code it should of returned is: 1392490800
Code Used
After form is submitted values are captured and assigned...
if ($_POST['Callbacl']){
$CID=$_POST['ID'];
$Notes = $_POST['callbacknotes'];
$Time_H = $_POST['Time_Hour'];
$Time_M = $_POST['Time_Minute'];
$Date_Day = $_POST['Date_Day'];
$Date_Month = $_POST['Date_Month'];
$Date_Year = $_POST['Date_Year'];
$Appt = mktime($Time_H, $Time_M,00, $Date_Month, $Date_Day, $Date_Year);
echo $Appt . "<br>";
die;
}
Post values
Array (
[ID] => 1
[Time_Hour] => 19
[Time_Minute] => 00
[Date_Month] => 02
[Date_Day] => 15
[Date_Year] => 2014
[callbacknotes] =>
[Callback] => Call Back
)
I suppose to your time zone in php.ini is not your preferred one.
Try to set a proper time zone in php.ini or to add the following code at the beginning of your block.
date_default_timezone_set('your time zone');
There is the list of supported time zones in PHP:
http://www.php.net/manual/en/timezones.php

Categories