3

This question talks about validating a string representing a date, and in it folks mention that it's good to avoid using Exceptions for regular flow logic. And TryParse() is great for that. But TryParse() takes a string, and in in my case i've already got the year month and day as integers. I want to validate the month/day/year combination. For example February 30th.

It's pretty easy to just put a try/catch around new DateTime(int, int, int), but I'm wondering if there's a way to do it without relying on exceptions.

I'd also feel silly composing these ints into a string and then using TryParse().

1
  • 1
    FYI - "Parsing" always involves strings. Commented Jun 13, 2017 at 19:01

4 Answers 4

6

The following will check for valid year/month/day combinations in the range supported by DateTime, using a proleptic Gregorian calendar:

public bool IsValidDate(int year, int month, int day) { return year >= 1 && year <= 9999 && month >= 1 && month <= 12 && day >= 1 && day <= DateTime.DaysInMonth(year, month); } 

If you need to work with other calendar systems, then expand it as follows:

public bool IsValidDate(int year, int month, int day, Calendar cal) { return year >= cal.GetYear(cal.MinSupportedDateTime) && year <= cal.GetYear(cal.MaxSupportedDateTime) && month >= 1 && month <= cal.GetMonthsInYear(year) && day >= 1 && day <= cal.GetDaysInMonth(year, month); } 
Sign up to request clarification or add additional context in comments.

Comments

0

Use String Interpolation

int year = 2017; int month = 2; int day = 28; DateTime dt; DateTime.TryParse($"{month}/{day}/{year}", out dt); 

3 Comments

right, but i feel silly converting ints into strings and then asking DateTime to convert them back into ints.
This approach is sensitive to culture. You might concatenate 1/7/2017, thinking January 7th, but it could potentially be parsed as July 1st.
@orionelenzil: Good for you! That's exactly the right instinct :)
0

As far as I know, there's no easy way to check for a DateTime's int's validity besides concatenating the ints into a correctly formatted string beforehand.

To avoid try/catch-ing, I would write a static utility class which utilizes DateTime.TryParse:

using System; public static class DateTimeUtilities { public static bool TryParse(int year, int month, int day, out DateTime result) { return DateTime.TryParse( string.Format("{0}/{1}/{2}", year, month, day), out result); } } 

Usage:

DateTime dateTime; if (DateTimeUtilities.TryParse(2017, 2, 30, out dateTime)) { // success } else { // fail, dateTime = DateTime.MinValue } 

Pending the needs of your application, e.g. culture (thanks @Matt Johnson), I would also look into DateTime.TryParseExact.

4 Comments

Even though you build your string as year/month/day, this approach is still sensitive to culture. The current culture might not use the Gregorian calendar. For example, ar-SA uses the UmAlQuraCalendar by default.
Correct, I saw the OP instantiate a new DateTime(int, int, int), so I figured this solution will be good enough for his needs. I thought about culture after I had posted an answer, which is why I included (admittedly without much detail) the TryParseExact note in the most recent edit.
Yes, I noticed that you didn't include a culture, so I didn't include it in my solution either. That being said @MattJohnson's solution is definitely the best answer, I learned something new today!
-1

Look at it this way. Any code that you write:

  • Will have to check month ranges 1-12
  • Will have to check day ranges by month, which means you'll have to hard code an array
  • Will have to account for leap years, which can be a pain the the rear

Rather than doing ALL that, and reinventing the wheel, and potentially getting it wrong -- why don't you keep it simple and just wrap the DateTime constructor in a try-catch and keep it moving? Let the nerds up in Redmond do all the hard work for this common task. The best solution is one that any developer following you can understand and rely upon quickly.

I'd bet money that under the hood, TryParse and the DateTime constructor are using the exact same validators, except that the latter throws an exception while the former does not. TryParse, for this, is overkill with all the extra string manipulation involved.

5 Comments

DateTime.DaysInMonth does the second two items you describe. (actually, it does the first also, but throws an exception if out of range)
@MattJohnson So we're still dealing with a possible exception unless there's more code to prevent it le sigh
Right. There is no DateTime.IsValid(year, month, day, ...) static function out of the box. One would have to implement it, similar to how I showed in my answer.
Really love the "nerds up in Redmond" comment, btw. Fits me well. :)
Matt's answer is much better IMO than catching an exception. It's clearer and certainly performs significantly better.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.