How to Validate a DateTime in C#? - c#

I doubt I am the only one who has come up with this solution, but if you have a better one please post it here. I simply want to leave this question here so I and others can search it later.
I needed to tell whether a valid date had been entered into a text box and this is the code that I came up with. I fire this when focus leaves the text box.
try
{
DateTime.Parse(startDateTextBox.Text);
}
catch
{
startDateTextBox.Text = DateTime.Today.ToShortDateString();
}

DateTime.TryParse
This I believe is faster and it means you dont have to use ugly try/catches :)
e.g
DateTime temp;
if(DateTime.TryParse(startDateTextBox.Text, out temp))
{
// Yay :)
}
else
{
// Aww.. :(
}

Don't use exceptions for flow control. Use DateTime.TryParse and DateTime.TryParseExact. Personally I prefer TryParseExact with a specific format, but I guess there are times when TryParse is better. Example use based on your original code:
DateTime value;
if (!DateTime.TryParse(startDateTextBox.Text, out value))
{
startDateTextox.Text = DateTime.Today.ToShortDateString();
}
Reasons for preferring this approach:
Clearer code (it says what it wants to do)
Better performance than catching and swallowing exceptions
This doesn't catch exceptions inappropriately - e.g. OutOfMemoryException, ThreadInterruptedException. (Your current code could be fixed to avoid this by just catching the relevant exception, but using TryParse would still be better.)

Here's another variation of the solution that returns true if the string can be converted to a DateTime type, and false otherwise.
public static bool IsDateTime(string txtDate)
{
DateTime tempDate;
return DateTime.TryParse(txtDate, out tempDate);
}

All the Answers are Quite great but if you want to use a single function ,this may work.
It will work with other date format but wont work with this date eg:05/06/202 it will consider it as valid date but it isnt.
private bool validateTime(string dateInString)
{
DateTime temp;
if (DateTime.TryParse(dateInString, out temp))
{
return true;
}
return false;
}

I would use the DateTime.TryParse() method: http://msdn.microsoft.com/en-us/library/system.datetime.tryparse.aspx

What about using TryParse?

A problem with using DateTime.TryParse is that it doesn't support the very common data-entry use case of dates entered without separators, e.g. 011508.
Here's an example of how to support this. (This is from a framework I'm building, so its signature is a little weird, but the core logic should be usable):
private static readonly Regex ShortDate = new Regex(#"^\d{6}$");
private static readonly Regex LongDate = new Regex(#"^\d{8}$");
public object Parse(object value, out string message)
{
msg = null;
string s = value.ToString().Trim();
if (s.Trim() == "")
{
return null;
}
else
{
if (ShortDate.Match(s).Success)
{
s = s.Substring(0, 2) + "/" + s.Substring(2, 2) + "/" + s.Substring(4, 2);
}
if (LongDate.Match(s).Success)
{
s = s.Substring(0, 2) + "/" + s.Substring(2, 2) + "/" + s.Substring(4, 4);
}
DateTime d = DateTime.MinValue;
if (DateTime.TryParse(s, out d))
{
return d;
}
else
{
message = String.Format("\"{0}\" is not a valid date.", s);
return null;
}
}
}

One liner:
if (DateTime.TryParse(value, out _)) {//dostuff}

protected bool ValidateBirthday(String date)
{
DateTime Temp;
if (DateTime.TryParse(date, out Temp) == true &&
Temp.Hour == 0 &&
Temp.Minute == 0 &&
Temp.Second == 0 &&
Temp.Millisecond == 0 &&
Temp > DateTime.MinValue)
return true;
else
return false;
}
//suppose that input string is short date format.
e.g. "2013/7/5" returns true or
"2013/2/31" returns false.
http://forums.asp.net/t/1250332.aspx/1
//bool booleanValue = ValidateBirthday("12:55"); returns false

private void btnEnter_Click(object sender, EventArgs e)
{
maskedTextBox1.Mask = "00/00/0000";
maskedTextBox1.ValidatingType = typeof(System.DateTime);
//if (!IsValidDOB(maskedTextBox1.Text))
if (!ValidateBirthday(maskedTextBox1.Text))
MessageBox.Show(" Not Valid");
else
MessageBox.Show("Valid");
}
// check date format dd/mm/yyyy. but not if year < 1 or > 2013.
public static bool IsValidDOB(string dob)
{
DateTime temp;
if (DateTime.TryParse(dob, out temp))
return (true);
else
return (false);
}
// checks date format dd/mm/yyyy and year > 1900!.
protected bool ValidateBirthday(String date)
{
DateTime Temp;
if (DateTime.TryParse(date, out Temp) == true &&
Temp.Year > 1900 &&
// Temp.Hour == 0 && Temp.Minute == 0 &&
//Temp.Second == 0 && Temp.Millisecond == 0 &&
Temp > DateTime.MinValue)
return (true);
else
return (false);
}

You can also define the DateTime format for a specific CultureInfo
public static bool IsDateTime(string tempDate)
{
DateTime fromDateValue;
var formats = new[] { "MM/dd/yyyy", "dd/MM/yyyy h:mm:ss", "MM/dd/yyyy hh:mm tt", "yyyy'-'MM'-'dd'T'HH':'mm':'ss" };
return DateTime.TryParseExact(tempDate, formats, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out fromDateValue);
}

DateTime temp;
try
{
temp = Convert.ToDateTime(grd.Rows[e.RowIndex].Cells["dateg"].Value);
grd.Rows[e.RowIndex].Cells["dateg"].Value = temp.ToString("yyyy/MM/dd");
}
catch
{
MessageBox.Show("Sorry The date not valid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop,MessageBoxDefaultButton.Button1,MessageBoxOptions .RightAlign);
grd.Rows[e.RowIndex].Cells["dateg"].Value = null;
}

DateTime temp;
try
{
temp = Convert.ToDateTime(date);
date = temp.ToString("yyyy/MM/dd");
}
catch
{
MessageBox.Show("Sorry The date not valid", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop,MessageBoxDefaultButton.Button1,MessageBoxOptions .RightAlign);
date = null;
}

protected static bool CheckDate(DateTime date)
{
if(new DateTime() == date)
return false;
else
return true;
}

Related

Is there a way to combine these 2 methods for DateTime and TimeSpan comparisons

Is there a way to combine these 2 methods for DateTime (ignore the ticks while comparing datetimes) and TimeSpan comparisons with generic parameter types and consolidating the logic?
private bool AreDateTimesEqual(DateTime? firstDateTime, DateTime? seconDateTime)
{
bool compareResult = false;
if (firstDateTime.HasValue && seconDateTime.HasValue)
{
firstDateTime = firstDateTime.Value.AddTicks(-firstDateTime.Value.Ticks);
seconDateTime = seconDateTime.Value.AddTicks(-seconDateTime.Value.Ticks);
compareResult = DateTime.Compare(firstDateTime.GetValueOrDefault(), seconDateTime.GetValueOrDefault()) == 0;
}
else if (!firstDateTime.HasValue && !seconDateTime.HasValue)
{
compareResult = true;
}
return compareResult;
}
private bool AreTimeSpansEqual(TimeSpan? firstTimeSpan, TimeSpan? secondTimeSpan)
{
bool compareResult = false;
if (firstTimeSpan.HasValue && secondTimeSpan.HasValue)
{
compareResult = TimeSpan.Compare(firstTimeSpan.GetValueOrDefault(), secondTimeSpan.GetValueOrDefault()) == 0;
}
else if (!firstTimeSpan.HasValue && !secondTimeSpan.HasValue)
{
compareResult = true;
}
return compareResult;
}
It sounds as if you're looking to compare two DateTime objects without the time part.
Keep in mind that both DateTime and TimeSpan implement the IEquatable interface which allows you to call Compare(...) on an instance of either.
To compare dates without time:
DateTime date1 = DateTime.Now;
DateTime date2 = DateTime.Now.AddHours(5);
return date1.Date.Compare(date2.Date) == 0;
For a DateTime variable, the .Date property will return the date without the time.
To compare TimeSpans, you would also use .Compare and check that the result is 0 (for equality).

Nullable-How to compare only Date without Time in DateTime types in C#?

How to compare only Date without Time in DateTime types in C#.One of the date will be nullable.How can i do that??
DateTime val1;
DateTime? val2;
if (!val2.HasValue)
return false;
return val1.Date == val2.Value.Date;
You can use the Date property of DateTime object
Datetime x;
Datetime? y;
if (y != null && y.HasValue && x.Date == y.Value.Date)
{
//DoSomething
}
This uses short-circuit to avoid comparisons if nullable date is null, then uses the DateTime.Date property to determine equivalency.
bool Comparison(DateTime? nullableDate, DateTime aDate) {
if(nullableDate != null && aDate.Date == nullableDate.Value.Date) {
return true;
}
return false;
}
bool DatesMatch(DateTime referenceDate, DateTime? nullableDate)
{
return (nullableDate.HasValue) ?
referenceDate.Date == nullableDate.Value.Date :
false;
}
If you want a true comparison, you can use:
Datetime dateTime1
Datetime? dateTime2
if(dateTime2.Date != null)
dateTime1.Date.CompareTo(dateTime2.Date);
Hope it helps...
The only challenging aspect here is the fact that you want something which is both DateTime and nullable.
Here is the solution for standard DateTime: How to compare only Date without Time in DateTime types in C#?
if(dtOne.Date == dtTwo.Date)
For nullable, it's just a matter of choice. I would choose an extension method.
class Program
{
static void Main(string[] args)
{
var d1 = new DateTime(2000, 01, 01, 12, 24, 48);
DateTime? d2 = new DateTime(2000, 01, 01, 07, 29, 31);
Console.WriteLine((d1.Date == ((DateTime)d2).Date));
Console.WriteLine((d1.CompareDate(d2)));
Console.WriteLine((d1.CompareDate(null)));
Console.WriteLine("Press enter to continue...");
Console.ReadLine();
}
}
static class DateCompare
{
public static bool CompareDate(this DateTime dtOne, DateTime? dtTwo)
{
if (dtTwo == null) return false;
return (dtOne.Date == ((DateTime)dtTwo).Date);
}
}
You could create a method like the one below, following the similar return values as the .net framework comparisons, giving -1 when the left side is smallest, 0 for equal dates, and +1 for right side smallest:
private static int Compare(DateTime? firstDate, DateTime? secondDate)
{
if(!firstDate.HasValue && !secondDate.HasValue)
return 0;
if (!firstDate.HasValue)
return -1;
if (!secondDate.HasValue)
return 1;
else
return DateTime.Compare(firstDate.Value.Date, secondDate.Value.Date);
}
Of Course a nicer implementation would be to create an extension method for this.

Getting the exact format for DateTime from an XML file

In my XML I have a date value as shown below:
[CDATA[07/07/1980]]
I do the following to retrieve the date:
public static DateTime? GetDateTimeValue(string dateTimeString)
{
DateTime i;
if ((dataTimeString != null) && (dataTimeString.Value.Trim() != ""))
if (DateTime.TryParse(dateTimeString, out i))
return i;
return null;
}
The value I get is 07/07/1980 12:00:00 AM.
I can do the following:
DatdTime.TryParse(dateTimeString.ToShortDateString())
But I don't want to manipulate the data in any way. I want to get the date as is.
Any help will be greatly appreciated.
Here is a method I use, but I do not use a nullable DateTime.
private static DateTime nodate = new DateTime(1900, 1, 1);
public static DateTime NODATE { get { return nodate; } }
public static DateTime GetDate(object obj) {
if ((obj != null) && (obj != DBNull.Value)) { // Databases return DBNull.Value
try {
return Convert.ToDateTime(obj);
} catch (Exception) { }
try {
return DateTime.Parse(obj.ToString());
} catch (Exception) { }
}
return NODATE;
}
I can't always use TryParse because a lot of my code has to be Compact Framework safe.
If anything goes wrong, I will see my NODATE value (January 1, 1900) in my date fields. It is pretty safe to guess that most of my database programs have no date if they try to display something indicating they were input on January 1st of 1900. After all: Everyone has New Year's off, right? :)

how to parse a time value of "400" (equivalent to 4:00) using DateTime.TryParseExact

I'm trying to convert user entered times into TimeSpans. Because TimeSpan does not have a TryParseExact method I'm using the one in DateTime and converting the output from it.
The formats I want to handle are: 04:00, 0400, 4:00, and 400. The first three aren't a problem and correspond to the first three cases in the if/else structure in the method below. The forth could correspond to either of the last two, but neither is working.
private void dataGridView1_CellParsing(object sender, DataGridViewCellParsingEventArgs e)
{
CultureInfo enUS = new CultureInfo("en-US");
DateTime parsedDate = new DateTime();
string userInput = (string)e.Value;
if (DateTime.TryParseExact(userInput, "HH:mm", enUS, DateTimeStyles.None, out parsedDate))
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
else if (DateTime.TryParseExact(userInput, "HHmm", enUS, DateTimeStyles.None, out parsedDate))
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
else if (DateTime.TryParseExact(userInput, "H:mm", enUS, DateTimeStyles.None, out parsedDate))
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
else if (DateTime.TryParseExact(userInput, "hmm", enUS, DateTimeStyles.None, out parsedDate))
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
else if (DateTime.TryParseExact(userInput, "Hmm", enUS, DateTimeStyles.None, out parsedDate))
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
}
I would simply do a string.PadLeft(int totalWidth, char paddingChar) on the user input to ensure the length of the string is 4 characters (minimum). As a result, your Hmm input would then qualify for the HHmm format.
userInput = userInput.PadLeft(4, '0'); // "400" becomes "0400"
If your string already meets or exceeds 4 in length, it will be left unmodified.
just a general comment- you can have a boolean variable (like isValidDate) initialized to false and set to true where you have
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
then move that code to an if block at the end
if isValidDate then
{
e.Value = parsedDate.TimeOfDay;
e.ParsingApplied = true;
}
You can use this overload of DateTime.TryParseExact to specify multiple formats in one go. It doesn't look like the Hmm format will work but you can use integer parsing instead like this:
internal static class Program
{
private static void Main(string[] args)
{
Console.WriteLine(ParseTime("04:00"));
Console.WriteLine(ParseTime("0400"));
Console.WriteLine(ParseTime("4:00"));
Console.WriteLine(ParseTime("400"));
}
public static TimeSpan ParseTime(string input)
{
CultureInfo cultureInfo = new CultureInfo("en-US");
DateTime parsedDateTime;
if (!DateTime.TryParseExact(input, new [] { "HH:mm", "HHmm", "H:mm" }, cultureInfo, DateTimeStyles.None, out parsedDateTime))
{
int parsedInt32;
if (!int.TryParse(input, NumberStyles.None, cultureInfo, out parsedInt32))
{
throw new ArgumentException("Unable to parse input value as time in any of the accepted formats.", "input");
}
int remainder;
int quotient = Math.DivRem(parsedInt32, 100, out remainder);
return new TimeSpan(quotient, remainder, 0);
}
return parsedDateTime.TimeOfDay;
}
}
I used a regex option (I know normally the worse thing to use but the system I was using required it... don't ask):
Regex.Replace("935", "^([0-9]{3})$", "0$1"); // outputs "0935"
I solved this as follows:
DateTime.TryParseExact(
userInput,
new[] { "%H", "Hm", "H:m" },
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out parsedDate);
I must give credit for the help I got from: Why is TryParseExact failing on Hmm and Hmmss?

Get just the hour of day from DateTime using either 12 or 24 hour format as defined by the current culture

.Net has the built in ToShortTimeString() function for DateTime that uses the CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern format. It returns something like this for en-US: "5:00 pm". For a 24 hour culture such as de-DE it would return "17:00".
What I want is a way to just return just the hour (So "5 pm" and "17" in the cases above) that works with every culture. What's the best/cleanest way to do this?
Thanks!
// displays "15" because my current culture is en-GB
Console.WriteLine(DateTime.Now.ToHourString());
// displays "3 pm"
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("en-US")));
// displays "15"
Console.WriteLine(DateTime.Now.ToHourString(new CultureInfo("de-DE")));
// ...
public static class DateTimeExtensions
{
public static string ToHourString(this DateTime dt)
{
return dt.ToHourString(null);
}
public static string ToHourString(this DateTime dt, IFormatProvider provider)
{
DateTimeFormatInfo dtfi = DateTimeFormatInfo.GetInstance(provider);
string format = Regex.Replace(dtfi.ShortTimePattern, #"[^hHt\s]", "");
format = Regex.Replace(format, #"\s+", " ").Trim();
if (format.Length == 0)
return "";
if (format.Length == 1)
format = '%' + format;
return dt.ToString(format, dtfi);
}
}
I would check to see whether CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern contains "h", "hh", "H", "HH", "t" or "tt", and in what order, and then build your own custom format string from those.
e.g.
en-US: map "h:mm tt" to "h tt"
ja-JP: map "H:mm" to "H"
fr-FR: map "HH:mm" to "HH"
Then use .ToString(), passing in the string you built.
Example code - this basically strips out everything that's not t, T, h, H, and multiple spaces. But, as pointed out below, just a string of "H" could fail...
string full = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
string sh = String.Empty;
for (int k = 0; k < full.Length; k++)
{
char i = full[k];
if (i == 'h' || i == 'H' || i == 't' || i == 'T' || (i == ' ' && (sh.Length == 0 || sh[sh.Length - 1] != ' ')))
{
sh = sh + i;
}
}
if (sh.Length == 1)
{
sh = sh + ' ';
string rtnVal = DateTime.Now.ToString(sh);
return rtnVal.Substring(0, rtnVal.Length - 1);
{
else
{
return DateTime.Now.ToString(sh);
}
Use this:
bool use2fHour =
CultureInfo
.CurrentCulture
.DateTimeFormat
.ShortTimePattern.Contains("H");
you may use DateTime.ToString() and provide format tyou want as an argument.
Ugh, I didn't want to be interested but now I am! Here's the code which respects all cultures and renders the AM/PM designators in the correct position, as well as recognizing 24-hour format, all depending on the culture.
Basically, this static extension method is overloaded to take the current culture (no parameters) or a specified culture.
DateTime.Now.ToTimeString()
DateTime.Now.ToTimeString(someCultureInfo)
Code is below, includes sample program:
public static class DateTimeStaticExtensions
{
private static int GetDesignatorIndex(CultureInfo info)
{
if (info.DateTimeFormat
.ShortTimePattern.StartsWith("tt"))
{
return 0;
}
else if (info.DateTimeFormat
.ShortTimePattern.EndsWith("tt"))
{
return 1;
}
else
{
return -1;
}
}
private static string GetFormattedString(int hour,
CultureInfo info)
{
string designator = (hour > 12 ?
info.DateTimeFormat.PMDesignator :
info.DateTimeFormat.AMDesignator);
if (designator != "")
{
switch (GetDesignatorIndex(info))
{
case 0:
return string.Format("{0} {1}",
designator,
(hour > 12 ?
(hour - 12).ToString() :
hour.ToString()));
case 1:
return string.Format("{0} {1}",
(hour > 12 ?
(hour - 12).ToString() :
hour.ToString()),
designator);
default:
return hour.ToString();
}
}
else
{
return hour.ToString();
}
}
public static string ToTimeString(this DateTime target,
CultureInfo info)
{
return GetFormattedString(target.Hour, info);
}
public static string ToTimeString(this DateTime target)
{
return GetFormattedString(target.Hour,
CultureInfo.CurrentCulture);
}
}
class Program
{
static void Main(string[] args)
{
var dt = new DateTime(2010, 6, 10, 6, 0, 0, 0);
CultureInfo[] cultures =
CultureInfo.GetCultures(CultureTypes.SpecificCultures);
foreach (CultureInfo culture in cultures)
{
Console.WriteLine(
"{0}: {1} ({2}, {3}) [Sample AM: {4} / Sample PM: {5}",
culture.Name, culture.DateTimeFormat.ShortTimePattern,
(culture.DateTimeFormat.AMDesignator == "" ?
"[No AM]":
culture.DateTimeFormat.AMDesignator),
(culture.DateTimeFormat.PMDesignator == "" ?
"[No PM]":
culture.DateTimeFormat.PMDesignator),
dt.ToTimeString(culture), // AM sample
dt.AddHours(12).ToTimeString(culture) // PM sample
);
}
// pause program execution to review results...
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
var culture = CultureInfo.CurrentCulture;
bool uses24HourClock = string.IsNullOrEmpty(culture.DateTimeFormat.AMDesignator);
var dt = DateTime.Now;
string formatString = uses24HourClock ? "HH" : "h tt";
Console.WriteLine(dt.ToString(formatString, culture));
Sam's edit:
Here's code to prove this doesn't work.
var date = new DateTime(2010, 1, 1, 16, 0, 0);
foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures))
{
bool amMethod = String.IsNullOrEmpty(cultureInfo.DateTimeFormat.AMDesignator);
bool formatMethod = cultureInfo.DateTimeFormat.ShortTimePattern.Contains("H");
if (amMethod != formatMethod)
{
Console.WriteLine("**** {0} AM: {1} Format: {2} Designator: {3} Time: {4}",
cultureInfo.Name,
amMethod,
formatMethod,
cultureInfo.DateTimeFormat.AMDesignator,
date.ToString("t", cultureInfo.DateTimeFormat));
}
}
Try using DateTime.Hour property.

Categories