Обработка часовых поясов с помощью PHP и SQL Server 2000 - PullRequest
0 голосов
/ 19 мая 2011

Привет, ребята, этот будет чокнутым:

Итак, какое-то время я работал над продуктом для своего работодателя, и мы близки к запуску.Но мы буквально просто поняли, что нарисовали себя в углу.

Мы никогда не учитывали часовые пояса, когда дело доходит до их отображения.Мы храним время в полях datetime, которые хранятся в нашем местном (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;
    }


}
?>

Это класс, который был сгенерирован написанным мною приложением, которое просматривает схему таблицы и строит методы получения, установки и т. Д. Для этого класса.

Класс dbobject имеет функцию сохранения и загрузки, которая записывает / извлекает данные в / из базы данных в строку с соответствующим первичным ключом.

В качестве последнего бита справочной информации этопример создания экземпляра класса customer (который расширяет базу клиентов, который расширяет 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, если поле, которое в настоящее время итерируется (через цикл foreach в массиве $ fields в этом классе), находится в массиве $ dateFields, оно преобразует это значение в соответствующий часовой пояс перед установкой его всвойство.

Чтобы инвертировать это для поддержания целостности данных, в функции save (), когда она выполняет итерации по датеЕсли это поле, оно преобразует его обратно в нашу локальную метку времени.

Вот пошаговое руководство по его визуализации.

Запись в таблице содержит поле с отметкой времени 2011-05-20 13: 45: 00

Мы знаем, что пример пользователя из Великобритании и смещение часового пояса +5.

Когда объект создается и вызывается load, он автоматически преобразует эту метку времени в 2011-05-20 18:45:00, поэтому всякий раз, когда вызывается метод получения, он возвращает эту строку.

Пользователь изменяет отметку времени с помощью средства выбора даты на веб-странице.Он выбирает 2011-05-20 20:00:00.Это значение сохраняется в экземпляре объекта как это значение.

Когда вызывается функция сохранения, она берет сохраненную временную метку в экземпляре и преобразует ее 2011-05-20 15:00:00 перед записью вбазы данных.

Готово.

Таким образом, все места, где мы отображаем время, будут автоматически «фиксированы», и когда им нужно будет изменить определенное значение метки времени, оно будет настроено автоматически присэкономьте время.

Итак, коренные вопросы:

A) Это лучший способ (и наиболее эффективный, учитывая наш сжатый срок) справиться с этим B) если нет, то что?C) Какие существуют решения PHP, которые помогут в реальном преобразовании временных меток из одного часового пояса в другой.

У меня строгий CDA, поэтому я стараюсь не публиковать больше кода, чем нужно, но сообщите мне, если потребуется дополнительная информация.

Примечание для уточнения: Изменение способа хранения времени невозможно / не идеально. Эта же база данных используется другими продуктами, в том числе внутренними инструментами контроля качества сотрудников. Использование другой системы времени (независимо от того, насколько привлекательным является UTC) может вызвать проблемы.

1 Ответ

1 голос
/ 19 мая 2011

Это немного не по теме, но если вы храните даты по местному времени, вы не можете точно обрабатывать преобразования часовых поясов 100% времени: в течение 1 часа каждый год, во время перехода на летнее время, время, которое вы сохранили вваша база данных неоднозначна - из местного времени просто нет способа получить UTC (и нет способа получить подходящее время в другом часовом поясе, который не имеет точно такое же переключение летнего времени), потому что вы не знаете, является ли событиебыл в первом экземпляре того времени или во втором.

Так что, если он все еще является предметом переговоров и вам нужно обрабатывать не-DST-эквивалентные часовые пояса или вам может понадобиться в будущем: переключитесь на сохранение как UTC.*

...