【发布时间】:2011-08-28 09:24:07
【问题描述】:
你们好,伙计们,这将是一个笨蛋:
所以有一段时间以来,我一直在为我的雇主开发一种产品,而且我们即将推出。但我们真的只是意识到我们把自己画在一个角落里。
在显示时区时,我们从不考虑时区。我们将时间存储在存储在本地 (EST) 时区的日期时间字段中。
假设我们在客户表中添加一个字段以确定他们所在的时区,在显示级别转换这些时间的最佳方法是什么,以及当我们接受来自用户的时间戳(例如,输入字段)时,将其转换返回 EST 进行存储。
对于我们的数据库抽象架构,我们使用表类方法。我不确定这个方法的花哨名称,但基本上我们使用的每个表都有一个类,其数据库模式为 PHP 代码,如下所示:
此代码将用于名为 L2FU_notification 的表
<?php
class L2FU_notificationbase extends dbobject
{
protected $EmailSentTimestamp;
protected $hasBeenEmailed;
protected $HasBeenViewed;
protected $notificationGeneratedDate;
protected $NotificationID;
protected $notificationText;
protected $notificationTitle;
protected $releaseDate;
protected $xtelelinkTarget;
protected $xtelelinkToBeNotified;
protected $fields = array('EmailSentTimestamp',
'hasBeenEmailed',
'HasBeenViewed',
'notificationGeneratedDate',
'NotificationID'
);
protected $table = "L2FU_notification";
protected $primaryKey = "NotificationID";
function getEmailSentTimestamp()
{
return $this->EmailSentTimestamp;
}
function setEmailSentTimestamp($EmailSentTimestamp)
{
$this->changedFields[] = 'EmailSentTimestamp';
$this->EmailSentTimestamp = $EmailSentTimestamp;
return $this;
}
function gethasBeenEmailed()
{
return $this->hasBeenEmailed;
}
function sethasBeenEmailed($hasBeenEmailed)
{
$this->changedFields[] = 'hasBeenEmailed';
$this->hasBeenEmailed = $hasBeenEmailed;
return $this;
}
function getHasBeenViewed()
{
return $this->HasBeenViewed;
}
function setHasBeenViewed($HasBeenViewed)
{
$this->changedFields[] = 'HasBeenViewed';
$this->HasBeenViewed = $HasBeenViewed;
return $this;
}
function getnotificationGeneratedDate()
{
return $this->notificationGeneratedDate;
}
function setnotificationGeneratedDate($notificationGeneratedDate)
{
$this->changedFields[] = 'notificationGeneratedDate';
$this->notificationGeneratedDate = $notificationGeneratedDate;
return $this;
}
function getNotificationID()
{
return $this->NotificationID;
}
function setNotificationID($NotificationID)
{
$this->changedFields[] = 'NotificationID';
$this->NotificationID = $NotificationID;
return $this;
}
}
?>
这是一个由我编写的应用程序生成的类,它查看表模式并为该类构建 getter、setter 等。
dbobject 类具有保存和加载功能,可以将数据写入/从数据库中读取数据到具有相应主键的行。
作为背景信息的最后一点,这是客户类的示例实例(它扩展了客户库,扩展了 dbobject)
<?php
$customerObj = new customer(1431); //let's say the customer ID we're working on is 1431. the constructor automatically calls load() when a primary key is passed at instantiation
$customerObj->setFirstName("Henry")->setLastName("Ford")->save();
?>
所以这是我正在开发的产品架构的一些基础——现在还不能改变,因为我们已经接近发布。
这是实际的问题:
我们如何处理与时区相关的时间戳的互操作性?不幸的是,SQL Server 2000 无法在显示时转换时区(然后在保存时将它们转换回本地时区),这本来是最简单的解决方案。
这是我的一个想法,并且实际上开始着手,但我想在花时间将它写到完成之前获得一些反馈,但它实际上并不能正常工作。
在所有基类中,我让生成器添加了一个新属性,该属性列出了表中所有字段类型为数组中的日期时间,如下所示:
protected $dateFields = array('EmailSentTimestamp',
'notificationGeneratedDate');
然后在我的 dbobject::load() 函数中,当我作为 SQL 查询的结果填充对象中的所有字段属性时,如果当前正在迭代的字段(通过 $ 上的 foreach 循环该类中的字段数组)在 $dateFields 数组中,它会将该值转换为正确的时区,然后再将其设置到属性中。
为了保持数据完整性,在 save() 函数中,当它在日期时间字段上进行迭代时,它会将其转换回我们的本地时间戳。
这是我如何将其可视化的一步一步。
表上的记录有一个时间戳为2011-05-20 13:45:00的字段
我们知道示例用户来自英国,并且时区偏移量为 +5。
当实例化对象并调用 load 时,它会自动将该时间戳转换为 2011-05-20 18:45:00,因此每当调用 getter 时,它都会返回该字符串。
用户通过网页上的日期时间选择器修改时间戳。他选择 2011-05-20 20:00:00。它作为这个值被存储回对象实例。
调用save函数时,将实例中存储的时间戳转换为2011-05-20 15:00:00,然后写入数据库。
完成。
这样,我们显示时间的所有地方都会自动“固定”,当它们需要更改某个时间戳值时,它会在保存时自动调整。
所以根本问题是
A) 这是处理此问题的最佳方式(考虑到我们紧迫的截止日期,也是最有效的方式)吗? B)如果不是,那是什么? C) 有哪些 PHP 解决方案可以帮助将时间戳从一个时区实际转换到另一个时区。
我处于严格的 CDA 之下,因此我尽量避免发布过多的代码,但如果需要更多信息,请告诉我。
澄清说明:更改时间的存储方式是不可能的/不理想的。其他产品也使用相同的数据库,包括内部员工 QA 工具。使用不同的时间系统(无论 UTC 多么吸引人)可能会导致问题。
【问题讨论】:
标签: php datetime timezone sql-server-2000