Поддерживает ли MySQL историческую дату (например, 1200)? - PullRequest
18 голосов
/ 21 марта 2010

Я не вижу никакой информации об этом. Где я могу найти самую старую дату, которую может поддерживать Mysql?

Ответы [ 7 ]

33 голосов
/ 21 марта 2010

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

В общем, однако, временные метки не рекомендуется для этого использования. Во-первых, ограничение диапазона является произвольным: в MySQL это 1 января, 1000. Если вы работаете с вещами 12-13-го века, все идет хорошо ... но если в какой-то момент вам нужно добавить что-то более старое (10-го века или ранее) , дата с треском сломается, и исправление проблемы потребует переформатирования всех ваших исторических дат во что-то более адекватное.

Временные метки обычно представляются в виде необработанных целых чисел с заданными «интервалом между тиками» и «точкой эпохи», поэтому число действительно представляет собой число тиков, прошедших с начала до представленной даты (или наоборот для отрицательных дат). Это означает, что, как и для любого типа данных с фиксированным целым числом, набор представимых значений конечен. Большинство известных мне временных форматов о диапазоне жертв в пользу точности, в основном потому, что приложениям, которые должны выполнять арифметику времени, часто приходится делать это с приличной точностью; в то время как приложения, которые должны работать с историческими датами, очень редко должны выполнять серьезную арифметику.

Другими словами, временные метки предназначены для точного представления дат. Второе (или даже доли секунды) исключение не имеет смысла для исторических дат: не могли бы вы сказать мне, вплоть до миллисекунд, когда Генрих 8-й был коронован как король Англии?

В случае MySQL формат по определению определяется как «4-значные годы», поэтому любая связанная оптимизация может основываться на предположении, что год будет иметь 4 цифры или что вся строка будет иметь ровно 10 символов ( "гггг-мм-дд") и т. д. Просто удача в том, что дата, о которой вы упомянули в заголовке, все еще подходит, но даже полагаться на это все же опасно: помимо того, что может хранить сама БД, вы должны знать из того, что остальная часть вашего стека сервера может манипулировать. Например, если вы используете PHP для взаимодействия с вашей базой данных, попытка обработать исторические даты в тот или иной момент может привести к сбою (в 32-разрядной среде диапазон для отметок времени в стиле UNIX составляет от 13 декабря 1901 по 19 января 2038 г.).

В итоге: MySQL будет правильно хранить любую дату с 4-значным годом; но в целом использование меток времени для исторических дат почти всегда вызывает проблемы и головные боли чаще, чем нет. Я настоятельно рекомендую против такого использования.

Надеюсь, это поможет.


Редактировать / дополнение:

Спасибо за это очень интересное ответ. Должен ли я создать свой собственный алгоритм на историческую дату или выберите другую дб но какой? - user284523

Я не думаю, что какая-либо БД имеет слишком большую поддержку для такого рода дат: приложениям, использующим ее, чаще всего достаточно с представлением строк / текста. На самом деле, для дат на 1-м году и позже текстовое представление даже даст правильную сортировку / сравнение (при условии, что дата представлена ​​по порядку величины: y, m, d порядок). Однако сравнения будут прерываться, если также будут задействованы «отрицательные» даты (они все равно будут сравниваться как более ранние, чем любые положительные, но сравнение двух отрицательных дат приведет к обратному результату).

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

В противном случае лучший подход - использовать какое-то число и определить свои собственные «интервал между тиками» и «точки эпохи». Хороший интервал может быть днями (если только вам действительно не нужна дополнительная точность, но даже тогда вы можете полагаться на «действительные» (с плавающей точкой) числа вместо целых); и разумная эпоха может быть 1 января. Основной проблемой будет превращение этих значений в их текстовое представление, и наоборот. Вам необходимо учитывать следующие детали:

  • В високосные годы есть один дополнительный день.
  • Правило для високосных лет было «любым кратным 4» до 1582 года, когда оно изменилось с юлианского на григорианский календарь и стало «кратным 4, за исключением тех, которые кратны 100, если они также не кратны 400»
  • Последний день юлианского календаря был 4 октября 1582 года. Следующий день, первый по григорианскому календарю, был 15 октября 1582 года. Было пропущено 10 дней, чтобы новый календарь снова соответствовал сезонам.
  • Как указано в комментариях, два вышеуказанных правила различаются в зависимости от страны: папские государства и некоторые католические страны действительно приняли новый календарь в указанные даты, но многим другим странам потребовалось больше времени для этого (последний из них - Турция в 1926 году) , Это означает, что любая дата между папским быком в 1582 году и последним усыновлением в 1926 году будет неоднозначной без географического контекста и даже более сложной для обработки.
  • Не существует "года 0": годом до года 1 был год -1 или год 1 до н.э.

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

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

11 голосов
/ 21 марта 2010

Из документации :

ДАТА

Дата. Поддерживаемый диапазон: «1000-01-01» до '9999-12-31'.

5 голосов
/ 21 марта 2010

Да. MySQL даты начало года 1000.

4 голосов
/ 10 августа 2012

Как бы то ни было, я обнаружил, что поле MySQL DATE на практике поддерживает даты <1000, хотя в документации сказано иное.Например, я смог ввести <code>325 и он хранится как 0325-00-00.Поиск WHERE table.date < 1000 также дал правильные результаты.

Но я не решаюсь полагаться на даты <1000, когда они официально не поддерживаются, плюс мне иногда нужны годы BCE с более чем 4 цифрами в любом случае (например, 10000 BCE).Так что отдельные поля INT для года, месяца и дня (как предложено выше) кажутся единственным выбором.</p>

Я бы хотел, чтобы тип DATE (или, возможно, новый тип HISTDATE) поддерживал полный диапазон исторических дат - было бы неплохо объединить три поля в одно и просто отсортировать по дате, а не сортировать по1008 *.

3 голосов
/ 13 апреля 2013

Это важная и интересная проблема, которая имеет другое решение.

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

Это можно сделать с помощью виртуальной машины Java (JVM), где время измеряется в миллисекундах относительно полуночи 1 января 1970 года по Гринвичу (Epoch), путемсохранение требуемого значения как long в базе данных (включая отрицательные значения) и выполнение требуемого преобразования / вычисления в слое компонента после извлечения.

Например:

Date d = new Date(Long.MIN_VALUE);
DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy G HH:mm:ss Z");
System.out.println(df.format(d));

Должен отображаться: Sun, 2 Dec 292269055 BC 16:47:04 + 0000

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

2 голосов
/ 28 февраля 2014

У меня была похожая проблема, и я хотел продолжить ретрансляцию полей даты в БД, чтобы позволить мне использовать поиск по диапазону дат с точностью до дня для исторических значений.(Моя база данных включает дату рождения и даты римских императоров ...)

Решение было добавить постоянный год (пример: 3000) ко всем датам перед добавлением их вDB и вычитая это же число перед отображением результатов запроса пользователям.

Если в вашей базе данных уже есть какое-то значение даты, не забудьте обновить выходное значение новым константным числом.

2 голосов
/ 24 сентября 2012

Используйте SMALLINT для года, поэтому год будет принимать от -32768 (до н.э.) до 32768 (нашей эры). Для месяцев и дней используйте TINYINT UNSIGNED

У большинства исторических событий нет месяцев и днейтак что вы можете запросить вот так:

SELECT events FROM history WHERE year='-4990'

Результат: 'Ноев Ковчег'

Или: SELECT events FROM history WHERE year='570' AND month='4' AND day='20' return: "Мухаммед родился, pbuh"

В зависимоститребования, вы также можете добавить DATETIME столбец и сделать его NULL для даты до 1000 и наоборот (таким образом, сохраняя некоторые байты)

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