Re: Check DateTime format
From: Dan S (DanS_at_discussions.microsoft.com)
Date: 07/22/04
- Next message: Steve: "WinForms application installer"
- Previous message: Democritus Rising: "3 speed fan"
- In reply to: Jon Skeet [C# MVP]: "Re: Check DateTime format"
- Next in thread: Cor Ligthert: "Re: Check DateTime format"
- Messages sorted by: [ date ] [ thread ]
Date: Thu, 22 Jul 2004 08:38:39 -0700
Interesting....thanks for the response Jon!
--
Dan S
"Jon Skeet [C# MVP]" wrote:
> Dan S <DanS@discussions.microsoft.com> wrote:
> > My application asks the user to enter in a date - in the mm/dd/yyyy
> > format. Is there any quick and easy way to verify the date the user
> > enters is formatted correctly? Right now I'm calling DateTime.Parse()
> > and catching the FormatException but it seems this is a bit
> > inefficient - catching the exception that is. There is some pretty
> > obvious delay while it traces back up the call stack. Is there a
> > better way? Something that returns a bool possibly?
>
> After the first time, which may involve a delay due to loading
> resources, throwing an exception is likely to be very fast - far faster
> than a user can actually notice. On my laptop I can throw a hundred
> thousand exceptions in a second - I think that's rather more than a
> user is likely to enter.
>
> I'm not saying that exceptions are always a nice way to go, but I
> wouldn't dismiss them for performance reasons - at least not in this
> case.
>
> You can use a regular expression to check the format, of course - but
> you may well find that doing so is more expensive than just trying to
> parse the date and catching the exception.
>
> You could probably do slightly better with a hard-coded test, something
> like:
>
> static readonly char[] LowerBounds = "00/00/1000".ToCharArray();
> static readonly char[] UpperBounds = "19/39/2999".ToCharArray();
> static bool IsProbablyValidDate(string date)
> {
> if (date.Length != 10)
> {
> return false;
> }
> for (int i=0; i < date.Length; i++)
> {
> char c=date[i];
> if (c < LowerBounds[i] || c > UpperBounds[i])
> {
> return false;
> }
> }
> return true;
> }
>
> That gets rid of *many* invalid dates, but not all - you'll still need
> to call DateTime.Parse (or preferrably DateTime.ParseExact) and catch
> the potential exception, unless you want to do all the parsing
> correctly.
>
> Note that it also requires the leading zeroes for months and days - if
> you don't want that, it becomes slightly trickier.
>
> (That only deals with dates in years 1000-2999; if you need to deal
> with earlier or later years, change the 7th character in
> LowerBounds/UpperBounds.)
>
> Here's a benchmark to compare the three approaches mentioned:
>
> using System;
> using System.Windows.Forms; // For MethodInvoker
> using System.Text.RegularExpressions;
> using System.Globalization;
>
> delegate void DoSomething();
>
> class Test
> {
> static string[] invalid = {"123123", "wibble", "32/12/3223",
> "14/23/1999", "04/35/1992", "02/29/2003"};
>
> static string[] valid = {"12/02/2321", "02/12/2312", "02/29/2004",
> "01/30/2000"};
>
> const int Iterations = 100000;
>
> static void Main()
> {
> Time (new MethodInvoker(TestRegex));
> Time (new MethodInvoker(TestHardCoded));
> Time (new MethodInvoker(TestNoPreCheck));
> }
>
> static void Time(MethodInvoker test)
> {
> DateTime start = DateTime.Now;
> test();
> DateTime end = DateTime.Now;
>
> Console.WriteLine ("{0}: {1}", test.Method.Name, end-start);
> }
>
> static readonly Regex Expression = new Regex
> (@"\d{1,2}\/\d{1,2}\/\d{4}", RegexOptions.Compiled);
> static void TestRegex()
> {
> for (int i=0; i < Iterations; i++)
> {
> foreach (string x in invalid)
> {
> if (Expression.IsMatch(x))
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
> throw new Exception("Invalid date passed");
> }
> catch
> {
> }
> }
> }
> foreach (string x in valid)
> {
> if (Expression.IsMatch(x))
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
>
> }
> catch
> {
> throw new Exception("Valid date failed");
> }
> }
> else
> throw new Exception("Valid date failed");
> }
> }
> }
>
> static void TestHardCoded()
> {
> for (int i=0; i < Iterations; i++)
> {
> foreach (string x in invalid)
> {
> if (IsProbablyValidDate(x))
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
>
> throw new Exception("Invalid date passed");
> }
> catch
> {
> }
> }
> }
> foreach (string x in valid)
> {
> if (IsProbablyValidDate(x))
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
>
> }
> catch
> {
> throw new Exception("Valid date failed");
> }
> }
> else
> throw new Exception("Valid date failed");
> }
> }
> }
>
> static void TestNoPreCheck()
> {
> for (int i=0; i < Iterations; i++)
> {
> foreach (string x in invalid)
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
> throw new Exception("Invalid date passed");
> }
> catch
> {
> }
> }
> foreach (string x in valid)
> {
> try
> {
> DateTime.ParseExact(x, "dd/mm/yyyy",
> CultureInfo.InvariantCulture);
> }
> catch
> {
> throw new Exception("Valid date failed");
> }
> }
> }
> }
>
> static readonly char[] LowerBounds = "00/00/1000".ToCharArray();
> static readonly char[] UpperBounds = "19/39/2999".ToCharArray();
> static bool IsProbablyValidDate(string date)
> {
> if (date.Length != 10)
> {
> return false;
> }
> for (int i=0; i < date.Length; i++)
> {
> char c=date[i];
> if (c < LowerBounds[i] || c > UpperBounds[i])
> {
> return false;
> }
> }
> return true;
> }
> }
>
> The results on my laptop were:
> TestRegex: 00:00:09.3437500
> TestHardCoded: 00:00:04.3437500
> TestNoPreCheck: 00:00:12.5156250
>
> Changing the regex to require exactly two digits instead of 1 or 2 for
> the month and day sped it up very slightly, but not really
> significantly.
>
> --
> Jon Skeet - <skeet@pobox.com>
> http://www.pobox.com/~skeet
> If replying to the group, please do not mail me too
>
- Next message: Steve: "WinForms application installer"
- Previous message: Democritus Rising: "3 speed fan"
- In reply to: Jon Skeet [C# MVP]: "Re: Check DateTime format"
- Next in thread: Cor Ligthert: "Re: Check DateTime format"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|