There is no static function IsValidDate() , so you have to write it yourself, the first naive implementation may be:
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); }
I said that this is a naive implementation, because (besides the range of arguments) the only check to see if the date exists belongs to the temporal year. In practice, this may fail due to problems with calendars if you work with non-Gregorian calendars (and missing days even in the Gregorian calendar, which was used to align the date from the Julian calendar).
Work with calendars
These assumptions may be violated for non-Gregorian calendars:
- January 1, 01 is the smallest valid date. It is not true. Different calendars have a different smallest date. This limit is only a technical limitation of
DateTime , but it can be a calendar (or era in a calendar) with a different minimum (and maximum) date. - The number of months in a year is less than or equal to 12. This is not true, in some calendars the upper limit is 13, and this is not always the same for each year.
- If the date is valid (according to all other rules), then this is a valid date. This is not true, a calendar can have more than one era, and not all dates are valid (possibly even within the date range of a date).
The rules for managing are pretty complicated, and it's too easy to forget something, so catching an exception might not be such a bad idea in this case. The best version of the previous validation function can simply provide a basic validation and rely on DateTime to validate other rules:
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; } }
Then, given this new feature, your source code should be:
return TryNew(year, month, day) ?? DateTime.MinValue;
Adriano repetti
source share