ค่า“ null” ของ DateTime


273

ฉันค้นหามาเยอะ แต่หาทางออกไม่เจอ คุณจัดการกับ DateTime อย่างไรที่ควรจะมีค่าที่ไม่ได้กำหนดค่าเริ่มต้น (เทียบเท่ากับ null) ฉันมีคลาสที่อาจมีการตั้งค่าคุณสมบัติ DateTime หรือไม่ ฉันกำลังคิดที่จะเริ่มต้นเจ้าของคุณสมบัติเพื่อ DateTime.MinValue ซึ่งสามารถตรวจสอบได้ง่าย ฉันเดาว่านี่เป็นคำถามที่พบบ่อยมากคุณจะทำอย่างไร

คำตอบ:


420

สำหรับ DateTimes ปกติหากคุณไม่ได้กำหนดค่าเริ่มต้นเลยพวกเขาจะจับคู่DateTime.MinValueเพราะเป็นประเภทค่าแทนที่จะเป็นประเภทอ้างอิง

คุณยังสามารถใช้ DateTime ที่ไม่มีค่าเช่นนี้:

DateTime? MyNullableDate;

หรือแบบฟอร์มอีกต่อไป:

Nullable<DateTime> MyNullableDate;

และในที่สุดก็มีวิธีการอ้างอิงค่าเริ่มต้นของประเภทใด ๆ สิ่งนี้จะคืนค่าnullสำหรับประเภทการอ้างอิง แต่สำหรับตัวอย่าง DateTime ของเรามันจะคืนค่าเหมือนกับDateTime.MinValue:

default(DateTime)

หรือใน C # รุ่นล่าสุด

default

8
มันจะช่วยได้อย่างมากหากคุณให้ตัวอย่างของวิธีการใช้งาน คุณจะกำหนด DateTime ในฐานข้อมูลซึ่งอาจเป็น DBNull ให้กับ DateTime ที่ไม่มีค่าได้อย่างไร
kirk.burleson

9
นอกจากนี้ยังเป็นสิ่งที่ดีที่จะทราบว่าเมื่อคุณทำการเริ่มต้นและด้วยค่า null พวกเขาจะได้รับมอบหมายDateTime.MinValueด้วย
Jeff LaFay

2
@ kirk.burleson ที่ดูเหมือนคำถามแยกต่างหาก
CompuChip

คุณจะต้องMyNullableDate=date; ตั้งค่าMyDate = MyNullableDate.Value;อ่านจากมันและif(MyNullableDate.HasValue)ตรวจสอบว่ามันว่างหรือไม่
satibel

เพื่อชี้แจงคำตอบของ "สุดท้าย" สักหน่อย - ค่าเริ่มต้นของ Nullable <DateTime> (DateTime?) เป็นโมฆะเนื่องจาก Nullable <T> สร้างประเภทอ้างอิง
ryanwebjackson

88

หากคุณใช้. NET 2.0 (หรือใหม่กว่า) คุณสามารถใช้ประเภท nullable:

DateTime? dt = null;

หรือ

Nullable<DateTime> dt = null;

จากนั้นในภายหลัง:

dt = new DateTime();

และคุณสามารถตรวจสอบค่าด้วย:

if (dt.HasValue)
{
  // Do something with dt.Value
}

หรือคุณสามารถใช้มันเช่น:

DateTime dt2 = dt ?? DateTime.MinValue;

คุณสามารถอ่านเพิ่มเติมได้ที่นี่:
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx


1
คุณสามารถใช้ประเภท nullable แม้ใน. NET รุ่นก่อนหน้าไม่จำเป็นต้อง 3.0
stephenbayer

1
มันมาใน. NET 2.0 ใช่ไหม? การ ไวยากรณ์ถูกเพิ่มใน VB.NET ใน 3.5 แต่ได้รับใน C # ตั้งแต่ 2.0 ฉันเชื่อ
David Mohundro

1
ประเภทที่ใช้งานได้มีอยู่ใน. Net 2.0 C # มีการจดชวเลขหรือไม่? สัญกรณ์จาก 2.0 มีเพียง VB.Net เท่านั้นที่ไม่มีชวเลข ใน 2.0 แต่คุณสามารถใช้ Nullable (ของ DateTime)
Mendelt

สำหรับตัวอย่างสุดท้ายฉันจะบอกว่า DateTime dt2 = dt ?? DateTime.MinValue;
Joel Coehoorn

ฉันจะใช้dt.GetValueOrDefault()- เป็นตัวเลือกที่มีประสิทธิภาพที่สุด
CompuChip

37

วันเวลา? MyDateTime {ได้รับ; ชุด;}

MyDateTime = (dr["f1"] == DBNull.Value) ? (DateTime?)null : ((DateTime)dr["f1"]);

1
สิ่งนี้ช่วยให้ฉันค้นพบว่าการผ่านnullไม่ได้ผล (DateTime?)nullจะต้องมี
Inphinite Phractals

33

วิธีต่อไปนี้ใช้ได้เช่นกัน

myClass.PublishDate = toPublish ? DateTime.Now : (DateTime?)null;

โปรดทราบว่าสถานที่ให้บริการ PublishDate ควรเป็น DateTime หรือไม่



8

เป็นค่าที่ชี้ให้เห็นว่าในขณะที่DateTimeตัวแปรไม่สามารถเป็นได้nullก็ยังสามารถเปรียบเทียบได้nullโดยไม่มีข้อผิดพลาดของคอมไพเลอร์:

DateTime date;
...
if(date == null) // <-- will never be 'true'
  ...

6

คุณสามารถใช้คลาสที่ไม่มีค่าได้

DateTime? date = new DateTime?();

มันอาจจะเป็นที่น่าสังเกตนี้จะทำให้คุณมีพฤติกรรมที่แตกต่างกว่า instantiating DateTimeไม่ใช่ ตามที่ระบุไว้ก่อนหน้านี้new DateTime()จะให้ผลอย่างมีประสิทธิภาพDateTime.Minในขณะที่new DateTime?()จะส่งผลให้เป็นโมฆะ
Vitoc

6

คุณสามารถใช้ DateTime ที่ไม่มีค่าสำหรับสิ่งนี้

Nullable<DateTime> myDateTime;

หรือสิ่งเดียวกันที่เขียนเช่นนี้

DateTime? myDateTime;

6

คุณสามารถตั้ง DateTime ให้เป็น Nullable ตามค่าเริ่มต้น DateTime จะไม่สามารถยกเลิกได้ คุณสามารถทำให้เป็นโมฆะในสองวิธี ใช้เครื่องหมายคำถามหลังจากพิมพ์ DateTime หรือไม่ myTime หรือใช้ลักษณะทั่วไป Nullable

DateTime? nullDate = null;

หรือ

DateTime? nullDate;

5

ฉันตั้งเวลาไว้DateTime.MinValueเสมอ วิธีนี้ฉันไม่ได้รับ NullErrorException ใด ๆ และฉันสามารถเปรียบเทียบกับวันที่ฉันรู้ว่าไม่ได้ตั้งค่าไว้


8
นั่นหมายความว่าคุณไม่สามารถบอกความแตกต่างระหว่าง "ฉันต้องการ DateTime ที่นี่จริง ๆ " และ "เป็นตัวเลือก" - Nullable <DateTime> เป็นทางออกที่ดีกว่ามาก IMO
Jon Skeet

? ฉันไม่ได้รับความคิดเห็นของคุณ ใช่ฉันรู้ว่าเมื่อวันที่และเวลาเพื่อให้ห่างไกลจากความเป็นจริงสิ่งที่เป็นเหมือนว่ามันเป็นโมฆะ ...
แพทริคจาร์แดงส์

2
มันสะดวก แต่ฉันดู DateTime.MinValue เป็นค่าไม่ใช่เงื่อนไขกรณีพิเศษ มันสามารถนำไปสู่ปัญหาลงบรรทัด ฉันจะไปกับ Nullable <DateTime>
โปลสัน

3
ฉันคิดว่าคุณพลาดบางอย่างเกี่ยวกับคำตอบของฉัน Spoulson เขียนบางสิ่งบางอย่างและฉันก็ตอบ เกี่ยวกับสมาชิกสาธารณะมันไม่เหมือนกันและคุณก็รู้ มันเหมือนกับ String.Empty หรือ null คุณสามารถทำได้ทั้งสองไม่ใช่เพราะ String.Empty ดีกว่าที่ null ไม่ถูกต้อง สิ่งที่เคย
Patrick Desjardins

1
ฉันกับ Daok ในเรื่องนี้ อาจไม่ใช่วิธี "ตามหนังสือ" แต่จะดีกว่าการใช้ NullReferenceException หรือจัดการกับ Nullable ประเภทที่ยุ่งยาก นอกจากนี้มีแอปพลิเคชันจำนวนมากที่จำเป็นต้องอ้างอิงถึงวันที่ 1 มกราคม 1 โฆษณาจริงหรือไม่
Jacobs Data Solutions

4

เพิ่งได้รับการเตือน - เมื่อใช้ Nullable วัตถุนั้นจะไม่เป็นวัตถุ datetime ที่ 'บริสุทธิ์' อีกต่อไปดังนั้นคุณจึงไม่สามารถเข้าถึงสมาชิก DateTime ได้โดยตรง ฉันจะพยายามอธิบาย

โดยการใช้ Nullable <> โดยทั่วไปคุณจะใส่ DateTime ไว้ในคอนเทนเนอร์ (ขอบคุณข้อมูลทั่วไป) ซึ่งเป็นโมฆะ - ชัดเจนถึงวัตถุประสงค์ คอนเทนเนอร์นี้มีคุณสมบัติของตัวเองซึ่งคุณสามารถเรียกใช้ซึ่งจะให้การเข้าถึงวัตถุ DateTime ดังกล่าว หลังจากใช้คุณสมบัติที่ถูกต้อง - ในกรณีนี้ Nullable.Value - คุณสามารถเข้าถึงสมาชิก DateTime มาตรฐานคุณสมบัติ ฯลฯ

ดังนั้น - ตอนนี้ปัญหามาถึงใจเป็นวิธีที่ดีที่สุดในการเข้าถึงวัตถุ DateTime มีอยู่สองสามวิธีหมายเลข 1 คือไกลที่สุดและ 2 คือ "เพื่อนทำไม"

  1. การใช้คุณสมบัติ Nullable.Value

    DateTime date = myNullableObject.Value.ToUniversalTime(); //Works

    DateTime date = myNullableObject.ToUniversalTime(); //Not a datetime object, fails

  2. การแปลงออบเจกต์ nullable เป็น datetime โดยใช้ Convert.ToDateTime (),

    DateTime date = Convert.ToDateTime(myNullableObject).ToUniversalTime(); //works but why...

แม้ว่าคำตอบจะได้รับการบันทึกไว้อย่างดี ณ จุดนี้ แต่ฉันเชื่อว่าการใช้งาน Nullable นั้นน่าจะคุ้มค่ากับการโพสต์ ขออภัยถ้าคุณไม่เห็นด้วย

แก้ไข: ลบตัวเลือกที่สามเนื่องจากเป็นบิตที่เจาะจงเกินไปและขึ้นอยู่กับกรณีและปัญหา


2

แม้ว่าทุกคนได้ให้คำตอบกับคุณแล้ว แต่ฉันจะพูดถึงวิธีที่ทำให้การส่งผ่านข้อมูลไปยังฟังก์ชั่นนั้นง่ายขึ้น

[ข้อผิดพลาด: ไม่สามารถแปลง system.datetime ได้หรือไม่ ไปที่ system.datetime]

DateTime? dt = null;
DateTime dte = Convert.ToDateTime(dt);

ตอนนี้คุณสามารถส่ง dte ภายในฟังก์ชันโดยไม่มีปัญหาใด ๆ


1

หากคุณเป็นบางครั้งคาดว่าเป็นโมฆะคุณสามารถใช้สิ่งนี้:

var orderResults = Repository.GetOrders(id, (DateTime?)model.DateFrom, (DateTime?)model.DateTo)

ในที่เก็บของคุณใช้ datetime ที่สามารถใช้ค่า null

public Orders[] GetOrders(string id, DateTime? dateFrom, DateTime? dateTo){...}

1

ฉันมีปัญหาเดียวกับที่ฉันต้องให้ Null เป็นพารามิเตอร์สำหรับ DateTime ในขณะที่ทำการทดสอบหน่วยสำหรับ Throws ArgumentNullException.It ทำงานในเคสของฉันโดยใช้ตัวเลือกต่อไปนี้:

Assert.Throws<ArgumentNullException>(()=>sut.StartingDate = DateTime.Parse(null));

0

เนื่องจากลักษณะของชนิดข้อมูลวันที่ / เวลาไม่สามารถมีnullค่าได้เช่นจำเป็นต้องมีค่าจึงไม่สามารถว่างเปล่าหรือไม่มีอะไรเลย หากคุณทำเครื่องหมายตัวแปรวันที่ / เวลาเป็นnullableเพียงคุณเท่านั้นที่สามารถกำหนดค่า Null ให้กับมันได้ ดังนั้นสิ่งที่คุณต้องการทำคือหนึ่งในสองสิ่ง (อาจมีมากกว่านั้น แต่ฉันนึกได้แค่สองอย่างเท่านั้น):

  • กำหนดค่าวันที่ / เวลาขั้นต่ำให้กับตัวแปรของคุณหากคุณไม่มีค่า คุณสามารถกำหนดค่าวันที่ / เวลาสูงสุดได้เช่นกัน เพียงตรวจสอบให้แน่ใจว่าคุณมีความสอดคล้องทั่วทั้งไซต์เมื่อตรวจสอบค่าวันที่ / เวลา ตัดสินใจเกี่ยวกับการใช้minหรือmaxติดกับมัน

  • ทำเครื่องหมายตัวแปรวันที่ / nullableเวลาของคุณเป็น วิธีนี้คุณสามารถตั้งค่าตัวแปรวันที่ / เวลาของnullคุณเป็นหากคุณไม่มีตัวแปร

ให้ฉันสาธิตจุดแรกของฉันโดยใช้ตัวอย่าง DateTimeชนิดตัวแปรที่ไม่สามารถกำหนดให้เป็นโมฆะจะต้องมีค่าในกรณีนี้ฉันกำลังจะไปตั้งไปยังDateTime's ค่าต่ำสุดถ้าไม่มีค่า

สถานการณ์ของฉันคือฉันมีBlogPostชั้นเรียน มันมีฟิลด์ / คุณสมบัติต่าง ๆ มากมาย แต่ฉันเลือกที่จะใช้สองอย่างสำหรับตัวอย่างนี้เท่านั้น DatePublishedคือเมื่อโพสต์เผยแพร่ในเว็บไซต์และต้องมีค่าวันที่ / เวลา DateModifiedคือเมื่อมีการแก้ไขโพสต์ดังนั้นจึงไม่จำเป็นต้องมีค่า แต่สามารถมีค่าได้

public class BlogPost : Entity
{
     public DateTime DateModified { get; set; }

     public DateTime DatePublished { get; set; }
}

การใช้ADO.NETเพื่อรับข้อมูลจากฐานข้อมูล (กำหนดDateTime.MinValueว่าไม่มีค่า):

BlogPost blogPost = new BlogPost();
blogPost.DateModified = sqlDataReader.IsDBNull(0) ? DateTime.MinValue : sqlDataReader.GetFieldValue<DateTime>(0);
blogPost.DatePublished = sqlDataReader.GetFieldValue<DateTime>(1);

คุณสามารถบรรลุจุดที่สองของฉันโดยการทำเครื่องหมายฟิลด์เป็นDateModified nullableตอนนี้คุณสามารถตั้งค่าเป็นnullหากไม่มีค่า:

public DateTime? DateModified { get; set; }

การใช้ADO.NETเพื่อรับข้อมูลจากฐานข้อมูลจะมีลักษณะแตกต่างจากวิธีที่ทำข้างต้นเล็กน้อย (การกำหนดnullแทนDateTime.MinValue):

BlogPost blogPost = new BlogPost();
blogPost.DateModified = sqlDataReader.IsDBNull(0) ? (DateTime?)null : sqlDataReader.GetFieldValue<DateTime>(0);
blogPost.DatePublished = sqlDataReader.GetFieldValue<DateTime>(1);

ฉันหวังว่านี่จะช่วยขจัดความสับสน เนื่องจากคำตอบของฉันประมาณ 8 ปีต่อมาคุณอาจเป็นโปรแกรมเมอร์ C # ผู้เชี่ยวชาญในตอนนี้ :)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.