Усовершенствованная проверка даты с PHP

  1. , К сожалению, нет.
  2. if( "mystring#".substr(-1) === "#" ) {}
5
задан Sampson 20 July 2009 в 00:00
поделиться

7 ответов

Как насчет серии тщательно написанных регулярных выражений, распознающих каждый возможный формат. Как только вы знаете формат, вы можете проверить и, возможно, поместить его в единообразное представление (например, 64-битное time_t).

например,

/(\d{4})-(\d{2})-(\d{2})/
/(\d+)(bc|b.c.|bce|b.c.e)/i
etc.

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

Обновление:

Все даты должны быть отсортированы в их глобальном списке.

Мне кажется, что для того, чтобы иметь возможность чтобы отсортировать даты, представленные в разных форматах, вам понадобится единое представление для каждой из них, как я упоминал ранее. Например, используйте словарь с несколькими ключами (std :: multimap в C ++, не уверен в PHP) для хранения сопоставлений (унифицированное представление) -> (входное представление).

5
ответ дан 14 December 2019 в 08:57
поделиться

Вы можете рассмотреть возможность реализации вашего собственного пользовательского класса типа DateTime. Я не уверен, каковы все ваши требования, но я мог видеть, что у него есть свойства для BC / AD, форматирования и т. Д. Немного подумав, это не должно быть намного сложнее, чем реализация класса типа Money, если это вам знакомо

Я предлагаю это потому, что 200 г. до н.э. и 1492-10-07 сильно отличаются, даже по формату. Говоря не о манжетах, если вы относитесь к BC <0

1
ответ дан 14 December 2019 в 08:57
поделиться

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

0
ответ дан 14 December 2019 в 08:57
поделиться

А как насчет использования Zend_Date. Библиотека дат Zend - очень хорошая служебная библиотека дат. Он может работать автономно или с другими библиотеками Zend и может работать с date_default_timezone_set (), поэтому даты автоматически анализируются для установленного часового пояса, и он будет работать для дат вне диапазона временных меток Unix. Иногда писать его может быть немного сложно, но его сильные стороны значительно перевешивают его недостатки.

Возможно, вам придется реализовать свой собственный синтаксический анализ для BC / AD, поскольку я не уверен, что он сработает для этого, но он Возможно, стоит попробовать.

Pear также имеет библиотеку дат , на которую, возможно, стоит взглянуть, однако я не использовал ее и слышал от многих людей, что они предпочитают Zend_Date пакету Pear's Date.

Вы всегда можете написать свое, но зачем изобретать колесо?

2
ответ дан 14 December 2019 в 08:57
поделиться

Поскольку вы контролируете интерфейс ввода, без потери общности мы можем предположить, что будут отдельные целые числа год / месяц / день (правильно проверить, является ли ... целым числом :) . Допустим, этот год будет отрицательным, чтобы указать BC.

Итак, прежде всего ... очевидный (частичный) ответ: checkdate () . Как сказано в документации по функциям, этого вполне достаточно для лет> = 1.

Таким образом, вы застряли с проблемой, что делать, если год <= 0.

Давайте совершим обходной путь здесь и посмотрим, почему это может быть БОЛЬШОЙ проблемой ...

Согласно приведенной выше ссылке на Википедию, юлианский календарь вступил в силу в 45 году до нашей эры. Этот календарь, для всех практических целей идентичен григорианскому календарю, который мы используем сегодня. Разница в том, что между ними есть десятидневный сдвиг; последним днем ​​по юлианскому календарю был четверг, 4 октября 1582 г., за ним последовал первый день по григорианскому календарю, пятница, 15 октября 1582 г. (цикл будних дней не изменился).

Это уже означает, что даты в диапазон с 5 октября 1582 года по 14 октября 1582 года (включительно) недействителен , если вы следуете григорианскому календарю ; они никогда не существовали.

Возвращаясь оттуда, вы будете хороши до 45 г. до н.э. Начиная с 46 г. до н.э., римский календарь использовался вместо юлианского.

Я не собираюсь вдаваться в эту неразбериху, просто упомяну, что, поскольку этот календарь сильно отличался от григорианского, ваши пользователи не будут готовы увидеть " Функция «is-year-leap», которая учитывает это несоответствие, плюс переключение «юлианский / грегорианский» будет иметь следующий вид:

define('YEAR_JULIAN_CALENDAR_INTRODUCED', -45);
define('YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY', 8);
define('YEAR_GREGORIAN_CALENDAR_INTRODUCED', 1582);

function is_leap_year($year) {
    if($year < YEAR_JULIAN_CALENDAR_INTRODUCED) {
        return false; // or good luck :)
    }
    if($year < YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY) {
        return $year <= -9 && $year % 3 == 0;
    }
    if($year < YEAR_GREGORIAN_CALENDAR_INTRODUCED) {
        return $year % 4 == 0;
    }
    // Otherwise, Gregorian is in effect
    return $year % 4 == 0 && ($year % 100 != 0 || $year % 400 == 0);
}

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

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Какая точность вам действительно нужна?

Если вы решите, что вам нужно разбираться в «технических деталях», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их как свою созданную вручную библиотеку дат или б) использовал их, чтобы проверить, что любые 3 Меня интересует-сторонняя библиотека на самом деле реализована правильно .

Если вам не нужно этого делать, просто представьте, что вы никогда не читали все это. :)

плюс переключатель юлианский / грегорианский:

define('YEAR_JULIAN_CALENDAR_INTRODUCED', -45);
define('YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY', 8);
define('YEAR_GREGORIAN_CALENDAR_INTRODUCED', 1582);

function is_leap_year($year) {
    if($year < YEAR_JULIAN_CALENDAR_INTRODUCED) {
        return false; // or good luck :)
    }
    if($year < YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY) {
        return $year <= -9 && $year % 3 == 0;
    }
    if($year < YEAR_GREGORIAN_CALENDAR_INTRODUCED) {
        return $year % 4 == 0;
    }
    // Otherwise, Gregorian is in effect
    return $year % 4 == 0 && ($year % 100 != 0 || $year % 400 == 0);
}

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

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Насколько точно вам нужно?

. Если вы решите, что вам нужно разбираться в «технических деталях», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их как свою созданную вручную библиотеку дат или б) использовал их, чтобы проверить, что любые 3 Меня интересует-сторонняя библиотека на самом деле реализована правильно .

Если вам это не нужно, просто представьте, что вы никогда не читали все это. :)

плюс переключатель юлианский / грегорианский:

define('YEAR_JULIAN_CALENDAR_INTRODUCED', -45);
define('YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY', 8);
define('YEAR_GREGORIAN_CALENDAR_INTRODUCED', 1582);

function is_leap_year($year) {
    if($year < YEAR_JULIAN_CALENDAR_INTRODUCED) {
        return false; // or good luck :)
    }
    if($year < YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY) {
        return $year <= -9 && $year % 3 == 0;
    }
    if($year < YEAR_GREGORIAN_CALENDAR_INTRODUCED) {
        return $year % 4 == 0;
    }
    // Otherwise, Gregorian is in effect
    return $year % 4 == 0 && ($year % 100 != 0 || $year % 400 == 0);
}

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

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Насколько точно вам нужно?

. Если вы решите, что вам нужно разбираться в «технических деталях», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их как свою созданную вручную библиотеку дат или б) использовал их, чтобы проверить, что любые 3 Меня интересует-сторонняя библиотека на самом деле реализована правильно .

Если вам не нужно этого делать, просто представьте, что вы никогда не читали все это. :)

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

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Насколько точно вам нужно?

Если вы решите, что вам нужно разбираться в «технических деталях», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их как свою созданную вручную библиотеку дат или б) использовал их, чтобы проверить, что любые 3 Меня интересует-сторонняя библиотека на самом деле реализована правильно .

Если вам это не нужно, просто представьте, что вы никогда не читали все это. :)

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

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Насколько точно вам нужно?

Если вы решите, что вам нужно разбираться в «технических деталях», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их как свою созданную вручную библиотеку дат или б) использовал их, чтобы проверить, что любые 3 Меня интересует-сторонняя библиотека на самом деле реализована правильно .

Если вам не нужно этого делать, просто представьте, что вы никогда не читали все это. :)

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Какая точность вам действительно нужна?

Если вы решите, что вам нужно быть аналом Что касается «технических деталей», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их в качестве моей созданной вручную библиотеки дат, или б) использовал бы их, чтобы проверить, что любая сторонняя библиотека, которая меня интересует на самом деле реализован правильно .

Если вам это не нужно, просто сделайте вид, что вы никогда не читали все это. :)

После всего этого обсуждения (я восхищаюсь смелостью любого, кто дочитал до этого места :), я должен спросить:

Какая точность вам действительно нужна?

Если вы решите, что вам нужно быть аналом Что касается «технических деталей», я бы лично реализовал функции, упомянутые выше, а затем: а) использовал бы их в качестве моей созданной вручную библиотеки дат, или б) использовал бы их, чтобы проверить, что любая сторонняя библиотека, которая меня интересует на самом деле реализован правильно .

Если вам это не нужно, просто сделайте вид, что вы никогда не читали все это. :)

а) Использовать их в качестве моей созданной вручную библиотеки дат или б) Использовать их, чтобы проверить, что любая интересующая меня сторонняя библиотека действительно реализована правильно .

Если вам это не нужно сделай это, просто сделай вид, что никогда не читал всего этого. :)

a) Использовать их как мою созданную вручную библиотеку дат или b) Использовать их, чтобы проверить, что любая интересующая меня сторонняя библиотека действительно реализована правильно .

Если вам не нужно сделай это, просто сделай вид, что никогда не читал всего этого. :)

1
ответ дан 14 December 2019 в 08:57
поделиться

а как насчет strtotime ()?

-2
ответ дан 14 December 2019 в 08:57
поделиться

Второй ответ после обновления вопроса Джонатана:

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

Вы можете просто указать время как количество секунд с 1 января 10000 г. до н.э. (выберите свою эпоху); 64 бит для этого было бы более чем достаточно. Для этого вам нужно решить одну или две задачи.

A. Как сделать 64-битные int в PHP.

PHP гарантированно предоставляет 31 бит для целых чисел. Таким образом, вы можете сделать одно из следующего:

  1. Напишите свой собственный 62-битный целочисленный класс, который хранит биты в двух частных целых членах. 62 бита также более чем достаточно.

    Это было бы болезненно и, вероятно, быстро. Главное преимущество: вы не зависите от каких-либо расширений PHP.

  2. Используйте BCMath или GMP для вычисления целых чисел произвольной точности.

    Я бы сначала попробовал это, если переносимость не является обязательной. Однако это может оказаться медленнее, чем приемлемо. Главное преимущество: вы не рискуете ошибиться в битовом коде.

Имея в руках 60-битный целочисленный класс (поддержка сложения / вычитания / сравнения с помощью соответствующих методов или вспомогательных функций) , затем вы можете написать класс CustomDateTime, который поддерживает всю необходимую логику. Этот класс будет включать весь код «date-to-int» и наоборот (например, конструкция); все операции реализации «иметь-чисто-сделать-int-int» (например, сравнение) будут просто перенаправлены в ваш целочисленный класс.

B. Как делать 64-битные ints в базе данных.

Все базы данных делают это без проблем. Однако вам почти наверняка нужно пойти по этому пути, потому что, например, MySQL не поддерживает даты до 1000 г. н.э. Не знаю о других поставщиках.

0
ответ дан 14 December 2019 в 08:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: