DateTime «нулевое» значение

273

Я много искал, но не смог найти решение. Как вы справляетесь с DateTime, который должен содержать неинициализированное значение (эквивалентное нулю)? У меня есть класс, который может иметь значение свойства 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
Это также хорошо , чтобы отметить , что , когда вы делаете их инициализации и с нулем, они назначены , DateTime.MinValueа также
Джефф Lafay
2
@ kirk.burleson, который выглядит как отдельный вопрос.
CompuChip
вам нужно MyNullableDate=date; будет установить его, MyDate = MyNullableDate.Value;прочитать из него и if(MyNullableDate.HasValue)проверить, является ли он нулевым
satibel
Чтобы прояснить вопрос «наконец» ответа - по умолчанию Nullable <DateTime> (DateTime?) Равен нулю, потому что Nullable <T> создает ссылочный тип.
ryanwebjackson
88

Если вы используете .NET 2.0 (или более позднюю версию), вы можете использовать обнуляемый тип:

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
Вы можете использовать обнуляемые типы даже в более ранних версиях .NET, нет необходимости в 3.0.
Стивенбайер
1
Это пришло в .NET 2.0, верно? ? Синтаксис был добавлен в VB.NET в 3.5, но он был в C # с 2.0, я считаю.
Дэвид Мохундро
1
Обнуляемые типы доступны в .Net 2.0. У C # была стенография? запись от 2.0. Только у VB.Net не было стенографии? в 2.0, но вы могли бы использовать Nullable (Of DateTime)
Мендель
Для последнего фрагмента я бы сказал DateTime dt2 = dt ?? DateTime.MinValue;
Джоэл Коухорн
Я бы использовал dt.GetValueOrDefault()- это самый эффективный вариант.
CompuChip
37

DateTime? 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'
  ...
uncoder
источник
6

Вы можете использовать обнуляемый класс.

DateTime? date = new DateTime?();
Аарон Смит
источник
Вероятно, стоит отметить, что это даст вам другое поведение, чем создание необнуляемого DateTime. Как уже упоминалось ранее, new DateTime()эффективно даст вам, DateTime.Minтогда как new DateTime?()приведет к нулю.
Виток
6

Вы можете использовать обнуляемый DateTime для этого.

Nullable<DateTime> myDateTime;

или то же самое написано так:

DateTime? myDateTime;
Патрик Свенссон
источник
6

Вы можете установить DateTime в Nullable. По умолчанию DateTime не обнуляется. Вы можете сделать его обнуляемым несколькими способами. Использование знака вопроса после типа DateTime? myTime или используя общий стиль Nullable.

DateTime? nullDate = null;

или

DateTime? nullDate;
user29958
источник
5

Я всегда установить время DateTime.MinValue. Таким образом, я не получаю никакого исключения NullErrorException и могу сравнить его с датой, которую я знаю, не установлено.

Патрик Дежарден
источник
8
Это означает, что вы не можете определить разницу между «мне действительно нужен DateTime здесь» и «это необязательно» - Nullable <DateTime> - гораздо лучшее решение, IMO.
Джон Скит
? Я действительно не получаю ваш комментарий. Да, я знаю, когда DateTime настолько далек от реальности, как если бы она была нулевой ...
Патрик Дежарден
2
Это удобно, но я рассматриваю DateTime.MinValue как значение, а не как особый случай. Это может привести только к проблемам в будущем. Я бы пошел с Nullable <DateTime>.
Спулсон
3
Я думаю, что вы что-то упустили из-за моего ответа, Спулсон что-то написал, а я отвечал. Насчет публичных участников, ну, это не то же самое, и вы это знаете. это как String.Empty или null. Вы можете сделать и то, и другое, не потому, что String.Empty лучше, чем null, и это неправильно. Без разницы.
Патрик Дежарден
1
Я с Даоком на этом. Это может быть не подход «по книге», но это лучше, чем получение NullReferenceException или работа с громоздким типом Nullable. Кроме того, сколько приложений на самом деле нужно указать дату 1 января 1 года нашей эры?
Jacobs Data Solutions
4

Только предупреждаем - при использовании Nullable он, очевидно, больше не является «чистым» объектом даты и времени, поэтому вы не можете напрямую обращаться к членам DateTime. Я постараюсь объяснить.

Используя Nullable <>, вы в основном оборачиваете DateTime в контейнер (спасибо generics), который является nullable - очевидно, его цель. Этот контейнер имеет свои собственные свойства, которые вы можете вызывать, чтобы обеспечить доступ к вышеупомянутому объекту DateTime; после использования правильного свойства - в данном случае Nullable.Value - вы получаете доступ к стандартным элементам DateTime, свойствам и т. д.

Итак - теперь возникает вопрос о том, как лучше всего получить доступ к объекту DateTime. Есть несколько способов, номер 1 от FAR лучший и 2 "чувак почему".

  1. Используя свойство Nullable.Value,

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

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

  2. Преобразование обнуляемого объекта в datetime с использованием Convert.ToDateTime (),

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

Хотя на данный момент ответ хорошо документирован, я думаю, что использование Nullable, вероятно, стоило опубликовать. Извините, если вы не согласны.

edit: удален третий вариант, так как он был слишком специфичным и зависящим от регистра.

Гейб
источник
2

Хотя все уже дали вам ответ, я упомяну способ, который облегчает передачу datetime в функцию

[ОШИБКА: невозможно преобразовать system.datetime? to system.datetime]

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

Теперь вы можете передать dte внутри функции без каких-либо проблем.

Нет праздников
источник
1

Если вы иногда ожидаете null, вы можете использовать что-то вроде этого:

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

В вашем репозитории используйте null-способную дату и время.

public Orders[] GetOrders(string id, DateTime? dateFrom, DateTime? dateTo){...}
DarkoM
источник
1

У меня была та же проблема, что и для задания значения DateTime в качестве параметра для DateTime, когда я выполнял модульный тест для Throws ArgumentNullException. В моем случае это работало с использованием следующей опции:

Assert.Throws<ArgumentNullException>(()=>sut.StartingDate = DateTime.Parse(null));
Кирилл Добрев
источник
0

Учитывая природу типа данных даты / времени, он не может содержать nullзначение, то есть он должен содержать значение, он не может быть пустым или ничего не содержать. Если вы помечаете переменную даты / времени как nullableтолько тогда, вы можете присвоить ей нулевое значение. Итак, что вы хотите сделать, это одна из двух вещей (может быть больше, но я могу думать только о двух):

  • Назначьте минимальное значение даты / времени для вашей переменной, если у вас нет значения для нее. Вы также можете назначить максимальное значение даты / времени - в зависимости от того, что вам подходит. Просто убедитесь, что вы едины для всего сайта при проверке значений даты / времени. Определитесь с использованием minили maxи придерживайтесь его.

  • Пометьте свою переменную даты / времени как nullable. Таким образом, вы можете установить переменную даты / времени, nullесли у вас нет этой переменной.

Позвольте мне продемонстрировать мой первый пункт на примере. Тип DateTimeпеременной не может быть установлен в нуль, ему нужно значение, в этом случае я собираюсь установить его на DateTimeминимальное значение, если значение отсутствует.

Мой сценарий таков, что у меня есть 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 # :)

Брендан Фогт
источник