2013-09-06 2 views
16

На самом деле это не проблема, которую я имею, но представьте, что кто-то строит веб-сайт о средневековых временах и хочет хранить даты, как бы они это сделали?Как хранить очень старые даты в базе данных?

Спецификация для MySQL DATE говорит, что она не опустится ниже 1000 года. Что имеет смысл, когда формат YYYY-MM-DD. Как вы можете хранить информацию о the death of Kenneth II of Scotland в 995? Конечно, вы можете сохранить его как строку, но есть ли реальные варианты типа даты?

+1

В подобных случаях, вы можете рассмотреть возможность использования другой базы данных; возможно, PostgreSQL может предоставить диапазоны дат, которые вам нужны? ([docs] (http://www.postgresql.org/docs/current/static/datatype-datetime.html), по-видимому, подразумевает значительно больший диапазон дат) – Spudley

+0

@Spudley: Oracle, DB2, Firebird don ' У меня есть это ограничение. Таким образом, есть много альтернатив. –

+0

@a_horse_with_no_name - PostgreSQL является самым известным открытым исходным кодом после mySQL, но да, есть много вариантов. – Spudley

ответ

4

На самом деле, вы можете хранить даты ниже 1000 года в MySQL, несмотря даже documentation осветления:

 
mysql> describe test; 
+-------+---------+------+-----+---------+-------+ 
| Field | Type | Null | Key | Default | Extra | 
+-------+---------+------+-----+---------+-------+ 
| id | int(11) | YES |  | NULL |  | 
| birth | date | YES |  | NULL |  | 
+-------+---------+------+-----+---------+-------+ 

-вы еще нужно ввести год в формате YYYY:

 
mysql> insert into test values (1, '0995-03-05'); 
Query OK, 1 row affected (0.02 sec) 

mysql> select * from test; 
+------+------------+ 
| id | birth  | 
+------+------------+ 
| 1 | 0995-03-05 | 
+------+------------+ 
1 row in set (0.00 sec) 

-А ты будет иметь возможность работать с этим как :

 
mysql> select birth + interval 5 day from test;                    
+------------------------+                         
| birth + interval 5 day |                         
+------------------------+                         
| 0995-03-10    | 
+------------------------+ 
1 row in set (0.03 sec) 

Что касается безопасности. Я никогда не сталкивался с тем случаем, когда это не будет работать в MySQL 5.x (это, по сути, не означает, что он будет работать на 100%, но, по крайней мере, он надежен с определенной вероятностью)

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

 
mysql> select '0001-05-04' - interval 1 year as above_bc, '0001-05-04' - interval 2 year as below_bc; 
+------------+----------+ 
| above_bc | below_bc | 
+------------+----------+ 
| 0000-05-04 | NULL  | 
+------------+----------+ 
1 row in set, 1 warning (0.00 sec) 

mysql> show warnings; 
+---------+------+--------------------------------------------+ 
| Level | Code | Message         | 
+---------+------+--------------------------------------------+ 
| Warning | 1441 | Datetime function: datetime field overflow | 
+---------+------+--------------------------------------------+ 
1 row in set (0.00 sec) 

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

+0

Использование функций даты и взлома. Хороший совет! –

+0

@GerbenJacobs не документировано, да. Но это будет работать в MySQL 5.x. Я никогда не сталкивался с тем случаем, когда он не даст правильный результат. –

+2

Как насчет дат BC? – Adam

0

К сожалению, я считаю, что в настоящее время самый простой вариант - хранить год, месяц и день в отдельных полях с годом как smallint.

+0

А что, если я хочу навестить начало вселенной? :) Smallint не подходит для описания текущей вселенной :-) –

+0

Возможно, вы спросите создателей mezzacotta.net, как они обрабатывают даты (поскольку их реализация может фактически обрабатывать даты, предшествующие возрасту вселенной) http: //www.mezzacotta .net/archive.php? date = -9999999999999-01-01 – Mchl

2

Выберите dbms, который поддерживает то, что вы хотите сделать. Среди других бесплатных систем управления базами данных PostgreSQL поддерживает временной диапазон от 4713 до 294276 н.э.

Если вы разделите дату на отдельные столбцы на год, месяц и день, вам также потребуется больше таблиц и ограничений, чтобы гарантировать, что значения в этих столбцах представляют фактические даты. Если эти столбцы позволяют хранить значение {2013, 2, 29}, ваша таблица будет разбита. Dbms, поддерживающий даты в вашем диапазоне, полностью исключает эту проблему.

Другие проблемы, которые могут работать в

  • Неверная дата арифметики в сроки, которые находятся вне диапазона.
  • Неправильное форматирование, специфичное для локали, для дат, находящихся за пределами допустимого диапазона.
  • Удивительное поведение с использованием функций даты и времени по датам, которые находятся за пределами допустимого диапазона.
  • Gregorian calendar weirdness.

Григорианский календарь странности? В Великобритании, на следующий день после 2 сентября 1752 года - 14 сентября 1752 года.PostgreSQL documents their rationale, игнорируя это следующим образом.

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

Соглашения о сроках до XIX века составляют интересное чтение, , но недостаточно согласованы, чтобы гарантировать кодирование в дату/время. обработчик.

0

Цитирует http://dev.mysql.com/doc/refman/5.6/en/datetime.html

For the DATE and DATETIME range descriptions, “supported” means that although earlier values might work, there is no guarantee. 

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

Убедитесь, что не используется TIMESTAMP, который, как представляется, имеет неотрицательный диапазон.

The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC. 

Вот пример JavaScript, как далеко до эпохи UNIX (1) вы можете получить с 2^36 секунд * -1000 (чтобы добраться до миллисекунд для Javascript).

d = new Date((Math.pow(2, 36) - 1) * -1000) 
Sun May 13 -208 18:27:45 GMT+0200 (Westeuropäische Sommerzeit) 

Поэтому я предлагаю хранить исторические даты как BIGINT относительно эпохи.

См. http://dev.mysql.com/doc/refman/5.6/en/integer-types.html для MxSQL 5.6.


(1)

epoch = new Date(0) 
Thu Jan 01 1970 01:00:00 GMT+0100 (Westeuropäische Normalzeit) 
epoch.toUTCString() 
"Thu, 01 Jan 1970 00:00:00 GMT"