使用 PHP 和 SQL Server 2000 处理时区



大家好,这个会很糟糕:

所以一段时间以来,我一直在为我的雇主开发一个产品,我们即将推出。但我们真的意识到我们把自己画在一个角落里。

在显示时区时,我们从未考虑过时区。我们将时间存储在日期时间字段中,这些字段以本地 (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。

相关内容

  • 没有找到相关文章

最新更新