Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing Time, Date/Time, or Date

I would like to parse an input string that contains either a time, a date and time, or just a date, and I need to know which parts where included in the input string.

Parsing the actual values is not a problem:

var dt1 = DateTime.Parse("10:00:00", CultureInfo.CurrentCulture);
var dt2 = DateTime.Parse("10pm", CultureInfo.CurrentCulture);
var dt3 = DateTime.Parse("01/02/2014", CultureInfo.CurrentCulture);
var dt4 = DateTime.Parse("01/02/2014 10:00:00", CultureInfo.CurrentCulture);

These all successfully parse as you'd expect.

However, if the date element is not provided, DateTime.Parse automatically adds the current date to the time. So if today was 1/1/2014, then DateTime.Parse("10pm") actually returns a DateTime object set to 1/1/2014 10:00:00.

Also, if I parse an input string with no time element, then DateTime.Parse assumes a time of 00:00:00.

So after the parse has occurred, simply by inspecting the resulting DateTime object, I cannot determine if the original input string specified the date and time, or the date only or the time only.

I could use a simple RegEx to look for the standard time pattern, e.g. ^\d\d:\d\d$ but I don't want to assume that all cultures use the same pattern to specify time.

How can I robustly detect which date and time elements were provided in the original input string regardless of culture, and without using some fuzzy regex that may only work for some cultures?

like image 446
BG100 Avatar asked Jan 10 '14 14:01

BG100


1 Answers

You could use DateTime.Parse with DateTimeStyles.NoCurrentDateDefault which prevents you from the current date:

CultureInfo culture = CultureInfo.InvariantCulture;

var dt1 = DateTime.Parse("10:00:00", culture, DateTimeStyles.NoCurrentDateDefault);
var dt2 = DateTime.Parse("10pm", culture, DateTimeStyles.NoCurrentDateDefault);
var dt3 = DateTime.Parse("01/02/2014", culture, DateTimeStyles.NoCurrentDateDefault);
var dt4 = DateTime.Parse("01/02/2014 10:00:00", culture, DateTimeStyles.NoCurrentDateDefault);
// problem, is this a date only or a date+time?
var dt5 = DateTime.Parse("01/02/2014 00:00:00", culture, DateTimeStyles.NoCurrentDateDefault);

Now the year is 1. On this way you could at least identify times only. You still have the problem to differentiate between dates without time and midnight-datetimes.

So this might be sufficient:

bool dt1TimeOnly, dt1DateOnly, dt1DateAndTime;
dt1TimeOnly = dt1.Year == 1;
dt1DateOnly = !dt1TimeOnly && dt1.TimeOfDay == TimeSpan.FromHours(0);
dt1DateAndTime = !dt1TimeOnly && !dt1DateOnly;

So the only way to identify exactly the input is to provide all supported formats and use DateTime.TryParseExact on each.

For example with this enum:

public enum DateTimeType
{ 
    Date,
    Time,
    DateTime,
    Unknown
}

and this method:

public DateTimeType GetDateTimeType(string input, CultureInfo culture, out DateTime parsedDate)
{ 
   if(culture == null) culture = CultureInfo.CurrentCulture;
   var supportedFormats = new[] { 
        new{ Pattern = culture.DateTimeFormat.ShortDatePattern, Type = DateTimeType.Date },
        new{ Pattern = culture.DateTimeFormat.ShortTimePattern, Type = DateTimeType.Time },
        new{ Pattern = culture.DateTimeFormat.LongDatePattern, Type  = DateTimeType.Date },
        new{ Pattern = culture.DateTimeFormat.LongTimePattern, Type  = DateTimeType.Time },
        new{ Pattern = "hhtt", Type = DateTimeType.Time},
        new{ 
            Pattern = culture.DateTimeFormat.ShortDatePattern + " " + culture.DateTimeFormat.LongTimePattern, 
            Type = DateTimeType.DateTime
        }
    };

    foreach(var fi in supportedFormats)
    {
        DateTime dt;
        if (DateTime.TryParseExact(input, fi.Pattern, culture, DateTimeStyles.NoCurrentDateDefault, out dt))
        {
            parsedDate = dt;
            return fi.Type;
        }
    }
    parsedDate = default(DateTime);
    return DateTimeType.Unknown;
}

Now this yields the correct dates and DateTimeTypes:

DateTime dt1;
DateTimeType type1 = GetDateTimeType("10:00:00", culture, out dt1);
DateTime dt2;
DateTimeType type2 = GetDateTimeType("10pm", culture, out dt2);
DateTime dt3;
DateTimeType type3 = GetDateTimeType("01/02/2014", culture, out dt3);
DateTime dt4;
DateTimeType type4 = GetDateTimeType("01/02/2014 10:00:00", culture, out dt4);
DateTime dt5;
DateTimeType type5 = GetDateTimeType("01/02/2014 00:00:00", culture, out dt5);
like image 56
Tim Schmelter Avatar answered Oct 14 '22 05:10

Tim Schmelter