Нет статической функции IsValidDate()
, поэтому вы должны написать ее самостоятельно, первая наивная реализация может быть:
public static bool IsValidDate(int year, int month, int day)
{
if (year < DateTime.MinValue.Year || year > DateTime.MaxValue.Year)
return false;
if (month < 1 || month > 12)
return false;
return day > 0 && day <= DateTime.DaysInMonth(year, month);
}
Я сказал, что это наивная реализация, потому что (помимо диапазона аргументов) единственная проверка, чтобы увидеть, существует ли дата для високосного года. На практике это может не сработать из-за проблем с календарем, если вы работаете с негригорианскими календарями (и пропускаете дни даже в григорианском календаре, который использовался для выравнивания даты по юлианскому календарю).
Работа с календарями
Эти предположения могут быть нарушены для негригорианских календарей:
- 1 января 01 - наименьшая действительная дата. Это неправда. Разные календари имеют разные наименьшие даты. Этот лимит составляет всего лишь
DateTime
технический лимит, но может существовать календарь (или Эра в календаре) с другой минимальной (и максимальной) датой.
- Количество месяцев в одном году меньше или равно 12. Это неправда, в некоторых календарях верхняя граница равна 13 и не всегда одинакова для каждого года.
- Если дата действительна (согласно всем другим правилам), то это действительная дата. Это неправда, календарь может иметь более одной эпохи, и не все даты действительны (возможно, даже в пределах диапазона дат эпохи).
Правила для управления этим довольно сложны, и слишком легко что-то забыть, поэтому в данном случае перехват исключения может быть не такой уж плохой идеей. Лучшая версия предыдущей функции проверки может просто обеспечить базовую проверку и полагаться на DateTime
для проверки других правил:
public static DateTime? TryNew(int year,
int month,
int day,
Calendar calendar)
{
if (calendar == null)
calendar = new GregorianCalendar();
if (year < calendar.MinSupportedDateTime.Year)
return null;
if (year > calendar.MaxSupportedDateTime.Year)
return null;
// Note that even with this check we can't assert this is a valid
// month because one year may be "shared" for two eras moreover here
// we're assuming current era.
if (month < 1 || month > calendar.GetMonthsInYear(year))
return null;
if (day <= 0 || day > DateTime.DaysInMonth(year, month))
return null;
// Now, probably, date is valid but there may still be issues
// about era and missing days because of calendar changes.
// For all this checks we rely on DateTime implementation.
try
{
return new DateTime(year, month, day, calendar);
}
catch (ArgumentOutOfRangeException)
{
return null;
}
}
Тогда, учитывая эту новую функцию, ваш оригинальный код должен быть:
return TryNew(year, month, day) ?? DateTime.MinValue;