大家好,这个会很糟糕:
所以一段时间以来,我一直在为我的雇主开发一个产品,我们即将推出。但我们真的意识到我们把自己画在一个角落里。
在显示时区时,我们从未考虑过时区。我们将时间存储在日期时间字段中,这些字段以本地 (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 类具有 save 和 load 函数,该函数将数据写入/从数据库读取数据到具有相应主键的行。
作为最后一点背景信息,这是客户类的示例实例化(它扩展了客户群,扩展了 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 无法在显示时转换时区(然后在保存时将它们转换回本地时区),这将是最简单的解决方案。
这是我有一个想法,实际上已经开始工作,但我想在花时间完成它之前得到一些反馈,它实际上并没有正常工作。
在所有基类中,我让生成器添加一个新属性,该属性列出了表中数组中 datetime 类型的所有字段,如下所示:
protected $dateFields = array('EmailSentTimestamp',
'notificationGeneratedDate');
然后在我的 dbobject::load() 函数中,当我作为 SQL 查询的结果填充对象中的所有字段属性时,如果当前正在迭代的字段(通过该类中 $fields 数组上的 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 多么吸引人)可能会导致问题。
这有点偏离主题,但如果您以本地时间存储日期,则无法 100% 准确处理时区转换: 每年 1 小时,在 DST 转换期间,您存储在数据库中的时间是不明确的 - 从本地时间根本无法派生 UTC(并且无法在另一个没有完全相同 DST 转换的时区中派生适当的时间), 因为您不知道事件是在那个时间的第一个实例中,还是在第二个实例中。
因此,如果它仍然可以协商,并且您需要处理非 DST 等效时区,或者将来可能需要:切换到存储为 UTC。