Giá trị ngày


273

Tôi đã tìm kiếm rất nhiều nhưng không thể tìm ra giải pháp. Làm thế nào để bạn đối phó với DateTime có thể chứa giá trị chưa được khởi tạo (tương đương với null)? Tôi có một lớp có thể có giá trị thuộc tính DateTime được đặt hay không. Tôi đã nghĩ đến việc khởi tạo chủ sở hữu tài sản thành DateTime.MinValue, sau đó có thể dễ dàng kiểm tra. Tôi đoán đây là một câu hỏi khá phổ biến, làm thế nào để bạn làm điều đó?

Câu trả lời:


420

Đối với DateTimes bình thường, nếu bạn hoàn toàn không khởi tạo chúng thì chúng sẽ khớp DateTime.MinValue , bởi vì đó là loại giá trị chứ không phải loại tham chiếu.

Bạn cũng có thể sử dụng DateTime nullable, như thế này:

DateTime? MyNullableDate;

Hoặc dạng dài hơn:

Nullable<DateTime> MyNullableDate;

Và cuối cùng, có một cách được xây dựng để tham chiếu mặc định của bất kỳ loại nào. Điều này trả về nullcho các loại tham chiếu, nhưng đối với ví dụ DateTime của chúng tôi, nó sẽ trả về giống như DateTime.MinValue:

default(DateTime)

hoặc, trong các phiên bản gần đây hơn của C #,

default

8
Nó sẽ giúp ích rất nhiều nếu bạn cung cấp một ví dụ về cách sử dụng nó. Làm thế nào để bạn chỉ định DateTime trong cơ sở dữ liệu, có thể là DBNull, cho DateTime nullable?
kirk.burleson

9
Nó cũng tốt để lưu ý rằng khi bạn DO khởi tạo chúng và với null, họ được giao nhiệm vụ DateTime.MinValuecũng
Jeff LaFay

2
@ kirk.burleson trông giống như một câu hỏi riêng biệt.
CompuChip

bạn sẽ cần MyNullableDate=date; phải đặt nó, MyDate = MyNullableDate.Value;để đọc từ nó và if(MyNullableDate.HasValue)kiểm tra xem nó có phải không
satibel

Để làm rõ câu trả lời "cuối cùng" một chút - mặc định của Nullable <DateTime> (DateTime?) Là null, vì Nullable <T> tạo ra một loại tham chiếu.
ryanwebjackson

88

Nếu bạn đang sử dụng .NET 2.0 (hoặc phiên bản mới hơn), bạn có thể sử dụng loại nullable:

DateTime? dt = null;

hoặc là

Nullable<DateTime> dt = null;

sau đó

dt = new DateTime();

Và bạn có thể kiểm tra giá trị với:

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

Hoặc bạn có thể sử dụng nó như:

DateTime dt2 = dt ?? DateTime.MinValue;

Bạn có thể đọc thêm tại đây:
http://msdn.microsoft.com/en-us/l Library / b3h38hb0.aspx


1
Bạn có thể sử dụng các loại nullable ngay cả trong các phiên bản .NET trước đó, không cần 3.0.
stephenbayer

1
Nó đến trong .NET 2.0 phải không? Các ? cú pháp đã được thêm vào VB.NET trong 3.5, nhưng tôi tin rằng nó đã có trong C # kể từ 2.0.
David Mohundro

1
Các loại không thể có sẵn trong .Net 2.0. C # đã có tốc ký? ký hiệu từ 2.0. Chỉ VB.Net không có tốc ký? trong 2.0 nhưng bạn có thể sử dụng Nullable (Of DateTime)
Mendelt

Đối với đoạn mã cuối cùng, tôi sẽ nói DateTime dt2 = dt ?? DateTime.MinValue;
Joel Coehoorn

Tôi sẽ sử dụng dt.GetValueOrDefault()- đó là lựa chọn hiệu quả nhất.
CompuChip

37

Ngày giờ? MyDateTime {get; set;}

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

1
Điều này giúp tôi khám phá việc vượt qua chỉ là nullkhông làm việc. Nó cần phải được (DateTime?)null.
Inphinite Phractals 27/2/19

33

Theo cách làm việc là tốt

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

Xin lưu ý rằng thuộc tính PublishDate phải là DateTime?



8

Cần chỉ ra rằng, trong khi một DateTimebiến không thể null, nó vẫn có thể được so sánh nullmà không có lỗi trình biên dịch:

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

6

Bạn có thể sử dụng một lớp nullable.

DateTime? date = new DateTime?();

Có lẽ đáng chú ý điều này sẽ cung cấp cho bạn hành vi khác với việc khởi tạo một thứ không thể rỗng DateTime. Như đã đề cập trước đây, new DateTime()sẽ cung cấp cho bạn một cách hiệu quả DateTime.Mintrong khi new DateTime?()sẽ dẫn đến null.
Vitoc

6

Bạn có thể sử dụng DateTime nullable cho việc này.

Nullable<DateTime> myDateTime;

hoặc điều tương tự được viết như thế này:

DateTime? myDateTime;

6

Bạn có thể đặt DateTime thành Nullable. Theo mặc định DateTime không thể rỗng. Bạn có thể làm cho nó vô giá trị theo một vài cách. Sử dụng dấu chấm hỏi sau loại DateTime? myTime hoặc sử dụng kiểu chung Nullable.

DateTime? nullDate = null;

hoặc là

DateTime? nullDate;

5

Tôi luôn đặt thời gian để DateTime.MinValue. Bằng cách này, tôi không nhận được bất kỳ NullErrorException nào và tôi có thể so sánh nó với một ngày mà tôi biết không được đặt.


8
Điều đó có nghĩa là bạn không thể nói sự khác biệt giữa "Tôi thực sự cần một DateTime ở đây" và "Đó là tùy chọn" - Nullable <DateTime> là một giải pháp tốt hơn nhiều, IMO.
Jon Skeet

? Tôi thực sự không nhận được bình luận của bạn. Vâng, tôi biết khi DateTime cách xa thực tế sẽ như thế nào nếu nó không có giá trị ...
Patrick Desjardins

2
Thật tiện lợi, nhưng tôi xem DateTime.MinValue là một giá trị, không phải là một điều kiện trường hợp đặc biệt. Nó chỉ có thể dẫn đến các vấn đề xuống dòng. Tôi sẽ đi với Nullable <DateTime>.
spoulson

3
Tôi nghĩ rằng bạn bỏ lỡ điều gì đó về câu trả lời của tôi, Spoulson đã viết một cái gì đó và tôi đã trả lời. Về các thành viên công cộng, nó không giống nhau và bạn biết điều đó. nó giống như String.Empty hoặc null. Bạn có thể làm cả hai, không phải vì String.Empty tốt hơn là null sai. Bất cứ điều gì.
Patrick Desjardins

1
Tôi với Daok về điều này. Nó có thể không phải là cách tiếp cận "theo cuốn sách" nhưng tốt hơn là lấy NullReferenceException hoặc xử lý kiểu Nullable rườm rà. Bên cạnh đó, có bao nhiêu ứng dụng ngoài kia thực sự cần tham chiếu ngày 1 tháng 1 năm 1 sau Công nguyên?
Giải pháp dữ liệu Jacobs

4

Chỉ cần được cảnh báo - Khi sử dụng Nullable, rõ ràng nó không còn là đối tượng thời gian 'thuần túy' nữa, vì vậy bạn không thể truy cập trực tiếp vào các thành viên DateTime. Tôi sẽ thử và giải thích.

Bằng cách sử dụng Nullable <> về cơ bản bạn đang gói DateTime trong một thùng chứa (cảm ơn bạn chung chung) là không thể - rõ ràng là mục đích của nó. Container này có các thuộc tính riêng mà bạn có thể gọi sẽ cung cấp quyền truy cập vào đối tượng DateTime đã nói ở trên; sau khi sử dụng đúng thuộc tính - trong trường hợp này là Nullable.Value - sau đó bạn có quyền truy cập vào các thành viên DateTime tiêu chuẩn, thuộc tính, v.v.

Vì vậy - bây giờ vấn đề nảy sinh là cách tốt nhất để truy cập đối tượng DateTime. Có một vài cách, số 1 là bởi FAR là tốt nhất và 2 là "dude why".

  1. Sử dụng thuộc tính Nullable.Value,

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

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

  2. Chuyển đổi đối tượng nullable thành datetime bằng Convert.ToDateTime (),

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

Mặc dù câu trả lời được ghi lại rõ ràng vào thời điểm này, tôi tin rằng việc sử dụng Nullable có lẽ đáng để đăng. Xin lỗi nếu bạn không đồng ý.

chỉnh sửa: Đã xóa tùy chọn thứ ba vì nó hơi quá cụ thể và phụ thuộc vào từng trường hợp.


2

Mặc dù mọi người đã cho bạn câu trả lời, nhưng tôi sẽ đề cập đến một cách giúp bạn dễ dàng chuyển datetime vào một hàm

[LRI: không thể chuyển đổi system.datetime? đến system.datetime]

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

Bây giờ bạn có thể vượt qua dte bên trong chức năng mà không có bất kỳ vấn đề.


1

Nếu bạn, đôi khi, mong đợi null, bạn có thể sử dụng một cái gì đó như thế này:

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

Trong kho lưu trữ của bạn sử dụng datetime có thể null.

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

1

Tôi gặp vấn đề tương tự khi tôi phải cung cấp cho Null làm tham số cho DateTime trong khi thực hiện kiểm tra Đơn vị cho Th Ném ArgumentNullException. Nó hoạt động trong trường hợp của tôi bằng cách sử dụng tùy chọn sau:

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

0

Do tính chất của kiểu dữ liệu ngày / giờ, nó không thể chứa một nullgiá trị, tức là nó cần chứa một giá trị, nó không thể để trống hoặc không chứa gì. Nếu bạn đánh dấu một biến ngày / giờ là nullablechỉ thì bạn có thể gán giá trị null cho nó. Vì vậy, những gì bạn đang muốn làm là một trong hai điều (có thể có nhiều hơn nhưng tôi chỉ có thể nghĩ về hai):

  • Chỉ định giá trị ngày / thời gian tối thiểu cho biến của bạn nếu bạn không có giá trị cho biến đó. Bạn cũng có thể chỉ định giá trị ngày / thời gian tối đa - bất kỳ cách nào phù hợp với bạn. Chỉ cần đảm bảo rằng bạn có toàn bộ trang web nhất quán khi kiểm tra giá trị ngày / giờ của bạn. Quyết định sử dụng minhoặc maxvà gắn bó với nó.

  • Đánh dấu biến ngày / giờ của bạn là nullable. Bằng cách này, bạn có thể đặt biến ngày / giờ của mình thành nullnếu bạn không có biến đó.

Hãy để tôi chứng minh điểm đầu tiên của tôi bằng cách sử dụng một ví dụ. Các DateTimekiểu dữ liệu không thể được thiết lập để null, nó cần một giá trị, trong trường hợp này tôi sẽ đặt nó vàoDateTime 's giá trị nhỏ nhất nếu không có giá trị.

Kịch bản của tôi là tôi có một BlogPostlớp học. Nó có nhiều trường / thuộc tính khác nhau nhưng tôi chọn chỉ sử dụng hai cho ví dụ này. DatePublishedlà khi bài đăng được xuất bản lên trang web và phải chứa giá trị ngày / giờ. DateModifiedlà khi một bài viết được sửa đổi, vì vậy nó không phải chứa một giá trị, nhưng có thể chứa một giá trị.

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

     public DateTime DatePublished { get; set; }
}

Sử dụng ADO.NETđể lấy dữ liệu từ cơ sở dữ liệu (gán DateTime.MinValuelà không có giá trị):

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

Bạn có thể thực hiện điểm thứ hai của tôi bằng cách đánh dấu DateModifiedtrường là nullable. Bây giờ bạn có thể đặt nó thành nullnếu không có giá trị cho nó:

public DateTime? DateModified { get; set; }

Sử dụng ADO.NETđể lấy dữ liệu từ cơ sở dữ liệu, nó sẽ trông hơi khác so với cách thực hiện ở trên (gán nullthay vì DateTime.MinValue):

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

Tôi hy vọng điều này sẽ giúp làm sáng tỏ bất kỳ sự nhầm lẫn. Cho rằng phản hồi của tôi là khoảng 8 năm sau, bây giờ bạn có thể là một lập trình viên C # chuyên nghiệp :)

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.