Làm thế nào để bạn lưu trữ những ngày mờ mờ vào một cơ sở dữ liệu?


125

Đây là một vấn đề tôi đã gặp phải một vài lần. Hãy tưởng tượng bạn có một bản ghi mà bạn muốn lưu trữ vào một bảng cơ sở dữ liệu. Bảng này có cột DateTime được gọi là "date_created". Bản ghi cụ thể này đã được tạo từ lâu và bạn không thực sự chắc chắn về ngày chính xác, nhưng bạn biết năm và tháng. Hồ sơ khác bạn biết chỉ trong năm. Hồ sơ khác bạn biết ngày, tháng và năm.

Bạn không thể sử dụng trường DateTime, vì "Tháng 5 năm 1978" không phải là ngày hợp lệ. Nếu bạn chia nó thành nhiều cột, bạn sẽ mất khả năng truy vấn. Có ai khác chạy vào đây, nếu vậy làm thế nào bạn xử lý nó?

Để làm rõ hệ thống tôi đang xây dựng, nó là một hệ thống theo dõi tài liệu lưu trữ. Một số nội dung đã được sản xuất từ ​​lâu và tất cả những gì chúng ta biết là "Tháng 5 năm 1978". Tôi có thể lưu trữ nó vào ngày 1 tháng 5 năm 1978, nhưng chỉ với một số cách để biểu thị rằng ngày này chỉ chính xác theo tháng. Cách đó vài năm sau khi tôi lấy kho lưu trữ đó, tôi không bối rối khi ngày không khớp.

Đối với mục đích của tôi, điều quan trọng là phân biệt "ngày chưa biết vào tháng 5 năm 1978" với "ngày 1 tháng 5 năm 1978". Ngoài ra, tôi sẽ không muốn lưu trữ các ẩn số là 0, như "0 tháng 5 năm 1978" bởi vì hầu hết các hệ thống cơ sở dữ liệu sẽ từ chối đó là giá trị ngày không hợp lệ.


14
Có quan trọng để phân biệt "ngày chưa biết vào tháng 5 năm 1978" với "ngày 1 tháng 5 năm 1978" không?

5
@MichaelT: vâng, điều quan trọng là phải phân biệt.
nbv4


6
@aslum: Hầu hết các hệ thống cơ sở dữ liệu sẽ từ chối đó là giá trị ngày không hợp lệ
nbv4

9
@JimmyHoffa - bạn chưa bao giờ gặp phải tình huống ngày mờ hoặc bạn cần so sánh ngày nào? Trong cả hai trường hợp, một trường hợp phổ biến là một lịch sử y tế: bạn nhớ rằng phẫu thuật cắt ruột thừa là vào năm ngoái vào ngày 1 tháng 4, nhưng phẫu thuật cắt amidan là vào năm 1975, và một điều khác đã xảy ra vào tháng Năm và tháng Sáu của một năm nào đó. Điều gì nếu bạn muốn biết nếu một số sự kiện y tế là trước hoặc sau một số đột phá y tế khác? Điều này xảy ra trước hay sau khi họ kiểm tra nguồn cung cấp máu cho HIV?
thứ năm

Câu trả lời:


148

Lưu trữ tất cả các ngày trong trường DATE bình thường trong cơ sở dữ liệu và có trường chính xác bổ sung về trường DATE chính xác thực sự là như thế nào.

date_created DATE,
date_created_accuracy INTEGER, 

date_created_accuracy: 1 = ngày chính xác, 2 = tháng, 3 = năm.

Nếu ngày của bạn mờ (ví dụ: tháng 5 năm 1980), hãy lưu trữ vào đầu giai đoạn (ví dụ: ngày 1 tháng 5 năm 1980). Hoặc nếu ngày của bạn chính xác đến năm (ví dụ 1980) lưu trữ vào ngày 1 tháng 1. 1980 với giá trị chính xác tương ứng.

Cách này có thể dễ dàng truy vấn theo cách hơi tự nhiên và vẫn có khái niệm ngày chính xác như thế nào. Ví dụ, điều này cho phép bạn truy vấn ngày giữa Jan 1st 1980Feb 28th 1981, và nhận được ngày mờ 1980May 1980.


1
Bạn vẫn phải tính ngày kết thúc ở đây từ những gì tôi có thể thấy, vì vậy tôi nghĩ rằng ở giữa truy vấn khá xấu vì bạn đã có một trường được tính toán mà bạn đang chọn tốt nhất.
Wyatt Barnett

8
Câu trả lời hay, thực sự thông minh. select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;. Thiên tài.
Naftuli Kay

58
Tôi sẽ khuyến khích bạn coi độ chính xác của ngày chỉ là "ngày". Trong đó một ngày chính xác là 0. Bằng cách này, người ta có thể sử dụng ngày linh hoạt hơn "Đôi khi vào mùa hè" có độ chính xác là 90 ngày dựa trên ngày 1 tháng 6 thay vì phạm vi ngày cụ thể được mã hóa cứng. Nó cũng có thể xử lý độ chính xác nhiều năm.

1
Bạn có thể nên gửi câu trả lời đó, MichaelT
Supr

1
+1: Một điều thú vị khác về giải pháp này là bạn có thể thêm logic hiển thị dựa trên giá trị của date_created_accuracytrường. Bạn có thể hiển thị "tháng 5 năm 1980" hoặc chỉ "1980" trong kết quả hoặc giao diện người dùng nếu điều đó chính xác như trường chỉ ra.
Kyralessa

27

Nếu bạn không cần sử dụng loại dữ liệu này như thông tin ngày giờ thông thường, bất kỳ định dạng chuỗi đơn giản nào cũng được.

Nhưng nếu bạn cần giữ tất cả các chức năng, có hai cách giải quyết tôi có thể nghĩ ra, cả hai đều yêu cầu thông tin bổ sung được lưu trữ trong cơ sở dữ liệu:

  1. Tạo min datemax datecác trường, có các giá trị khác nhau cho dữ liệu "không đầy đủ", nhưng sẽ trùng với ngày chính xác.
  2. Tạo các loại cho từng loại ngày không chính xác (không có _ 0, date_missing _ 1, tháng_missing _ 2, year_missing_4, vv _ để bạn có thể kết hợp chúng). Thêm một typetrường vào các bản ghi và giữ thông tin nào bị thiếu.

Các trường ngày tối thiểu và tối đa là suy nghĩ đầu tiên của tôi là tốt.
Michael Itzoe

1
Khởi động từ lâu, chúng tôi đã phải giải quyết vấn đề chính xác tương tự. Người dùng có thể kể chuyện về các sự kiện xảy ra bất cứ lúc nào trong quá khứ, vì vậy chúng tôi phải hỗ trợ ngày mờ. Sau nhiều lần qua lại, giải pháp mà chúng tôi đã đưa ra gần giống với đề xuất của superM ở đây, trong đó ngày được lưu trữ dưới dạng các nội dung tối thiểu và tối đa có thể chứa ngày của câu chuyện. Khi báo cáo ngày, độ chính xác (nghĩa là "bản ghi này chính xác theo tháng / năm / ngày") có thể được trích xuất từ ​​đồng bằng giữa các ngày tối thiểu và tối đa. Không cần lưu trữ trường thứ 3 cho chính xác.
đáp ứng

4
+1 cho min datemax datecác trường. Tôi nghĩ rằng đó là giải pháp linh hoạt nhất, nhưng chính xác và dễ sử dụng.
Supr

1
Tôi đã phản đối ý tưởng này lúc đầu. Nhưng nhận ra đó là cách tiếp cận linh hoạt nhất, tôi bỏ phiếu cho điều này.
Anurag Kalia

Nó chỉ là tự nhiên. Bạn đang mô tả không quá nhiều về một ngày mờ nhạt mà là một khung thời gian ..... có bắt đầu và kết thúc.
Pieter B

20

Đây thực sự là một định nghĩa yêu cầu nhiều hơn là một vấn đề kỹ thuật - điều bạn cần tập trung vào là "làm thế nào chúng ta có thể xác định ngày trong quá khứ" và giải pháp kỹ thuật sẽ chảy.

Những lần tôi phải tiếp cận một cái gì đó như thế này, chúng tôi thường:

  • Xác định cách lập bản đồ mọi thứ - như MichaelT gợi ý , quyết định rằng mọi thứ được xác định là Tháng / Ngày sẽ được xác định là nửa đêm vào ngày đầu tiên của tháng. Điều này thường đủ tốt cho hầu hết các mục đích - nếu ngày chính xác là quan trọng thì có lẽ bạn sẽ có một hồ sơ về nó 35 năm sau, phải không?
  • Tìm hiểu xem bạn có cần theo dõi điều này không - IE, các bản ghi có ngày tạo ra hơi cần một lá cờ nói như vậy không? Hoặc đó chỉ là một vấn đề đào tạo người dùng để mọi người biết và có thể hành động phù hợp.

Đôi khi, người ta cần phải làm một cái gì đó như làm cho ngày trở nên mờ nhạt - ví dụ, có thể một ngày có thể cần phải trả lời một truy vấn cho bất kỳ điều gì vào tháng 5 năm 1978. Điều này có thể thực hiện được - chỉ cần làm cho các trường created_date 2 của bạn, các bản ghi cũ nhận được 30 ngày trải đều khi thích hợp, những cái mới nhận được 2 giá trị giống hệt nhau.


1
+1 - Tôi đang nghiên cứu xây dựng câu trả lời với cách tiếp cận ngày kép. Câu trả lời của bạn đã ở đây đầu tiên.

2
+1, Thật xấu xí và tạo ra nhiều thông tin bổ sung vô dụng cho các mục mới không yêu cầu, nhưng mặt khác, nó giữ cho các truy vấn đơn giản hơn nhiều so với những gì khác. Chúng tôi đã sử dụng một giải pháp tương tự cho một vấn đề liên quan bây giờ.
Izkata

3
@Izkata - Điểm công bằng, nhưng bạn có thể thanh lịch đến mức nào khi bạn cần làm một thứ gì đó nên là một điểm duy nhất trong khoảng thời gian một tháng. Chắc chắn là đẹp hơn việc phải tính toán bắt đầu và kết thúc cho các truy vấn đang bay ở đâu đó.
Wyatt Barnett

1
+1 để có thể biểu thị mức độ chi tiết tùy ý mà không có sự bùng nổ của các giá trị enum.
Dan Neely

18

Cách đơn giản nhất để biểu thị nếu ngày chính xác là tạo trường chính xác INT (1) với NULL mặc định

Nếu ngày chính xác là thời gian lưu trữ theo ngày trong "date_created" và để lại độ chính xác NULL

Nếu ngày chỉ chính xác với tháng lưu trữ thời gian là ngày đầu tiên của tháng với giá trị chính xác 1

Nếu ngày chỉ chính xác cho năm lưu trữ vào ngày 1 tháng 1 với giá trị chính xác 2

Bạn có thể sử dụng các số khác nhau để giữ các giá trị khác nhau, chẳng hạn như quý đầu tiên, v.v.


Truy vấn trở nên thực sự lông khi bạn làm điều đó.
Blrfl

3
Điều này gặp khó khăn với dữ liệu không nằm trong ranh giới tháng sạch như "Quý 2 năm 1991" và "Mùa đông 1978-1979".

1
OP muốn một số cách để biểu thị rằng ngày này chỉ chính xác theo tháng.
david strachan

7
Bạn đang lạm dụng ý nghĩa của NULL ở đây. NULL có nghĩa là "không xác định", vì vậy nếu ngày chính xác, độ chính xác không thể là NULL. Nó có thể là '1'.
Konerak

@Konerak Về mặt ngữ nghĩa có. Nhưng vì phần lớn các ngày là chính xác, chỉ những trường hợp đặc biệt cần được xác định và sử dụng NULL ở đây làm mặc định.
david strachan

17

Trước đây, tôi đã lưu trữ ngày với độ chính xác là ngày bắt đầu và ngày kết thúc. Ngày may 21,2012 sẽ được biểu thị là start = 12 am,may21,2012 và end = 12 am,may22,2012. Năm 2012 sẽ được biểu thị là bắt đầu = 12 am,Jan1,2012 end = 12 am,Jan1,2013.

Tôi không chắc chắn nếu tôi muốn giới thiệu phương pháp này. Khi hiển thị thông tin cho người dùng, bạn cần phát hiện chính xác rằng phạm vi ngày chính xác bao gồm một ngày để hiển thị "có thể 25" thay vì hai điểm cuối quá cụ thể (có nghĩa là xử lý tiết kiệm ánh sáng ban ngày và vv).

Tuy nhiên, khi bạn không cố dịch sang người, việc lập trình với các điểm cuối dễ dàng hơn rất nhiều so với độ chính xác + trung tâm. Bạn không kết thúc với rất nhiều trường hợp. Điều đó thật tuyệt.


Trên thực tế, không cần quá khó khăn để xác định cách trình bày một phạm vi nếu phạm vi luôn được lưu trữ dưới dạng UTC. Theo dấu thời gian của UTC, mỗi ngày, tuần, tháng, năm - thậm chí cả mùa và quý - sẽ có hai số không đổi, toàn cầu, khác biệt và dễ xác định đại diện cho sự bắt đầu và kết thúc của giai đoạn. Logic đơn giản trở thành một vài câu lệnh if để xem hai ngày đó có ở đầu và cuối của một số loại thời gian hay không. Không có công cụ toán học hoặc múi giờ phức tạp nào cần thiết :)
Supr

@Supr Xác định xem một giây cụ thể có ở biên giới của một thời kỳ con người cụ thể hay không, là một vấn đề khó khăn. Đặc biệt là trong thời gian dài, với vòng quay của Trái đất chậm lại và không ngừng thay đổi nhỏ theo định nghĩa của con người về thời gian địa phương.
Craig Gidney

14

Tại sao không lưu trữ hai ngày.

Created_After và created_B Before. Các ngữ nghĩa thực tế được "tạo ra trên hoặc sau" và "được tạo ra trên hoặc trước"

Vì vậy, nếu bạn biết ngày chính xác thì created_After và created_B Before sẽ là cùng một ngày.

Nếu bạn biết đó là tuần đầu tiên vào tháng 5 năm 2000 thì created_After = '2000-05-01' và created_B Before = '2000-05-07'.

Nếu bạn chỉ biết tháng 5 năm 1999 thì các giá trị sẽ là '1999-05-01' và '1999-05-30'.

Nếu đó là "Mùa hè của '42" thì các giá trị sẽ là '1942-06-01' và '1942-08-31'.

Lược đồ này đơn giản để truy vấn với SQL thông thường và khá dễ dàng cho người dùng không có kỹ thuật theo dõi.

Ví dụ: để tìm tất cả các tài liệu có thể đã được tạo vào tháng 5 năm 2001:

SELECT * FROM DOCTAB WHERE Created_After < '2001-05-31' And Created_Before > 2001-05-01;

Ngược lại, để tìm tất cả các tài liệu chắc chắn được tạo vào tháng 5 năm 2001:

SELECT * FROM DOCTAB WHERE Created_After > '2001-05-01' And Created_Before < 2001-05-31;

1
Tôi nghĩ rằng đây là giải pháp thanh lịch nhất.
Pieter B

Điều này giống như câu trả lời của superM và Strilanc. +1 mặc dù để giải thích rõ ràng hơn và cho thấy việc truy vấn sẽ đơn giản như thế nào.
Supr

9

Định dạng thời gian ngày ISO 8601 đi kèm với định nghĩa thời lượng, ví dụ:

2012-01-01P1M (đọc: 2012, ngày 1 tháng 1, giai đoạn: 1 tháng) là những gì nên có trong tháng 1 năm 2012.

Tôi sẽ sử dụng điều này để lưu trữ dữ liệu. Bạn có thể cần một trường cơ sở dữ liệu kiểu String để làm như vậy. Đó là một chủ đề khác nhau làm thế nào để tiến hành một tìm kiếm hợp lý về điều đó.


+1 cho ý tưởng nhưng -1 vì không sử dụng trường ngày vì lý do làm thế nào để tìm kiếm và / hoặc tìm
user151019

Phụ thuộc vào cơ sở dữ liệu. Tuy nhiên, điều này có thể là cơ sở để mở rộng, nhưng câu hỏi là: Tài liệu trong tập kết quả có được không nếu bạn tìm kiếm, trong trường hợp này, tất cả các tài liệu mới hơn ngày 12 tháng 1, phải không? Nó không tầm thường. Ở đây, câu hỏi là làm thế nào để lưu trữ ngày mờ.
Matthias Rrid

3

Nói chung, tôi vẫn lưu trữ chúng dưới dạng ngày để truy vấn chung vẫn có thể ngay cả khi hơi kém chính xác.

Nếu điều quan trọng là phải biết độ chính xác mà tôi có trong quá khứ hoặc đã lưu trữ một "cửa sổ" chính xác dưới dạng thập phân +/- hoặc dưới dạng tra cứu (ngày, tháng, năm, v.v.). Trong các trường hợp khác thay vì cửa sổ, tôi chỉ lưu trữ giá trị ngày ban đầu dưới dạng chuỗi và chuyển đổi những gì tôi có thể thành datetime, có thể là 1978-05-01 00:00:00 và "May 1978" cho ví dụ của bạn.


3

Nếu bạn chia nó thành nhiều cột, bạn sẽ mất khả năng truy vấn.

Nói ai? Đây là những gì bạn làm:

  1. Có 3 cột, Ngày, Tháng, Năm, mỗi loại int và một cột thứ tư Loại ngày của DateTime.
  2. Có một trình kích hoạt sử dụng 3 cột Ngày, Tháng, Năm để xây dựng TheDate nếu TheDate bị bỏ trống nhưng một hoặc nhiều trường Ngày, Tháng, Năm có giá trị.
  3. Có một trình kích hoạt cư trú các trường Ngày, Tháng, Năm khi TheDate được cung cấp nhưng các trường này thì không.

Vì vậy, nếu tôi thực hiện một thao tác chèn như: insert into thistable (Day, Month, Year) values (-1, 2, 2012);thì TheDate sẽ trở thành 2/1/2013 nhưng tôi sẽ biết đó thực sự là một ngày không xác định vào tháng 2/2012 vì -1 trong trường Ngày.

Nếu tôi insert into thistable (TheDate) values ('2/5/2012');thì Ngày sẽ là 5, Tháng sẽ là 2 và Năm sẽ là 2012 và vì không ai trong số họ là -1 nên tôi sẽ biết đây là ngày chính xác.

Tôi không mất khả năng truy vấn vì trình kích hoạt chèn / cập nhật đảm bảo 3 trường của tôi (Ngày, Tháng, Năm) luôn tạo ra giá trị DateTime trong TheDate có thể được truy vấn.


3

Một lựa chọn khác là lưu trữ ngày dưới dạng số nguyên của biểu mẫu YYYYMMDD.

  • Bạn chỉ biết năm là 1951: Cửa hàng như 19510000
  • Bạn biết tháng và năm là tháng 3 năm 1951: Lưu trữ dưới dạng 19510300
  • Bạn biết ngày đầy đủ là ngày 14 tháng 3 năm 1951: Lưu trữ dưới dạng 19510314
  • Một ngày hoàn toàn không xác định: Lưu trữ dưới dạng 0

Những lợi ích

Bạn có thể lưu trữ ngày mờ của bạn trong một trường thay vì hai trường ngày hoặc một ngày và độ chính xác như nhiều câu trả lời khác đề xuất.

Truy vấn vẫn dễ dàng:

  • tất cả các hồ sơ cho năm 1951 - SELECT * FROM table WHERE thedate>=19510000 and thedate<19520000
  • tất cả các hồ sơ cho tháng 3 năm 1951 - SELECT * FROM table where thedate>=19510300 and thedate<19510400
  • tất cả hồ sơ cho ngày 14 tháng 3 năm 1951 - SELECT * FROM table where thedate=19510314

GHI CHÚ

  • GUI của bạn sẽ cần một GetDateString(int fuzzyDate)cái khá dễ thực hiện.
  • Sắp xếp dễ dàng với định dạng int. Bạn nên biết rằng ngày chưa biết sẽ đến đầu tiên. Bạn có thể đảo ngược điều này bằng cách sử dụng 99cho 'phần đệm' thay vì 00cho tháng hoặc ngày.

Làm thế nào để bạn đại diện cho ngày mờ nhạt của "mùa đông 1941-1942"? Đó có thể là tháng 12 năm 1941 hoặc tháng 1 năm 1942.

1
Câu hỏi của bạn có liên quan đến một trường hợp giải pháp chung. Câu hỏi ban đầu không liệt kê đây là một vấn đề. Dựa trên câu hỏi được đăng, đôi khi ngày đầy đủ được biết, đôi khi chỉ năm và tháng, và đôi khi chỉ năm. Không có vấn đề về phạm vi ngày mờ được đề cập như một yêu cầu. Tôi đồng ý bạn cần hai ngày nếu bạn cần giải quyết vấn đề này (mặc dù, việc lưu trữ phạm vi dưới dạng hai "số ngày mờ" có thể cung cấp sự linh hoạt hơn khi lưu trữ hai ngày "cứng").
Rick

1

ISO 8601 cũng chỉ định một cú pháp cho "ngày mờ". Ngày 12 tháng 2 năm 2012 lúc 3 giờ chiều sẽ là "2012 / 02-12T15" và tháng 2 năm 2012 có thể chỉ đơn giản là "2012/02". Điều này mở rộng độc đáo bằng cách sử dụng sắp xếp từ điển tiêu chuẩn:

$ (echo "2013-03"; echo "2013-03"; echo "2012-02-12T15"; echo "2012-02"; echo "2011") | sort
2011
2012
2012-02
2012-02-12T15
2013-03

0

Đây là ý kiến ​​của tôi về điều này:

Chuyển từ ngày mờ sang đối tượng datetime (sẽ phù hợp với cơ sở dữ liệu)

import datetime
import iso8601

def fuzzy_to_datetime(fuzzy):
    flen = len(fuzzy)
    if flen == 4 and fuzzy.isdigit():
        dt = datetime.datetime(year=int(fuzzy), month=1, day=1, microsecond=111111)

    elif flen == 7:
        y, m = fuzzy.split('-')
        dt = datetime.datetime(year=int(y), month=int(m), day=1, microsecond=222222)

    elif flen == 10:
        y, m, d = fuzzy.split('-')
        dt = datetime.datetime(year=int(y), month=int(m), day=int(d), microsecond=333333)

    elif flen >= 19:
        dt = iso8601.parse_date(fuzzy)

    else:
        raise ValueError("Unable to parse fuzzy date: %s" % fuzzy)

    return dt

Và sau đó, một hàm lấy đối tượng datetime và chuyển nó trở lại thành một ngày mờ.

def datetime_to_fuzzy(dt):
    ms = str(dt.microsecond)
    flag1 = ms == '111111'
    flag2 = ms == '222222'
    flag3 = ms == '333333'

    is_first = dt.day == 1
    is_jan1 = dt.month == 1 and is_first

    if flag1 and is_jan1:
        return str(dt.year)

    if flag2 and is_first:
        return dt.strftime("%Y-%m")

    if flag3:
        return dt.strftime("%Y-%m-%d")

    return dt.isoformat()

Và sau đó là một bài kiểm tra đơn vị. Tôi đã bỏ lỡ bất kỳ trường hợp?

if __name__ == '__main__':
    assert fuzzy_to_datetime('2001').isoformat() == '2001-01-01T00:00:00.111111'
    assert fuzzy_to_datetime('1981-05').isoformat() == '1981-05-01T00:00:00.222222'
    assert fuzzy_to_datetime('2012-02-04').isoformat() == '2012-02-04T00:00:00.333333'
    assert fuzzy_to_datetime('2010-11-11T03:12:03Z').isoformat() == '2010-11-11T03:12:03+00:00'

    exact = datetime.datetime(year=2001, month=1, day=1, microsecond=231)
    assert datetime_to_fuzzy(exact) == exact.isoformat()

    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=1, day=1, microsecond=111111)) == '2001'
    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=3, day=1, microsecond=222222)) == '2001-03'
    assert datetime_to_fuzzy(datetime.datetime(year=2001, month=6, day=6, microsecond=333333)) == '2001-06-06'

    assert datetime_to_fuzzy(fuzzy_to_datetime('2002')) == '2002'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2002-05')) == '2002-05'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2002-02-13')) == '2002-02-13'
    assert datetime_to_fuzzy(fuzzy_to_datetime('2010-11-11T03:12:03.293856+00:00')) == '2010-11-11T03:12:03.293856+00:00'

Có một trường hợp góc trong đó một sự kiện xảy ra chính xác tại 2001-01-01T00:00:00.333333nhưng hệ thống sẽ diễn giải như chỉ là "2001", nhưng điều đó dường như rất khó xảy ra.


0

Tôi làm việc cho một công ty xuất bản kinh doanh nhiều sách cũ, nơi chúng tôi thường không thể có được ngày chính xác cho mọi thứ. Chúng tôi thường có hai lĩnh vực cho một mục ngày nào đó, ngày và một khoảng boolean:

date date
dateCirca enum('Y', 'N')

Chúng tôi sử dụng trường ngày để chỉ ra ngày của một số sự kiện hoặc một ngày "đủ gần" trong trường hợp chúng tôi không biết ngày thực sự. Trong trường hợp chúng tôi không biết ngày thực sự, chúng tôi đánh dấu dateCircatrường đó Yvà đưa ra một ngày đủ gần, được đánh dấu là "ngày 1", chẳng hạn như

1st March, 2013  // We don't know the day of the month
1st January, 2013  // We don't know the month/day of the year
1st January, 2000  // We don't know the month/day/year, we only know the century

0

Tổng quan

Có nhiều cách biểu diễn có thể, và do đó, lược đồ cơ sở dữ liệu, để lưu trữ thời gian ngày mờ (hoặc thậm chí chỉ là ngày mờ):

  1. Ngày và mã cho biết độ chính xác hoặc độ chính xác của nó
  2. Ngày và thời gian trong đó có một số khả năng để biểu thị một khoảng:
    1. Biểu diễn tất cả các khoảng dưới dạng số nguyên (hoặc số khác) của một số đơn vị cố định, ví dụ: ngày, phút, nano giây.
    2. Biểu thị một khoảng là cả số lượng (hoặc số khác) và mã chỉ đơn vị của nó.
  3. Ngày bắt đầu và ngày kết thúc
  4. Chuỗi
  5. Phân phối xác suất:
    1. Các đại lượng thập phân hoặc dấu phẩy động cho các tham số chỉ định phân phối cụ thể trong một họ cụ thể, ví dụ: độ lệch trung bình và độ lệch chuẩn của phân phối chuẩn.
    2. Hàm phân phối xác suất, ví dụ như mã (tra cứu) (có khả năng với các tham số của các giá trị cụ thể) hoặc dưới dạng biểu thức bằng ngôn ngữ, định dạng hoặc biểu diễn đủ biểu cảm.

[1], [2] và [3] là tất cả các khoảng thời gian thống nhất (ngầm), tức là một tập hợp các điểm (bằng nhau) có thể theo thời gian.

[4] là cách diễn đạt nhất, nghĩa là khi cho phép bất kỳ câu hoặc cụm từ ngôn ngữ viết có thể (hoặc ít nhất là dài tùy ý). Nhưng nó cũng là khó nhất để làm việc với. Trong giới hạn, AI ở cấp độ con người sẽ được yêu cầu xử lý các giá trị tùy ý. Trên thực tế, phạm vi của các giá trị có thể sẽ cần phải được hạn chế nghiêm ngặt và các giá trị 'có cấu trúc' thay thế có thể sẽ được ưu tiên cho nhiều hoạt động, ví dụ như sắp xếp, tìm kiếm.

[5] có lẽ là đại diện nhỏ gọn chung nhất mà (phần nào) thực tế.

Khoảng thời gian thống nhất

Khoảng thời gian thống nhất là cách nhỏ gọn đơn giản nhất để biểu diễn một tập hợp các giá trị thời gian (có thể).

Đối với [1], các phần của giá trị thời gian ngày bị bỏ qua, tức là các phần tương ứng với các đơn vị nhỏ hơn độ chính xác hoặc độ chính xác được chỉ định; mặt khác, điều này tương đương với [2] và mã chính xác / chính xác tương đương với một khoảng có cùng đơn vị (và số lượng ngụ ý là 1).

[2] và [3] tương đương rõ ràng. [1] hoàn toàn ít biểu cảm hơn một trong hai khoảng thời gian hiệu quả không thể được biểu thị bằng [1], ví dụ. thời gian ngày mờ tương đương với khoảng thời gian 12 giờ kéo dài một ranh giới ngày.

[1] người dùng dễ dàng nhập liệu hơn bất kỳ đại diện nào khác và thường yêu cầu gõ ít nhất (ít nhất một chút). Nếu thời gian ngày có thể được nhập vào trong các biểu diễn văn bản khác nhau, ví dụ: "2013", "2014-3", "2015-5-2", "30/7/2016 11p", "2016-07-31 18:15" , độ chính xác hoặc độ chính xác cũng có thể được suy ra tự động từ đầu vào.

Độ chính xác hoặc độ chính xác của [1] cũng dễ dàng nhất để chuyển đổi thành một hình thức được chuyển đến người dùng, ví dụ: '2015-5 với độ chính xác của tháng' thành "tháng 5 năm 2015", so với "ngày 13 tháng 5 năm 2015 2p, cộng hoặc trừ 13,5 ngày" (tho lưu ý rằng cái sau không thể được đại diện bởi [1] anyways).

Dây

Thực tế, các giá trị chuỗi sẽ cần phải được chuyển đổi sang các biểu diễn khác để truy vấn, sắp xếp hoặc so sánh nhiều giá trị. Vì vậy, trong khi bất kỳ ngôn ngữ tự nhiên (con người) bằng văn bản nào biểu cảm rõ ràng hơn [1], [2], [3] hoặc [5], chúng tôi chưa có phương tiện xử lý vượt quá các định dạng hoặc định dạng văn bản tiêu chuẩn. Cho rằng, đây có lẽ là đại diện ít hữu ích nhất của chính nó .

Một lợi thế của biểu diễn này là trong thực tế, các giá trị phải được trình bày cho người dùng theo nguyên trạng và không yêu cầu chuyển đổi để dễ hiểu.

Phân bố xác suất

Phân phối xác suất tổng quát hóa các biểu diễn khoảng thống nhất [1], [2], [3] và (có thể nói là) tương đương với biểu diễn chuỗi (chung) [4].

Một lợi thế của phân phối xác suất trên các chuỗi là trước đây là không rõ ràng.

[5-1] sẽ phù hợp với các giá trị (hầu hết) phù hợp với phân phối hiện có, ví dụ: đầu ra giá trị thời gian theo ngày từ một thiết bị có các phép đo được biết (hoặc suy nghĩ) phù hợp với phân phối cụ thể.

[5-2] có lẽ là cách thực tế (phần nào) tốt nhất để biểu diễn gọn gàng các giá trị 'thời gian mờ' tùy ý. Tất nhiên, khả năng tính toán của các phân phối xác suất cụ thể đã sử dụng các vấn đề và chắc chắn có những vấn đề thú vị (và có lẽ không thể) được giải quyết khi truy vấn, sắp xếp hoặc so sánh các giá trị khác nhau, nhưng rất nhiều điều này có thể đã được biết hoặc giải quyết ở đâu đó trong hiện tại toán học và thống kê tài liệu vì vậy điều này chắc chắn đứng như một đại diện cực kỳ chung chung và không mơ hồ.


-1

Tôi thực sự thích giải pháp của James Anderson - Giới hạn chính xác các ngày là cách để có được cấu trúc truy vấn linh hoạt nhất. Một cách khác để đạt được điều tương tự là sử dụng một trung tâm bắt đầu, kết thúc hoặc thậm chí datecộng với một interval(ít nhất là có sẵn trong PostgreQuery , OracleSQLAlchemy ).


-2

Trong trường hợp của bạn, bạn chỉ cần năm, tháng và ngày. Năm và tháng là bắt buộc, ngày là tùy chọn. Tôi sẽ sử dụng một cái gì đó như thế:

year smallint not null,
month smallint not null,
day smallint

Thêm vào đó, bạn vẫn có thể sử dụng các chỉ mục rất hiệu quả. (Tiny = trừ, hàng đợi trở nên "phức tạp" hơn một chút (lâu hơn).


1
Nhưng điều này có nghĩa là nếu sự mờ nhạt cũng ngấu nghiến phần tháng, phương pháp này thất bại.
Anurag Kalia

1
@AnuragKalia - vì vậy làm cho trường tháng không thể. Không có lý do gì điều này không thể được cấu hình lại vào một ngày sau đó.
JeffO

Đó chỉ là một ví dụ. Giải pháp phải đủ chung để đáp ứng các vấn đề trong tương lai. Nếu phạm vi bạn chỉ định là 15 tháng 3 năm 2013 đến 22 tháng 3 năm 2013, phương pháp này không hiệu quả. Câu trả lời tối thiểu ở trên là câu trả lời chung nhất.
Anurag Kalia

1
Bạn đã tìm thấy yêu cầu như vậy trong bài OP hay đó chỉ là phantasie của bạn?
Thủy thủ Danubian

Làm cho tháng không thể cho phép bạn chỉ định một ngày nhưng không có tháng. Cũng không có nghĩa gì cả. Khi 1978-??-31nào?
MSalters

-2

Tôi chỉ đơn giản là lưu trữ thời gian chính xác cho các ngày bình thường và làm cho phần thời gian của ngày mờ chung chung như 00:00:00. Sau đó tôi sẽ thực hiện tất cả các ngày mờ vào ngày đầu tiên của tháng.

Khi bạn truy vấn, bạn

  1. kiểm tra phạm vi ngày trong đó thời gian cũng bằng 00:00:00 (mờ)
  2. kiểm tra phạm vi ngày trong đó thời gian KHÔNG bằng 00:00:00 (thực)
  3. kiểm tra phạm vi ngày nhưng bỏ qua phần thời gian (kết hợp)

Có nhiều giải pháp tốt hơn thế này, nhưng cá nhân tôi ghét siêu dữ liệu (dữ liệu về dữ liệu của tôi). Nó chỉ có thói quen ra khỏi tay sau một thời gian.


2
Làm thế nào điều này sẽ đối phó với ngày thực sự có thời gian 00:00:00?
gnat

Mặc dù về mặt lý thuyết có thể thêm một ngày thực sự vào thời điểm đó, nhưng điều đó sẽ không xảy ra. Tôi đã thấy các bảng có hàng triệu hàng và không một bảng nào trong số chúng có giá trị thời gian trong đó thời gian là 00:00:00. Chủ nghĩa thực dụng trumps quy ước.
Thuyền trưởng Kenpachi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.