Asked  8 Months ago    Answers:  5   Viewed   33 times

There's a lot of info on doing time zone adjustments in PHP, but I haven't found an answer for specifically what I want to do due to all the noise.

Given a time in one timezone, I want to convert it to the time in another timezone.

This is essentially what I want to do, but I need to be able to do it using only the built-in PHP libs, not PEAR Date.

This is what I've been doing, but it seems to always give me the offset relative to GMT:

$los_angeles_time_zone = new DateTimeZone('America/Los_Angeles');
$hawaii_time_zone = new DateTimeZone('Pacific/Honolulu');

$date_time_los_angeles = new DateTime('2009-09-18 05:00:00', $los_angeles_time_zone);
printf("LA Time: %s<br/>", $date_time_los_angeles->format(DATE_ATOM));

$time_offset = $hawaii_time_zone->getOffset($date_time_los_angeles);
printf("Offset: %s<br/>", $time_offset);

This is the output:

LA Time: 2009-09-18T05:00:00-07:00
Offset: -36000

I was expecting 3 hours (10800 seconds). but the '-7:00' thing tells me it's keeping everything relative to GMT, which maybe explains why it's giving me the "absolute" offset.

How do I just get the offset between the two timezones without all of this GMT hoohah?

Thanks.

UPDATE:

I occured to me that I could do this and get what I want:

    $date_time_los_angeles = new DateTime('2009-09-18 05:00:00', $los_angeles_time_zone);
printf("LA Time: %s<br/>", $date_time_los_angeles->format(DATE_ATOM));

$date_time_hawaii = new DateTime('2009-09-18 05:00:00', $hawaii_time_zone);
printf("Hawaii Time: %s<br/>", $date_time_hawaii->format(DATE_ATOM));


$time_offset = $los_angeles_time_zone->getOffset($date_time_los_angeles) - $hawaii_time_zone->getOffset($date_time_los_angeles);
printf("Offset: %s<br/>", $time_offset);

But it feels awkward to me. Anyone know a cleaner way to do it?

 Answers

73

Here are a couple of functions using the DateTime classes. The first one will return the difference in seconds between two timezones. The second returns a "translation" of the time from one timezone to another.

function timezone_diff($tz_from, $tz_to, $time_str = 'now')
{
    $dt = new DateTime($time_str, new DateTimeZone($tz_from));
    $offset_from = $dt->getOffset();
    $timestamp = $dt->getTimestamp();
    $offset_to = $dt->setTimezone(new DateTimezone($tz_to))->setTimestamp($timestamp)->getOffset();
    return $offset_to - $offset_from;
}

function time_translate($tz_from, $tz_to, $time_str = 'now', $format = 'Y-m-d H:i:s')
{
    $dt = new DateTime($time_str, new DateTimezone($tz_from));
    $timestamp = $dt->getTimestamp();
    return $dt->setTimezone(new DateTimezone($tz_to))->setTimestamp($timestamp)->format($format);
}

Demo:

$los_angeles_time = '2009-09-18 05:00:00';
$los_angeles_tz   = 'America/Los_Angeles';
$hawaii_tz        = 'Pacific/Honolulu';

$los_angeles_hawaii_diff = timezone_diff($los_angeles_tz, $hawaii_tz, $los_angeles_time);
echo $los_angeles_hawaii_diff . '<br />';

$hawaii_time = time_translate($los_angeles_tz, $hawaii_tz, $los_angeles_time);
echo $hawaii_time . '<br />';
Wednesday, March 31, 2021
 
ClmentM
answered 8 Months ago
11

Apparently, this is not a bug, it is 'expected, but undocumented behaviour'See the comments to the bug report. All single letters (except for 'j') represent military timezones, see some code to demonstrate this.

There is more information here.

From RFC822

The military standard uses a single character for each zone. "Z" is Universal Time. "A" indicates one hour earlier, and "M" indicates 12 hours earlier; "N" is one hour later, and "Y" is 12 hours later. The letter "J" is not used.

So to answer your question

I am not getting the point, how it's working?

When DateTime::__construct() is passed a single value that is not a valid time string it assumes that the first parameter has been omitted and tries to parse the string as a time zone. As the RFC explains, 'x' is a valid timezone, so you will get a DateTime instance that is in timezone 'X'.

I should mention that although the constructor of DateTime recognises these single letter zones, the constructor of DateTimeZone does not!

I hope that helps.

Saturday, May 29, 2021
 
danjah
answered 5 Months ago
40

I got the solution, so i would like to share

Actually I have set default timezone in config.inc.php file as below

date_default_timezone_set('America/Los_Angeles');

then I check the current time and timezone of MySQL server from phpmyadmin with below query

SELECT NOW(), SYSDATE(), @@global.time_zone , @@session.time_zone , 
      TIMEDIFF( NOW( ) , CONVERT_TZ( NOW( ) , @@session.time_zone ,  '+00:00' )) 
      AS OFFSET

This return the OFFSET value +05:30

solution steps:

  • First I changed the timezone of mySQL Server to GMT/UTC +00:00 ( I have super privilage on mySQL server)

    SET GLOBAL time_zone = '+00:00';  
    
  • We save the date and time using start_date = NOW() ( column datatype: DATETIME )

Now there is 2 way to get date and time as per user's timezone (America/Denver)

first method ( using PHP DateTime)

 /*
   * first set timezone as GMT.
   * This is MUST because default timezone is differ from user timezone  
  */     
    $gmt = new DateTimeZone('GMT');
    $user_tz = 'America/Denver';
    $st = new DateTime($row[`start_date`], $gmt);
    // now set user timezone
    $st->setTimezone($user_tz );
    $stime = $qt->format('r');
    echo $stime;

second method (using MySQL UNIX_TIMESTAMP)

#$retrieve data from server in timestamp
$qry = "SELECT `start_date`,UNIX_TIMESTAMP(`start_date`) AS sTimestamp FROM..."  
$st = new DateTime('@'.$row['sTimestamp ']);                     
$stime = $st->format('r');
echo $stime;
                  

Note : dont change start_date to timestamp with strtotime(). It will return different value from the UNIX_TIMESTAMP() i.e.

 strtotime($row['start_date']) !== $row['sTimestamp']
Saturday, August 7, 2021
 
Alix
answered 3 Months ago
79

You can get time zone selects with the appropriate methods:

  • time_zone_options_for_select
  • time_zone_select

Similarly, there's date_select for dates.

Storage:

If the timezone is specific to the user and doesn't change, then store their time zone in their user record and set it when you load the current_user. Rails will convert times to/from UTC and always store UTC in the database and do the automatic convert to that default timezone for you (including daylight savings!). Easiest way to do it.

use_zone(zone) lets you override the default zone for a block, so you can accept a form value and set it with that function and set your value in that block.

UPDATE: I wrote up some Rails timezone examples as a blog entry.

Wednesday, September 22, 2021
 
maniclorn
answered 1 Month ago
22

Use indexTZ<- and the America/New_York timezone

> tail(SPY)
                    SPY.Bid.Price SPY.Ask.Price SPY.Trade.Price SPY.Mid.Price SPY.Volume
2012-08-09 19:54:00        140.47        140.48          140.48       140.475       2372
2012-08-09 19:55:00        140.46        140.47          140.46       140.465       5836
2012-08-09 19:56:00        140.47        140.48          140.48       140.475       2538
2012-08-09 19:57:00        140.47        140.48          140.47       140.475       2209
2012-08-09 19:58:00        140.48        140.49          140.49       140.485       4943
2012-08-09 19:59:00        140.58        140.59          140.58       140.585      16780
> indexTZ(SPY) <- "America/New_York"
> tail(SPY)
                    SPY.Bid.Price SPY.Ask.Price SPY.Trade.Price SPY.Mid.Price SPY.Volume
2012-08-09 15:54:00        140.47        140.48          140.48       140.475       2372
2012-08-09 15:55:00        140.46        140.47          140.46       140.465       5836
2012-08-09 15:56:00        140.47        140.48          140.48       140.475       2538
2012-08-09 15:57:00        140.47        140.48          140.47       140.475       2209
2012-08-09 15:58:00        140.48        140.49          140.49       140.485       4943
2012-08-09 15:59:00        140.58        140.59          140.58       140.585      16780
Warning message:
timezone of object (America/New_York) is different than current timezone (GMT). 
Thursday, October 14, 2021
 
the Tin Man
answered 2 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share