Как лучше всего работать с историческими датами (как 10 000 или миллион лет назад) в PHP? - PullRequest
7 голосов
/ 04 апреля 2019

Я анализирую наборы данных WSON WIDID для сбора исторических данных.До сих пор я не нашел подходящий формат для хранения их в PHP / MySQL (через Doctrine).

В последние несколько тысячелетий, похоже, DateTime работает, но я не хочу ограничивать свое приложениетот.Вполне возможно, что ему придется обработать свойство start time Universe .Кроме того, я также хочу сохранить точность данных, так как мы можем знать приблизительный год рождения одного человека и точную минуту для другого.(Правка: на данный момент дат достаточно, я могу жить без времени, мой пример был преувеличен. Тем не менее, я иногда знаю точную дату, иногда только месяц или даже год.)

Я имеюдумал о создании собственного класса для дат (я не планирую вычислять разницу во времени или что-то в этом роде), но я также не хочу заново изобретать колесо.

Результаты поиска по определенному запросудвигатель, как и здесь ... не радует, к сожалению.

Есть какие-нибудь идеи или опыт, которыми вы можете поделиться?

Ответы [ 2 ]

1 голос
/ 05 апреля 2019

Для подобного варианта использования мы закончили с сохранением значений для каждого периода времени, позволяя хранить все в БД и запрашивать с различными уровнями точности.

class YourAwesomeDateManager {

    public
        $millenium,
        $century,
        $decade,
        $year,
        $month;
        // and so on...

    function setDate() {
        // Hydrate with the best precision available
    }

    public function getDate ($precision) {
        // ...
    }
}

Это позволяет извлекать различные форматы даты и возвращать 0 для недоступных полей точности

Дело в том, что нет общего названия для периодов выше тысячелетий . Так что вам придется проявить креативность.

0 голосов
/ 06 апреля 2019

Чтобы предложить ответ на мой вопрос: нет, похоже, ничего подобного.

Итак, я продолжил и реализовал функцию, которая делает то, что мне нужно. Я отказался от черновика класса WikidataDate, так как просто создавал десятки из них, чтобы просто преобразовать одну строку в другую ...

Спасибо за ваш отзыв, не стесняйтесь предлагать улучшения или другие решения!

const CALENDARMODEL        = 'http://www.wikidata.org/entity/Q1985727';
const WIKIDATA_DATE_FORMAT = '/^[+]?(-?\d{1,11})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/';

const PRECISION_YEAR           = 9;
const PRECISION_YEAR_AND_MONTH = 10;
const PRECISION_DATE           = 11;

const PRECISIONS = [
    self::PRECISION_YEAR,
    self::PRECISION_YEAR_AND_MONTH,
    self::PRECISION_DATE,
];

/**
 * Parse a date object (a "value" node) coming from parsing Wikidata JSON.
 *
 * Example string outputs:
 * - "2018-12-31"   the last day of 2018
 * - "333-11"       the month of the battle of Issos
 * - "-53"          the year in which Lutetia (Paris) was first mentioned
 * - "-13798000000" the beginning of the universe
 *
 * @param \stdClass $object
 *
 * @return string
 *
 * @throws \Exception
 */
private function parseWikidataDate(\stdClass $object): string
{
    if (!WikidataEntityDenormalizer::validateObjectProperties($object, ['time', 'precision', 'calendarmodel'])) {
        throw new \Exception('Object missing necessary properties');
    }

    if (!in_array($object->precision, static::PRECISIONS)) {
        throw new \Exception('Unexpected precision: '.$object->precision);
    }

    if (static::CALENDARMODEL !== $object->calendarmodel) {
        throw new \Exception('Unexpected calendar model');
    }

    $result = [];
    preg_match(static::WIKIDATA_DATE_FORMAT, $object->time, $result);

    if (7 !== count($result)) {
        throw new \Exception(sprintf('Could not parse Wikidata date: %s', $object->time));
    }

    $date = $result[1];

    if ('00' !== $result[2]) {
        $date .= '-'.$result[2];
    }

    if ('00' !== $result[3]) {
        $date .= '-'.$result[3];
    }

    return $date;
}
...