【问题标题】:DateTime::diff() isn't affected by timezone but always return same valueDateTime::diff() 不受时区影响,但总是返回相同的值
【发布时间】:2012-06-21 11:44:46
【问题描述】:

我正在向我的系统添加基于拍卖的数据。例如:

user's timezone  is : `America/Denver`
auction start time is : Thu, 21 Jun 2012 03:46:22 AM
auction period : 1 day.
auction end time : Fri, 22 Jun 2012 03:46:22 AM

我将所有这些信息按原样存储在我的数据库中(即所有存储时间都基于用户的时区)。

现在我想要结束时间和当前时间之间的实际差异(美国/丹佛时区)。

我使用了DateTime() 函数

所以即使我不转换时区;它返回相同的差异(这也是错误的)。

我的 PHP 代码如下;你也可以在CodePad找到它

$end_time = 'Fri, 22 Jun 2012 03:46:22 AM';
$tz = 'America/Denver';
dateDifference($end_time,$tz);

function dateDifference($end, $tz = NULL)
    {
      $owner_tz = new DateTimeZone($tz);
      //var_dump($owner_tz->getName()); 

      $from  = new DateTime("now", new DateTimeZone('GMT'));     
      $from ->setTimeZone($owner_tz);

      $to = new DateTime($end,new DateTimeZone('GMT'));
      /* @Note:I have commented below setTimeZone() because I have already stored 
       * `end time` as per user's  timezone, So I dont need to convert it again 
       * into user's timezone.you can un-comment below line. 
       * it doesn't affect the results anyways.
       */
     //$to ->setTimeZone($owner_tz);        

    //procedural style using date_diff()
    $interval = date_diff($from, $to);        
    var_dump($interval); 

    // OO style using dateTime::diff()
    $interval = $from->diff($to);       
    var_dump($interval);     
}

返回:

object(DateInterval)[4]
  public 'y' => int 0
  public 'm' => int 0
  public 'd' => int 0
  public 'h' => int 16
  public 'i' => int 40
  public 's' => int 24
  public 'invert' => int 0
  public 'days' => int 6015

参考资料:

【问题讨论】:

  • 根据用户的时区存储日期/时间信息是一种非常糟糕的做法,如果用户更改了他/她的时区怎么办?一个好的做法是在没有时区的情况下存储所有日期/时间信息(如 UTC 时间戳),这样您可以最​​大限度地减少转换和计算操作的数量,因此您只需担心在输出日期/时间时设置正确的时区用户。
  • 我的列数据类型是 datetime ,所以当我存储时我需要做些什么更改,因为日期时间的发布数据作为用户的时区来
  • 我并不是说您需要更改您的应用程序,这只是一个建议。您是否将 date_default_timezone_set 放在某个地方以确保您的服务器时间正确?
  • 是的,我已经在我的配置文件中设置了它。但你的想法真的很好。我之前曾有过这种想法
  • 但是这里的重点是为什么date_diff显示错误的结果??

标签: php datetime timezone


【解决方案1】:

在以下几行中,您基本上是在说结束日期是格林威治标准时间,而它应该是美国/丹佛时间:

$to = new DateTime($end, new DateTimeZone('GMT'));

然后您打算将其转换为美国/丹佛时间,但由于您使用 GMT 时区创建日期,所以无论如何这都是错误的。

// $to ->setTimeZone($owner_tz);

这将使用用户时区创建结束日期,这可能是您正在寻找的:

$to = new DateTime($end, $owner_tz);

【讨论】:

  • 不!我已经评论了那条线。我不想更改它,因为在添加拍卖时,结束时间已经按照用户的时区保存。
  • 正如我所说,您打算这样做,但第一行是您犯错的地方。让我重新表述一下答案。
  • 没有区别,都是等价的。你可以检查一下。所以new DateTime($end, $owner_tz); === new DateTime($end,new DateTimeZone('GMT')->setTimeZone($owner_tz);
【解决方案2】:

我得到了解决方案,所以我想分享一下

其实我已经在config.inc.php 文件中设置了默认时区,如下所示

date_default_timezone_set('America/Los_Angeles');

然后我使用以下查询从 phpmyadmin 中检查 MySQL 服务器的当前时间和时区

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

这将返回OFFSET+05:30

解决步骤:

  • 首先我将 mySQL Server 的时区更改为 GMT/UTC +00:00(我在 mySQL Server 上有 super 权限)

    SET GLOBAL time_zone = '+00:00';  
    
  • 我们使用start_date = NOW()(列数据类型:DATETIME)保存日期和时间

现在有两种方法可以根据用户的时区 (America/Denver) 获取日期和时间

第一种方法(使用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;

第二种方法(使用 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;
                  

注意:不要将start_date 更改为带有strtotime() 的时间戳。它将返回与UNIX_TIMESTAMP() 不同的值 即

 strtotime($row['start_date']) !== $row['sTimestamp']

【讨论】:

    猜你喜欢
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    相关资源
    最近更新 更多