2013-09-06 44 views
16

Nó không thực sự là một vấn đề tôi đang có, nhưng hãy tưởng tượng ai đó xây dựng một trang web về thời trung cổ và muốn lưu trữ ngày, làm thế nào họ sẽ đi về nó?Làm thế nào để lưu trữ ngày tháng rất cũ trong cơ sở dữ liệu?

Thông số kỹ thuật cho MySQL DATE cho biết nó sẽ không xuống dưới năm 1000. Điều này có ý nghĩa khi định dạng là YYYY-MM-DD. Làm thế nào bạn có thể lưu trữ thông tin về the death of Kenneth II of Scotland trong 995? Tất nhiên bạn có thể lưu trữ nó như một chuỗi, nhưng có những tùy chọn kiểu ngày thật không?

+1

Trong những trường hợp như thế này, bạn có thể xem xét sử dụng một cơ sở dữ liệu khác nhau; có lẽ PostgreSQL có thể cung cấp phạm vi ngày bạn cần không? ([tài liệu] (http://www.postgresql.org/docs/current/static/datatype-datetime.html) dường như ngụ ý phạm vi ngày lớn hơn đáng kể là có thể) – Spudley

+0

@Spudley: Oracle, DB2, Firebird don ' t có giới hạn đó. Vì vậy, có rất nhiều lựa chọn thay thế. –

+0

@a_horse_with_no_name - PostgreSQL là DB mã nguồn mở nổi tiếng nhất sau mySQL, nhưng có, có rất nhiều tùy chọn. – Spudley

Trả lời

4

Trên thực tế, bạn có thể ngày cửa hàng bên dưới năm 1000 trong MySQL mặc dù thậm chí documentation làm rõ:

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

-bạn vẫn cần phải năm đầu vào ở định dạng 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) 

-và bạn sẽ có thể hoạt động với điều này dưới dạng ngày:

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

Vì sự an toàn. Tôi đã không bao giờ phải đối mặt với một trường hợp khi điều này sẽ không làm việc trong MySQL 5.x (đó, nguyên nhân, không có nghĩa là nó sẽ làm việc 100%, nhưng ít nhất nó là đáng tin cậy với xác suất nhất định)

Giới thiệu về BC ngày (dưới Đấng Christ). Tôi nghĩ điều đó đơn giản - trong MySQL có không có cách nào để lưu trữ ngày phủ định. I E. bạn sẽ cần đến cửa hàng năm riêng biệt như một trường số nguyên ký:

 
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) 

Nhưng tôi nghĩ rằng, trong mọi trường hợp (sau đây/ở trên năm 0) nó tốt hơn đến các bộ phận ngày cửa hàng như số nguyên trong trường hợp đó - điều này sẽ không dựa đến tính năng không có giấy tờ. Tuy nhiên, bạn sẽ cần phải hoạt động với 3 trường đó không phải là ngày (do đó, theo nghĩa nào đó không phải là giải pháp cho vấn đề của bạn)

+0

Sử dụng chức năng ngày tháng so với hackiness. Mẹo tốt! –

+0

@GerbenJacobs nó không phải là tài liệu, có. Nhưng điều này sẽ làm việc trong MySQL 5.x - Tôi đã không bao giờ phải đối mặt với các trường hợp khi nó sẽ không tạo ra kết quả chính xác –

+2

Điều gì về BC ngày? – Adam

0

Đáng buồn thay, tôi nghĩ rằng hiện tại tùy chọn dễ nhất là lưu trữ năm, tháng và ngày trong các trường riêng biệt với năm là smallint.

+0

Và nếu tôi muốn ngày bắt đầu vũ trụ thì sao? :) Smallint dường như không đúng để mô tả vũ trụ hiện tại :-) –

+0

Bạn có thể hỏi người tạo mezzacotta.net cách họ xử lý ngày (vì việc triển khai thực sự có thể xử lý ngày tháng trước tuổi vũ trụ) http: //www.mezzacotta .net/archive.php? date = -9999999999999-01-01 – Mchl

2

Chọn dbms hỗ trợ những gì bạn muốn làm. Trong số các hệ thống quản lý cơ sở dữ liệu miễn phí khác, PostgreSQL hỗ trợ một khoảng thời gian từ 4713 TCN đến 294276 AD.

Nếu bạn chia nhỏ ngày thành các cột riêng biệt cho năm, tháng và ngày, bạn cũng cần nhiều bảng và ràng buộc hơn để đảm bảo rằng giá trị trong các cột đó đại diện cho ngày thực tế. Nếu các cột đó cho phép bạn lưu trữ giá trị {2013, 2, 29}, bảng của bạn bị hỏng. Một dbms hỗ trợ các ngày trong phạm vi của bạn hoàn toàn tránh được loại vấn đề này.

vấn đề khác bạn có thể chạy vào

  • ngày số học không chính xác về số ngày được ra khỏi phạm vi.
  • Định dạng cụ thể theo ngôn ngữ không chính xác vào các ngày nằm ngoài phạm vi.
  • Hành vi đáng ngạc nhiên từ các hàm ngày và giờ vào các ngày nằm ngoài phạm vi phủ sóng.
  • Gregorian calendar weirdness.

Độ kỳ lạ của lịch Gregorian? Ở Anh, ngày sau ngày 2 tháng 9 năm 1752 là ngày 14 tháng 9 năm 1752.PostgreSQL documents their rationale để bỏ qua điều đó như sau.

PostgreSQL sử dụng ngày Julian cho tất cả các tính toán ngày/giờ. Điều này có thuộc tính hữu ích của việc tính toán chính xác các ngày từ 4713 trước Công nguyên đến nay trong tương lai, sử dụng giả định rằng độ dài của năm là 365,2425 ngày.

Quy ước ngày trước thế kỷ 19 tạo ra sự đọc thú vị, nhưng không đủ nhất quán để đảm bảo mã hóa thành ngày/giờ xử lý .

0

Để trích dẫn từ 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. 

Vì vậy, có một sự thay đổi tốt mà một phạm vi rộng lớn hơn sẽ làm việc cho một cài đặt MySQL cấu hình đầy đủ.

Đảm bảo không sử dụng TIMESTAMP, dường như có dải ô không âm.

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. 

Dưới đây là ví dụ JavaScript cách xa kỷ nguyên UNIX (1) bạn có thể nhận được với 2^36 giây * -1000 (để nhận được mili giây cho Javascript).

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

Vì vậy, tôi khuyên bạn nên lưu trữ ngày lịch sử là BIGINT so với kỷ nguyên.

Xem http://dev.mysql.com/doc/refman/5.6/en/integer-types.html cho 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" 
Các vấn đề liên quan