คุณเก็บ“ วันที่คลุมเครือ” ไว้ในฐานข้อมูลได้อย่างไร


125

นี่เป็นปัญหาที่ฉันพบเจอในสองสามครั้ง ลองนึกภาพคุณมีบันทึกที่คุณต้องการจัดเก็บลงในตารางฐานข้อมูล ตารางนี้มีคอลัมน์ DateTime ที่ชื่อ "date_created" หนึ่งในเร็กคอร์ดนี้ถูกสร้างขึ้นมานานแล้วและคุณไม่แน่ใจจริงๆเกี่ยวกับวันที่แน่นอน แต่คุณรู้ปีและเดือน บันทึกอื่น ๆ ที่คุณรู้เพียงแค่ปี บันทึกอื่น ๆ ที่คุณรู้ว่าวันเดือนและปี

คุณไม่สามารถใช้ฟิลด์ DateTime ได้เนื่องจาก "May 1978" ไม่ใช่วันที่ที่ถูกต้อง หากคุณแบ่งออกเป็นหลายคอลัมน์คุณจะไม่สามารถสืบค้นได้ มีคนอื่นวิ่งเข้าไปในนี้ถ้าเป็นเช่นนั้นคุณจัดการกับมันได้อย่างไร?

เพื่อชี้แจงระบบที่ฉันกำลังสร้างมันเป็นระบบที่ติดตามคลังข้อมูล เนื้อหาบางส่วนได้ถูกผลิตมานานแล้วและสิ่งที่เรารู้คือ "พฤษภาคม 1978" ฉันสามารถจัดเก็บเป็นวันที่ 1 พฤษภาคม 1978 แต่มีเพียงวิธีที่จะแสดงว่าวันนี้มีความถูกต้องเฉพาะกับเดือน ด้วยวิธีนี้หลายปีต่อมาเมื่อฉันเรียกคืนไฟล์เก็บถาวรนั้นฉันไม่สับสนเมื่อวันที่ไม่ตรงกัน

เพื่อจุดประสงค์ของฉันมันเป็นสิ่งสำคัญที่จะต้องแยก "วันที่ไม่รู้จักในเดือนพฤษภาคม 2521" กับ "1 พฤษภาคม 2521" นอกจากนี้ฉันไม่ต้องการเก็บสิ่งที่ไม่รู้จักเป็น 0 เช่น "0 พฤษภาคม 1978" เพราะระบบฐานข้อมูลส่วนใหญ่จะปฏิเสธว่าเป็นค่าวันที่ที่ไม่ถูกต้อง


14
จำเป็นหรือไม่ที่จะต้องแยก "วันที่ไม่รู้จักในเดือนพฤษภาคม 2521" กับ "1 พฤษภาคม 2521"

5
@MichaelT: ใช่มันสำคัญที่จะต้องแยกความแตกต่าง
nbv4


6
@aslum: ระบบฐานข้อมูลส่วนใหญ่จะปฏิเสธว่าเป็นค่าวันที่ไม่ถูกต้อง
nbv4

9
@JimmyHoffa - คุณไม่เคยเจอสถานการณ์วันที่เลือนหรือที่ที่คุณต้องการเปรียบเทียบวันที่? ในกรณีใดกรณีหนึ่งทั่วไปเป็นประวัติทางการแพทย์: คุณจำได้ว่าไส้ติ่งเป็นปีที่แล้วเมื่อวันที่ 1 เมษายน แต่บางครั้งก็เกิดขึ้นที่ต่อมทอนซิลในปี 1975 และมีบางอย่างเกิดขึ้นในช่วงเดือนพฤษภาคมและมิถุนายนของปี ถ้าคุณต้องการทราบว่าเหตุการณ์ทางการแพทย์บางอย่างเกิดขึ้นก่อนหรือหลังการพัฒนาทางการแพทย์อื่น ๆ สิ่งนี้เกิดขึ้นก่อนหรือหลังพวกเขาตรวจดูเลือดสำหรับเอชไอวีหรือไม่?
วันพฤหัสบดีที่

คำตอบ:


148

เก็บวันที่ทั้งหมดในฟิลด์ DATE ปกติในฐานข้อมูลและมีฟิลด์ความแม่นยำเพิ่มเติมว่าฟิลด์ DATE นั้นถูกต้องจริงเพียงใด

date_created DATE,
date_created_accuracy INTEGER, 

date_created_accuracy: 1 = วันที่แน่นอน, 2 = เดือน, 3 = ปี

หากวันที่ของคุณคลุมเครือ (เช่นพฤษภาคม 1980) เก็บไว้ที่จุดเริ่มต้น (เช่นวันที่ 1 พฤษภาคม 1980) หรือถ้าวันที่ของคุณถูกต้องถึงปี (เช่น 1980) จัดเก็บวันที่ 1 มกราคม 2523 ด้วยค่าความถูกต้องที่สอดคล้องกัน

วิธีนี้สามารถสืบค้นได้อย่างเป็นธรรมชาติและยังคงมีความคิดว่าวันที่ที่ถูกต้องคืออะไร ตัวอย่างเช่นนี้ช่วยให้คุณสามารถสอบถามวันที่ระหว่างJan 1st 1980และFeb 28th 1981และได้รับวันเลือนและ1980May 1980


1
คุณยังคงต้องคำนวณวันที่สิ้นสุดที่นี่จากสิ่งที่ฉันเห็นดังนั้นฉันคิดว่าในระหว่างการสืบค้นนั้นค่อนข้างน่าเกลียดเพราะคุณมีเขตข้อมูลจากการคำนวณที่คุณเลือกได้ดีที่สุด
ไวแอตต์บาร์เน็ตต์

8
คำตอบที่ดีฉลาดจริงๆ select * from mytable where date_created between "1980/1/1" and "1981/2/28" and date_created_accuracy <= 2;. อัจฉริยภาพ
Naftuli Kay

58
ฉันขอแนะนำให้คุณพิจารณาความถูกต้องของวันที่ว่าเป็น "วัน" โดยที่วันที่แน่นอนคือ 0 วิธีนี้เราสามารถใช้วันที่ที่ยืดหยุ่นกว่า "บางครั้งในฤดูร้อน" ซึ่งมีความแม่นยำของวันที่ 90 วันจากวันที่ 1 มิถุนายนมากกว่าช่วงวันที่เข้ารหัสที่ยาก นอกจากนี้ยังสามารถจัดการกับความแม่นยำได้หลายปี

1
คุณควรส่งคำตอบนั้น MichaelT
Supr

1
+1: อีกสิ่งที่ดีเกี่ยวกับโซลูชันนี้คือคุณสามารถเพิ่มตรรกะการแสดงผลตามมูลค่าของdate_created_accuracyฟิลด์ คุณสามารถแสดง "พฤษภาคม 1980" หรือเพียงแค่ "1980" ในผลลัพธ์หรือ UI หากความถูกต้องตามที่ระบุในฟิลด์
Kyralessa

27

หากคุณไม่จำเป็นต้องใช้ข้อมูลชนิดนี้เป็นข้อมูลวันเวลาปกติรูปแบบสตริงแบบง่าย ๆ จะทำ

แต่ถ้าคุณต้องการใช้ฟังก์ชั่นทั้งหมดมีวิธีแก้ไขสองวิธีที่ฉันนึกถึงทั้งสองต้องการข้อมูลเพิ่มเติมที่เก็บไว้ในฐานข้อมูล:

  1. สร้างmin dateและmax dateฟิลด์ซึ่งมีค่าแตกต่างกันสำหรับข้อมูล "ไม่สมบูรณ์" แต่จะตรงกับวันที่ที่ถูกต้อง
  2. สร้างประเภทสำหรับวันที่ที่ไม่ถูกต้องแต่ละประเภท (ไม่มี _ 0, date_missing _ 1, month_missing _ 2, year_missing_4, ฯลฯ _ เพื่อให้คุณสามารถรวมได้) เพิ่มtypeเขตข้อมูลลงในระเบียนและเก็บข้อมูลที่หายไป

เขตข้อมูล Min และ max Date เป็นความคิดแรกของฉันเช่นกัน
Michael Itzoe

1
นานมาแล้วที่เราต้องแก้ปัญหาเดียวกันแน่นอน ผู้ใช้สามารถเล่าเรื่องราวเกี่ยวกับเหตุการณ์ที่เกิดขึ้นได้ทุกเวลาในอดีตดังนั้นเราจึงต้องสนับสนุนวันที่คลุมเครือ หลังจากผ่านไปมามากโซลูชันที่เราไปถึงนั้นคล้ายกับข้อเสนอแนะของ superM มากที่สุดที่นี่ซึ่งวันที่จะถูกเก็บไว้เป็นอินสแตนซ์ที่เป็นไปได้ต่ำสุด & สูงสุดที่จะมีวันที่ของเรื่อง เมื่อรายงานวันที่ความถูกต้อง (เช่น "บันทึกนี้มีความถูกต้องกับเดือน / ปี / วัน") สามารถแยกได้จากเดลต้าระหว่างวันที่ min & max ไม่จำเป็นต้องเก็บฟิลด์ที่ 3 เพื่อความแม่นยำ
meetamit

4
+1 สำหรับmin dateและmax dateฟิลด์ ฉันคิดว่านั่นเป็นโซลูชันที่ยืดหยุ่นที่สุดแม่นยำและใช้งานง่ายที่สุด
Supr

1
ตอนแรกฉันเป็นปรปักษ์กับความคิดนี้ แต่เมื่อตระหนักว่ามันเป็นวิธีที่ยืดหยุ่นที่สุดฉันลงคะแนนให้กับสิ่งนี้
Anurag Kalia

มันเป็นเรื่องธรรมดา คุณกำลังอธิบายวันที่ไม่ชัดเจนมาก แต่เป็นกรอบเวลา ..... ซึ่งมีจุดเริ่มต้นและจุดสิ้นสุด
Pieter B

20

นี่เป็นคำจำกัดความของข้อกำหนดมากกว่าปัญหาทางเทคนิคสิ่งที่คุณต้องให้ความสำคัญคือ "เราจะกำหนดวันที่ในอดีตได้อย่างไร" และโซลูชันทางเทคนิคจะไหลออกมา

เวลาที่ฉันต้องเข้าใกล้สิ่งนี้เรามักจะ:

  • กำหนดวิธีทำแผนที่สิ่งต่าง ๆเช่นที่ MichaelT แนะนำให้ตัดสินใจว่าสิ่งใดที่ถูกกำหนดให้เป็นเดือน / วันกลายเป็นเที่ยงคืนของวันที่ 1 ของเดือนดังกล่าว ปกติแล้วมันจะดีพอสำหรับจุดประสงค์ส่วนใหญ่ - ถ้าวันที่แน่นอนนั้นสำคัญคุณอาจจะมีบันทึกในอีก 35 ปีต่อมาใช่ไหม?
  • คิดออกถ้าคุณต้องการติดตามสิ่งนี้ - IE บันทึกด้วยการสร้างวันที่เล็กน้อยต้องมีการตั้งค่าสถานะว่าใช่หรือไม่ หรือเป็นเพียงปัญหาการฝึกอบรมของผู้ใช้เพื่อให้ผู้คนรู้และสามารถปฏิบัติตามได้

บางครั้งเราต้องทำอะไรบางอย่างเช่นทำให้วันที่เลือน - ตัวอย่างเช่นวันหนึ่งอาจต้องตอบคำถามในเดือนพฤษภาคม 2521 สิ่งนี้ทำได้ - เพียงแค่สร้างเขตข้อมูล 2 ของคุณระเบียนเก่าจะได้ 30 วันแพร่กระจายตามความเหมาะสมใหม่จะได้รับ 2 ค่าที่เหมือนกัน


1
+1 - ฉันกำลังทำงานเพื่อกำหนดคำตอบด้วยวิธีการแบบ Double Date คำตอบของคุณมาถึงที่นี่ก่อน

2
+1, มันน่าเกลียดและสร้างข้อมูลพิเศษที่ไร้ประโยชน์มากมายสำหรับรายการใหม่ที่ไม่ต้องการ แต่ในทางกลับกันมันจะเก็บข้อความค้นหาได้ง่ายกว่าที่ควรจะเป็น เราใช้โซลูชันที่คล้ายกันสำหรับปัญหาที่เกี่ยวข้องมาระยะหนึ่งแล้ว
Izkata

3
@Izkata - จุดยุติธรรม แต่คุณจะได้รับความหรูหราเมื่อคุณต้องการทำบางสิ่งที่ควรจะเป็นจุดเดียวในช่วงเวลาหนึ่งเดือน แน่นอนว่าสวยกว่าการคำนวณจุดเริ่มต้นและจุดสิ้นสุดของข้อความค้นหาทันที
ไวแอตต์บาร์เน็ตต์

1
+1 สำหรับความสามารถในการแสดงความละเอียดโดยพลการโดยไม่มีการระเบิดของค่า enum
Dan Neely

18

วิธีที่ง่ายที่สุดในการแสดงว่าวันที่ถูกต้องคือการสร้างเขตข้อมูลความแม่นยำ INT (1) ด้วยค่าเริ่มต้นเป็นโมฆะ

หากวันที่ถูกต้องเก็บวันที่เวลาใน "date_created" และออกความถูกต้องเป็นโมฆะ

หากวันที่ถูกต้องเฉพาะกับร้านค้าเดือนวันที่ - เวลาเป็นวันที่ 1 ของเดือนที่มีค่าความถูกต้อง 1

หากวันที่นั้นถูกต้องสำหรับปีวันที่ร้านค้าวันที่ 1 มกราคมด้วยค่าความแม่นยำ 2

คุณสามารถใช้ตัวเลขต่าง ๆ เพื่อเก็บค่าต่าง ๆ เช่นไตรมาสแรกเป็นต้น


คำค้นหามีขนดกเมื่อคุณทำเช่นนั้น
Blrfl

3
สิ่งนี้มีปัญหากับข้อมูลที่ไม่อยู่ในขอบเขตเดือนที่สะอาดเช่น "Q2 1991" และ "Winter 1978-1979"

1
OP ต้องการวิธีแสดงว่าวันนี้มีความถูกต้องเฉพาะกับเดือน
David Strachan

7
คุณกำลังใช้ความหมายที่ผิดของ NULL ที่นี่ NULL หมายถึง "ไม่ทราบ" ดังนั้นหากวันที่ถูกต้องความแม่นยำจะไม่สามารถเป็น NULL ได้ สามารถเป็น '1'
Konerak

@ Konerak Semantically ใช่ แต่เนื่องจากส่วนใหญ่ของวันที่มีความถูกต้องเฉพาะกรณีพิเศษจะต้องมีการระบุและใช้เป็นโมฆะที่นี่เป็นค่าเริ่มต้น
david strachan

17

ในอดีตที่ผ่านมาฉันเก็บวันที่ที่มีความแม่นยำเป็นวันที่เริ่มต้นและวันที่สิ้นสุด วันพฤษภาคม 21,2012 จะแสดงเป็นเริ่มต้น = 12 am,may21,2012 และสิ้นสุด = 12 am,may22,2012 ปี 2555 จะแสดงเป็น start = 12 am,1,1,1,1212 end = 12 am,1,1,1,1313

ฉันไม่แน่ใจว่าฉันจะแนะนำวิธีการนี้หรือไม่ เมื่อแสดงข้อมูลให้กับผู้ใช้คุณจำเป็นต้องตรวจสอบอย่างถูกต้องว่าช่วงวันที่นั้นครอบคลุมวันหนึ่ง ๆ อย่างแน่นอนเพื่อแสดง "พฤษภาคม 25" แทนที่จะเป็นจุดสิ้นสุดเฉพาะสองจุด (ซึ่งหมายถึงการจัดการกับการประหยัดเวลากลางวันและอื่น ๆ )

อย่างไรก็ตามเมื่อคุณไม่ได้พยายามแปลเป็นมนุษย์การเขียนโปรแกรมที่มีจุดปลายนั้นง่ายกว่าการตั้งศูนย์ + ความแม่นยำ คุณไม่ได้จบลงด้วยกรณีจำนวนมาก นั่นเป็นสิ่งที่ดีงาม


ที่จริงแล้วมันไม่จำเป็นต้องมีความยุ่งยากมากนักในการกำหนดวิธีการนำเสนอช่วงถ้าช่วงถูกเก็บเป็น UTC เสมอ ในฐานะที่เป็นเวลาประทับ UTC ทุกวันสัปดาห์เดือนปี - แม้ฤดูกาลและไตรมาส - จะมีตัวเลขสองค่าคงที่ทั่วโลกที่แตกต่างกันและกำหนดได้อย่างง่ายดายเป็นตัวแทนของการเริ่มต้นและจุดสิ้นสุดของช่วงเวลา ตรรกะจะกลายเป็นเพียงแค่ if-statement เพื่อดูว่าวันที่ทั้งสองอยู่ที่จุดเริ่มต้นและจุดสิ้นสุดของช่วงเวลาบางประเภทหรือไม่ ไม่มีทางคณิตศาสตร์หรือเวลาสิ่งโซนซับซ้อนจำเป็น :)
Supr

@Supr การพิจารณาว่าวินาทีใดที่อยู่บนขอบของช่วงเวลาของมนุษย์นั้นคือปัญหาที่ยาก โดยเฉพาะอย่างยิ่งในระยะยาวด้วยการหมุนของโลกที่ชะลอตัวลงและการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ กับคำนิยามของมนุษย์ในเวลาท้องถิ่น
Craig Gidney

14

ทำไมไม่เก็บสองวัน

Created_After และ Created_Before ความหมายที่แท้จริงถูก "สร้างขึ้นในหรือหลัง" และ "สร้างขึ้นในหรือก่อน"

ดังนั้นหากคุณทราบวันที่แน่นอนดังนั้น Created_After และ Created_Before จะเป็นวันที่เดียวกัน

หากคุณรู้ว่ามันเป็นสัปดาห์แรกในเดือนพฤษภาคม 2000 ดังนั้น Created_After = '2000-05-01' และ Created_Before = '2000-05-07'

หากคุณเพิ่งรู้พฤษภาคม 1999 ค่าจะเป็น '1999-05-01' และ '1999-05-30'

หากเป็น "ฤดูร้อนของ '42" ค่าจะเป็น '1942-06-01' และ '1942-08-31'

สคีมานี้ง่ายต่อการค้นหาด้วย SQL ปกติและค่อนข้างง่ายสำหรับผู้ใช้ที่ไม่ใช่ด้านเทคนิคที่จะติดตาม

เช่นเพื่อค้นหาเอกสารทั้งหมดที่อาจสร้างขึ้นในเดือนพฤษภาคม 2544:

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

ตรงกันข้ามเพื่อค้นหาเอกสารทั้งหมดที่สร้างขึ้นแน่นอนในเดือนพฤษภาคม 2001:

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

1
ฉันคิดว่านี่เป็นทางออกที่หรูหราที่สุด
Pieter B

นี่เป็นคำตอบเดียวกับ superM และ Strilanc +1 แม้ว่าการอธิบายอย่างชัดเจนยิ่งขึ้นและแสดงให้เห็นว่าการสืบค้นทำได้ง่ายเพียงใด
Supr

9

รูปแบบวันที่ISO 8601มาพร้อมกับการกำหนดช่วงเวลาเช่น

2012-01-01P1M (อ่าน: 2012, 1 มกราคม, ระยะเวลา: 1 เดือน) คือสิ่งที่ควรเป็น“ ในเดือนมกราคม 2012”

ฉันจะใช้สิ่งนี้เพื่อจัดเก็บข้อมูล คุณอาจต้องใช้เขตข้อมูลฐานข้อมูลชนิดสตริงเพื่อทำเช่นนั้น มันเป็นหัวข้อที่แตกต่างกันในการค้นหาอย่างสมเหตุสมผล


+1 สำหรับแนวคิด แต่ -1 ไม่ใช้ฟิลด์วันที่ด้วยเหตุผลวิธีค้นหาและ / หรือค้นหา
user151019

ขึ้นอยู่กับฐานข้อมูล อย่างไรก็ตามสิ่งนี้อาจเป็นฐานขยาย แต่คำถามคือ: เอกสารในชุดผลลัพธ์หากคุณค้นหาในกรณีนี้เอกสารทั้งหมดใหม่กว่าวันที่ 12 มกราคมหรือไม่? มันไม่สำคัญเลย ที่นี่คำถามคือวิธีการจัดเก็บวันที่เลือน
Matthias Ronge

3

โดยทั่วไปฉันยังคงเก็บข้อมูลเหล่านั้นไว้เป็นวันที่ในการดำเนินการสืบค้นทั่วไปยังคงเป็นไปได้แม้ว่าจะแม่นยำน้อยกว่าก็ตาม

หากเป็นสิ่งสำคัญที่ต้องทราบความถูกต้องที่ฉันมีในอดีตอาจเก็บ "หน้าต่าง" ความแม่นยำไว้ไม่ว่าจะเป็น +/- ทศนิยมหรือเป็นการค้นหา (วัน, เดือน, ปี, ฯลฯ ) ในกรณีอื่น ๆ แทนหน้าต่างฉันเพิ่งเก็บค่าวันที่ดั้งเดิมเป็นสตริงและแปลงสิ่งที่ฉันสามารถเป็นวันที่และเวลาอาจเป็น 1978-05-01 00:00:00 และ "May 1978" สำหรับตัวอย่างที่คุณระบุ


3

หากคุณแบ่งออกเป็นหลายคอลัมน์คุณจะไม่สามารถสืบค้นได้

พูดว่าใคร นี่คือสิ่งที่คุณทำ:

  1. มี 3 คอลัมน์วันเดือนปีแต่ละประเภท int และคอลัมน์ที่สี่ TheDate of DateTime ชนิด
  2. มีทริกเกอร์ที่ใช้คอลัมน์ 3 วัน, เดือน, ปีเพื่อสร้าง TheDate หากวันที่นั้นไม่มีค่าเป็นโมฆะ แต่ฟิลด์ Day, Month, Year หนึ่งรายการขึ้นไปมีค่า
  3. มีทริกเกอร์ที่เติมฟิลด์วันเดือนปีเมื่อระบุวันที่ แต่ฟิลด์เหล่านี้ไม่ใช่

ดังนั้นถ้าฉันแทรกเช่น: insert into thistable (Day, Month, Year) values (-1, 2, 2012);แล้ว TheDate จะกลายเป็น 2/1/2013 แต่ฉันจะรู้ว่ามันเป็นวันที่แน่นอนใน 2/2012 เนื่องจาก -1 ในฟิลด์วัน

ถ้าฉันinsert into thistable (TheDate) values ('2/5/2012');วันนั้นจะเป็น 5 เดือนจะเป็น 2 และปีจะเป็นปี 2012 และเพราะไม่มีพวกเขาคือ -1 ฉันจะรู้ว่านี่คือวันที่แน่นอน

ฉันไม่สูญเสียความสามารถในการสืบค้นเนื่องจากตัวแทรก / อัปเดตทำให้แน่ใจว่า 3 ฟิลด์ของฉัน (วันเดือนปี) จะสร้างค่า DateTime ใน TheDate ซึ่งสามารถสอบถามได้เสมอ


3

YYYYMMDDอีกตัวเลือกหนึ่งที่จะเก็บวันที่เป็นจำนวนเต็มของแบบฟอร์ม

  • คุณจะรู้ว่าปี 1951: เก็บเป็น 19510000
  • คุณรู้ว่าเดือนและปีคือเดือนมีนาคม 1951: จัดเก็บเป็น 19510300
  • คุณรู้ว่าวันที่เต็มคือ 14 มีนาคม 2494: เก็บเป็น 19510314
  • วันที่ไม่ทราบอย่างสมบูรณ์: เก็บเป็น 0

ประโยชน์ที่ได้รับ

คุณสามารถเก็บวันที่คลุมเครือของคุณไว้ในฟิลด์เดียวแทนสองฟิลด์วันที่หรือวันที่และความแม่นยำตามคำแนะนำอื่น ๆ

ข้อความค้นหายังคงง่าย:

  • บันทึกทั้งหมดสำหรับปี 2494 - SELECT * FROM table WHERE thedate>=19510000 and thedate<19520000
  • บันทึกทั้งหมดสำหรับมีนาคม 1951 - SELECT * FROM table where thedate>=19510300 and thedate<19510400
  • บันทึกทั้งหมดสำหรับ 14 มีนาคม 2494 - SELECT * FROM table where thedate=19510314

หมายเหตุ

  • GUI ของคุณจะต้องมีระบบGetDateString(int fuzzyDate)ที่ใช้งานได้ง่าย
  • การเรียงลำดับเป็นเรื่องง่ายด้วยรูปแบบ int คุณควรรู้ว่าวันที่ไม่รู้จักจะมาก่อน คุณสามารถย้อนกลับได้โดยใช้99สำหรับ 'การเติมเต็ม' แทน00สำหรับเดือนหรือวัน

คุณเป็นตัวแทนวันที่เลือนลางของ "ฤดูหนาวปี 1941-1942" ได้อย่างไร? อาจเป็นธันวาคม 1941 หรือมกราคม 1942

1
คำถามของคุณเกี่ยวข้องกับกรณีแก้ไขปัญหาทั่วไป คำถามเดิมไม่ได้ระบุว่านี่เป็นปัญหา ตามคำถามที่โพสต์บางครั้งอาจทราบวันที่เต็มบางครั้งเฉพาะปีและเดือนและบางครั้งก็เป็นปีเท่านั้น ไม่มีการกล่าวถึงปัญหาของช่วงวันที่ที่ไม่ชัดเจนตามข้อกำหนด ฉันเห็นด้วยว่าคุณต้องการสองวันถ้าคุณต้องการแก้ปัญหานี้ (แม้ว่าการจัดเก็บช่วงเป็นสอง "fuzzy date ints" อาจให้ความยืดหยุ่นมากกว่าการเก็บสองวันที่ "ยาก")
Rick

1

ISO 8601 ยังระบุไวยากรณ์สำหรับ "fuzzy date" 12 กุมภาพันธ์ 2012 เวลา 15.00 น. จะเป็น "2012-02-12T15" และกุมภาพันธ์ 2012 อาจเป็นเพียง "2012-02" สิ่งนี้ขยายอย่างดีโดยใช้การเรียงลำดับพจนานุกรมมาตรฐาน:

$ (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

นี่คือสิ่งที่ฉันทำในสิ่งนี้:

ไปจากวันที่เลือนไปยังวัตถุ datetime (ซึ่งจะพอดีกับฐานข้อมูล)

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

จากนั้นฟังก์ชั่นที่นำวัตถุ datetime และย้ายมันกลับไปเป็นวันที่เลือน

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()

แล้วทดสอบหน่วย ฉันพลาดทุกกรณีหรือไม่?

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'

มีกรณีมุมที่เหตุการณ์ที่เกิดขึ้นอย่างแม่นยำ2001-01-01T00:00:00.333333แต่ระบบจะตีความว่าเป็นเพียง "2001" แต่ดูเหมือนไม่น่าเป็นไปได้มาก


0

ฉันทำงานให้กับ บริษัท สำนักพิมพ์ที่มีหนังสือเก่า ๆ มากมายที่เรามักจะไม่ได้รับสิ่งที่แน่นอน โดยทั่วไปเรามีสองฟิลด์สำหรับรายการวันที่ที่กำหนดวันที่และบูลีนcirca :

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

เราใช้ฟิลด์วันที่เพื่อระบุวันที่ของเหตุการณ์หรือวันที่ "ใกล้พอ" ในกรณีที่เราไม่ทราบวันที่จริง ในกรณีที่เราไม่ทราบวันที่ที่แท้จริงเราทำเครื่องหมายdateCircaฟิลด์เป็นYและให้วันที่ใกล้พอที่ถูกทำเครื่องหมายเป็น "วันที่ 1" เช่น

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

ภาพรวม

มีการนำเสนอที่เป็นไปได้มากมายและทำให้สกีมาฐานข้อมูลสำหรับการจัดเก็บวันที่แบบฟัซซี่ (หรือแม้แต่แค่วันแบบฟัซซี่):

  1. วันที่และรหัสแสดงความแม่นยำหรือความแม่นยำ
  2. วันที่และเวลาที่มีความเป็นไปได้หลายอย่างในการเป็นตัวแทนช่วงเวลา:
    1. แสดงช่วงเวลาทั้งหมดเป็นปริมาณจำนวนเต็ม (หรือตัวเลขอื่น ๆ ) ของหน่วยคงที่บางอย่างเช่นวัน, นาที, นาโนวินาที
    2. แสดงช่วงเวลาเป็นทั้งจำนวนเต็ม (หรือตัวเลขอื่น ๆ ) ปริมาณและรหัสแสดงหน่วย
  3. เริ่มต้นและสิ้นสุดวันที่ - เวลา
  4. เชือก
  5. การกระจายความน่าจะเป็น:
    1. ปริมาณทศนิยมหรือทศนิยมสำหรับพารามิเตอร์ที่ระบุการแจกแจงเฉพาะในตระกูลนั้น ๆ เช่นค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของการแจกแจงแบบปกติ
    2. ฟังก์ชั่นการแจกแจงความน่าจะเป็นเช่นรหัส (ค้นหา) (อาจมีพารามิเตอร์ของค่าเฉพาะ) หรือเป็นการแสดงออกในภาษารูปแบบหรือการแสดงออกที่เพียงพอ

[1], [2] และ [3] เป็นช่วงเวลาที่เหมือนกันทั้งหมด (โดยปริยาย) คือชุดของจุด (เท่ากัน) ที่เป็นไปได้ในเวลา

[4] เป็นคำที่มีความหมายมากที่สุดคือเมื่ออนุญาตให้ใช้ประโยคหรือวลีภาษาที่เป็นไปได้ (หรืออย่างน้อยที่สุดก็ได้) แต่มันก็ยากที่สุดที่จะทำงานด้วย ในระดับที่ จำกัด AI ระดับมนุษย์จะต้องจัดการกับค่านิยมโดยพลการ ในทางปฏิบัติช่วงของค่าที่เป็นไปได้นั้นจะต้องถูก จำกัด อย่างรุนแรงและค่าที่มีโครงสร้าง 'ทางเลือก' อาจเป็นที่ต้องการสำหรับการดำเนินการหลายอย่างเช่นการเรียงลำดับการค้นหา

[5] น่าจะเป็นการนำเสนอขนาดกะทัดรัดที่สุดที่ใช้งานได้จริง

ช่วงเวลาสม่ำเสมอ

ช่วงเวลาที่สม่ำเสมอเป็นวิธีที่กะทัดรัดที่สุดในการแสดงชุดของค่าวันที่ (เป็นไปได้)

สำหรับ [1] ส่วนของค่าวันที่และเวลาจะถูกละเว้นเช่นส่วนที่สอดคล้องกับหน่วยที่ดีกว่าความแม่นยำหรือความแม่นยำที่ระบุ มิฉะนั้นนี่จะเท่ากับ [2] และรหัสความแม่นยำ / ความแม่นยำจะเท่ากับช่วงเวลาที่มีหน่วยเดียวกัน (และปริมาณโดยนัย 1)

[2] และ [3] เทียบเท่ากันอย่างชัดแจ้ง [1] มีความหมายน้อยกว่าอย่างเคร่งครัดเนื่องจากมีช่วงเวลาที่มีประสิทธิภาพที่ไม่สามารถเป็นตัวแทนของ [1] เช่น วันที่และเวลาที่คลุมเครือเทียบเท่ากับช่วงเวลา 12 ชั่วโมงที่ครอบคลุมขอบเขตวันที่

[1] นั้นง่ายสำหรับผู้ใช้ในการป้อนข้อมูลมากกว่าการแสดงอื่น ๆ และโดยทั่วไปควรจะพิมพ์น้อยลง (อย่างน้อยเล็กน้อย) หากสามารถป้อนวันที่และเวลาในรูปแบบข้อความต่างๆเช่น "2013", "2014-3", "2015-5-2", "7/30/2016 11p", "2016-07-31 18:15" ความแม่นยำหรือความแม่นยำอาจถูกอนุมานโดยอัตโนมัติจากอินพุต

ความแม่นยำหรือความแม่นยำของ [1] นั้นง่ายที่สุดในการแปลงเป็นแบบฟอร์มที่จะสื่อความถึงผู้ใช้เช่น '2015-5 ด้วยความแม่นยำของเดือน' ถึง "พฤษภาคม 2015" กับ "13 พฤษภาคม 2558 2p บวกหรือลบ 13.5 วัน" (โปรดทราบว่าส่วนหลังไม่สามารถเป็นตัวแทนของ [1] ได้)

เงื่อนไข

ในทางปฏิบัติค่าสตริงจะต้องถูกแปลงเป็นการรับรองอื่นสำหรับการสอบถามการเรียงลำดับหรือเปรียบเทียบค่าหลายค่า ดังนั้นในขณะที่ภาษาธรรมชาติ (มนุษย์) ที่เป็นลายลักษณ์อักษรใด ๆ มีความหมายชัดเจนกว่า [1], [2], [3] หรือ [5] เรายังไม่มีวิธีจัดการนอกเหนือจากการเป็นตัวแทนข้อความหรือรูปแบบมาตรฐาน ระบุว่านี้น่าจะเป็นตัวแทนที่มีประโยชน์น้อยด้วยตัวเอง

ข้อดีอย่างหนึ่งของการเป็นตัวแทนนี้คือในทางปฏิบัติผู้ใช้ควรเข้าใจคุณค่าของการเปลี่ยนแปลงและไม่ต้องการการแปลงให้เข้าใจได้ง่าย

การแจกแจงความน่าจะเป็น

การแจกแจงความน่าจะเป็นทำให้เป็นตัวแทนช่วงเวลาสม่ำเสมอ [1], [2], [3] และ (เนื้อหา) เทียบเท่ากับการแสดงสตริง (ทั่วไป) [4]

ข้อดีอย่างหนึ่งของการแจกแจงความน่าจะเป็นเหนือสตริงคืออดีตนั้นไม่คลุมเครือ

[5-1] จะเหมาะสมสำหรับค่าที่ (ส่วนใหญ่) เป็นไปตามการกระจายที่มีอยู่เช่นเอาท์พุทค่าวันที่และเวลาจากอุปกรณ์ที่ทราบการวัด (หรือคิดว่า) เพื่อให้สอดคล้องกับการแจกแจงเฉพาะ

[5-2] น่าจะดีที่สุด (ค่อนข้าง) วิธีการปฏิบัติเพื่อดานแทนพล 'เลือน datetime' ค่า แน่นอนว่าความสามารถในการคำนวณของการแจกแจงความน่าจะเป็นที่เฉพาะเจาะจงใช้เรื่องและมีปัญหาที่น่าสนใจ (และอาจเป็นไปไม่ได้) ที่จะแก้ไขเมื่อทำการสืบค้นเรียงลำดับหรือเปรียบเทียบค่าที่แตกต่างกัน วรรณกรรมทางคณิตศาสตร์และสถิติดังนั้นนี่จึงเป็นตัวแทนที่ชัดเจนและไม่คลุมเครือ


-1

ฉันชอบวิธีการแก้ปัญหาของ James Anderson - การ จำกัด ขอบเขตวันที่อย่างถูกต้องเป็นวิธีการรับโครงสร้างคิวรีที่ยืดหยุ่นที่สุด อีกวิธีหนึ่งในการบรรลุเป้าหมายเดียวกันคือการใช้จุดเริ่มต้นจุดจบหรือแม้กระทั่งจุดศูนย์กลางdateบวกinterval(มีอย่างน้อยในPostgreSQL , OracleและSQLAlchemy )


-2

ในกรณีของคุณคุณต้องการเพียงปีเดือนและวัน ต้องระบุปีและเดือน, วันเป็นตัวเลือก ฉันจะใช้สิ่งนั้น:

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

นอกจากนี้คุณยังสามารถใช้ดัชนีได้อย่างมีประสิทธิภาพมาก (เล็ก = ลบลบ, คิวรับ"ซับซ้อน" อีกเล็กน้อย (อีกต่อไป)


1
แต่นี่หมายความว่าหากความเลือนลวกกลืนส่วนเดือนด้วยวิธีนี้ล้มเหลว
Anurag Kalia

1
@AnuragKalia - ทำให้ฟิลด์เดือนเป็นโมฆะ เหตุผลนี้ไม่สามารถกำหนดค่าใหม่ได้ในภายหลัง
JeffO

นั่นเป็นเพียงตัวอย่าง การแก้ปัญหาจะต้องกว้างพอที่จะรองรับปัญหาในอนาคต หากช่วงที่คุณระบุคือ 15 Mar 2013 ถึง 22 Mar 2013 วิธีนี้จะใช้ไม่ได้ คำตอบขั้นต่ำสุดเป็นคำตอบทั่วไป
Anurag Kalia

1
คุณพบข้อกำหนดดังกล่าวในโพสต์ OPs หรือเป็นเพียงแฟนพันธุ์แท้ของคุณ?
Danubian Sailor

การทำให้เดือนเป็นโมฆะช่วยให้คุณสามารถระบุวัน แต่ไม่มีเดือน ไม่สมเหตุสมผลเช่นกัน เมื่อ1978-??-31ไหร่
MSalters

-2

ฉันเพียงแค่จะเก็บเวลาที่แน่นอนสำหรับวันที่ปกติและทำให้ส่วนเวลาของวันที่เลือนทั่วไปเช่น 00:00:00 ฉันจะทำให้วันที่เลือนทั้งหมดของวันที่ 1 ของเดือน

เมื่อคุณสอบถามคุณ

  1. ตรวจสอบช่วงวันที่ที่เวลาเท่ากับ 00:00:00 (เลือน)
  2. ตรวจสอบช่วงวันที่ซึ่งเวลาไม่เท่ากับ 00:00:00 (จริง)
  3. ตรวจสอบช่วงวันที่ แต่ไม่สนใจส่วนเวลา (รวมกัน)

มีวิธีแก้ปัญหาที่ดีกว่านี้ แต่ฉันเกลียดข้อมูลเมตา (ข้อมูลเกี่ยวกับข้อมูลของฉัน) มันเพิ่งมีนิสัยชอบออกจากมือไปซักพักหนึ่ง


2
วิธีนี้จัดการกับวันที่จริงมีเวลา 00:00:00
ริ้น

แม้ว่าจะเป็นไปได้ในทางทฤษฎีที่จะเพิ่มวันที่แท้จริงตามเวลานั้น แต่จะไม่เกิดขึ้น ฉันเห็นตารางที่มีแถวเป็นล้านแถวและไม่ใช่ตารางเดียวที่มีค่าวันที่ซึ่งเวลาคือ 00:00:00 ลัทธิปฏิบัตินิยมสำคัญกว่าการประชุม
กัปตัน Kenpachi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.