I'm writing a C# class that will convert strings to dates. Pretty easy I guess. The class accepts formatstrings like "yyyy-MM-dd" and inputstrings like "2010-10-10"
However I have some cases that give me trouble:
format "yyyyMMdd" input "19950000"
or
format "dd-MM-yyyy" input "00-06-2001"
Note that these cases have zeroes ('00') for day and/or month, and that these cannot be converted to a DateTime. I'll need to replace them.
To handle theses cases I need to split the input string in the parts, one each for day, month and year, so I can set some default day and month (probably 01) if they are missing. But I need to use the formatstring to accomplish this.
So the question is, how can I split an inputstring in the components specified in the formatstring?
Thanks
[UPDATE] Using Joe's answer I came up with this:
string[] formats = { format, format.Replace("dd", "00").Replace("MM", "00"), format.Replace("dd", "00"), format.Replace("MM", "00") };
// Parse input
DateTime d = DateTime.ParseExact(txtDate.Text, formats, CultureInfo.InvariantCulture, DateTimeStyles.None);
This uses the supplied format and creates alternative formats with zeroes ('00') for day, month and both day and month.
Thanks Joe!
If you have a well-defined set of formats, you can use DateTime.ParseExact, passing an array of format strings.
// Define all allowed formats
string[] formats = { "yyyyMMdd", "yyyyMM00", "yyyy0000" };
// Parse input
DateTime d;
d = DateTime.ParseExact("20100930", formats,
CultureInfo.InvariantCulture, DateTimeStyles.None);
d = DateTime.ParseExact("20100900", formats,
CultureInfo.InvariantCulture, DateTimeStyles.None);
d = DateTime.ParseExact("20100000", formats,
CultureInfo.InvariantCulture, DateTimeStyles.None);
Missing days / months will be set to a default of 1.
My approach would be to define various Regular Expressions and using a chain of responsibility design pattern, pass the value to the first, if matches it stops there and if not sends to the next one until one of them matches the string.
My regex pattern would separate date, month and year element and set a default value for each if it is 0.
Here for Chain-of-responsibility_pattern:
http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern
private const string Pattern_dd-mm-yyyy = "(\d\d)-(\d\d)-(\d){4}";
private const string Pattern_ddmmyyyy = "(\d\d)(\d\d)(\d){4}";
private const string Pattern_ddSlashmmSlashyyyy = "(\d\d)/(\d\d)/(\d){4}";
I don't fully understand your problem (I don't have the rep for a comment) but I can still give you some advices.
First of all, the DateTime class provides a ParseExact method (http://msdn.microsoft.com/en-us/library/w2sa9yss(v=VS.80).aspx) which accepts a formatting string for date and time. You can pass your format string to it
I don't clearly understand the part about the cases: do you need to accept timestamps in multiple formats? If so, you can try/catch until you find a match, or loop using the TryParseExact method which almost works the same.
Once you have a DateTime value, use the Year, Month and Day properties to get the components you've been searching in the input string
Related
I am trying to parse a string to Datetime, but it is not working and giving an error:
"String was not recognized as a valid DateTime."
The string is perfect.
Here is the code:
string deliv = DeliveryDateTextBox.Text;
string[] delivday = deliv.Split('-');
int year, month, day;
int.TryParse(delivday[0], out day);
int.TryParse(delivday[1], out month);
int.TryParse(delivday[2], out year);
string dtt = day + "/" + month + "/" + year;
DateTime datet = DateTime.ParseExact(dtt, "dd/MM/yyyy", null);
jobcard.DeliveryDate = datet;
I debugged the code and it is giving {01-01-0001 12:00:00 AM} on datet.
Besides the fact that you should be using new DateTime(year, month, day), or even DateTime.TryParseExact(deliv, "d-M-yyyy", .... ) on the original string...
Your call to DateTime.ParseExact() is failing because your input string has single-digit day and/or single-digit month, while your pattern dd/MM/yyyy demands double digits for both.
This can be fixed by using d/M/yyyy for the pattern, it will accept single and double digits. But please don't, see the first paragraph!
You over complicated things in this code.
Manually parsing the string to extract int values of day, month and year just to recombine them into a new string and parsing it makes no sense.
Simply try to parse the original string:
DateTime datet;
if(DateTime.TryParseExact(
DeliveryDateTextBox.Text,
"dd-MM-yyyy",
CultureInfo.InvariantCulture,
DateTimeStyles.None, out datet))
{
// string was successfully parsed to dateTime.
}
There is no "perfect" DateTime String. How you can can/should represent a DateTime is dependent 100% on the CultureFormat of Windows, which can be totally different even within a langauge: For example en-gb and en-us disagree on what the decimal, thousand seperator are and in which order the date components should be listed.
Your whole code does not make a lot of sense. It seems you have some disjointed textboxes where the user inputs the day, month and year seperately. Then you parse them to int. Then you turn them into a string. Then you try to parse the string.
And at no point do you even check if the original user inputs are valid. That original parsing to Int might already fail. So you might try to parse 0/0/0 into a DateTime. To which your output is actually the perfect answer. And then there is stuff like anything before 1800 or so being literally not on the Gregorian calendar.
If you want the user to input a date, use a DatePicker element. Every GUI technology I know of has one. They give you DateTimes as return value. Do not try your custom workaround.
Is DateTime format strictly dependent on the language of the OS being used? Because the following doesn't work:
DateTime date = DateTime.Now;
var usCultureInfo = CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine(date.ToString("dddd MM-dd-yy"),usCultureInfo);
I'd like the result to print out as Saturday, 06-29-2013 but the day gets printed out in Korean 토요일, 06-29-2013.
You are a victim of Composite Formatting overload for Console.WriteLine where you could pass Format string and a series of object to be inserted in the placeholders of the format string
You need to write in this way
Console.WriteLine(date.ToString("dddd MM-dd-yy",usCultureInfo));
and you get the right day text.
See the specs here DateTime.ToString(format, IFormatProvider)
Or simply you can use
string abc=date.ToString("dddd MM-dd-yy");
I need to validate the date format using regular expression in C#.
Here is the format: "YYYYMMDD"
Regular expressions aren't suitable for this task. It is difficult for example to write a regular expression that matches the valid date "20080229" but not the invalid date "20100229".
Instead you should use DateTime.TryParseExact with the format string "yyyyMMdd". Here is an example:
string s = "20100229";
DateTime result;
if (!DateTime.TryParseExact(
s,
"yyyyMMdd",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal,
out result))
{
Console.WriteLine("Invalid date entered.");
};
Ok, this is the most beautiful regex I've ever built. This accounts for all leap years since 1582, the introduction of leap. It also handles non leap every fourth century. For example, 1600 is leap but 1700 is not though it is divisible by four. I tested this on all days between 1582 and 9999.
var yyyymmdd = new RegExp("^(?:(?:(?:(?:(?:[13579][26]|[2468][048])00)|(?:[0-9]{2}(?:(?:[13579][26])|(?:[2468][048]|0[48]))))(?:(?:(?:09|04|06|11)(?:0[1-9]|1[0-9]|2[0-9]|30))|(?:(?:01|03|05|07|08|10|12)(?:0[1-9]|1[0-9]|2[0-9]|3[01]))|(?:02(?:0[1-9]|1[0-9]|2[0-9]))))|(?:[0-9]{4}(?:(?:(?:09|04|06|11)(?:0[1-9]|1[0-9]|2[0-9]|30))|(?:(?:01|03|05|07|08|10|12)(?:0[1-9]|1[0-9]|2[0-9]|3[01]))|(?:02(?:[01][0-9]|2[0-8])))))$");
Another version using dashes
var yyyyDashMmDashDd = new RegExp("^(?:(?:(?:(?:(?:[13579][26]|[2468][048])00)|(?:[0-9]{2}(?:(?:[13579][26])|(?:[2468][048]|0[48]))))-(?:(?:(?:09|04|06|11)-(?:0[1-9]|1[0-9]|2[0-9]|30))|(?:(?:01|03|05|07|08|10|12)-(?:0[1-9]|1[0-9]|2[0-9]|3[01]))|(?:02-(?:0[1-9]|1[0-9]|2[0-9]))))|(?:[0-9]{4}-(?:(?:(?:09|04|06|11)-(?:0[1-9]|1[0-9]|2[0-9]|30))|(?:(?:01|03|05|07|08|10|12)-(?:0[1-9]|1[0-9]|2[0-9]|3[01]))|(?:02-(?:[01][0-9]|2[0-8])))))$");
I love that this works for nearly all languages, as long as they support regex. While its arguably more sensible to use a language specific date parser, I thinks this shows the power and elegance of regular expressions.
Here is an image of the pattern with slashes in Regexper if you want to see it.
Consider using DateTime.TryParseExact to validate the date.
You can use the method to silmultaneously validate and read the DateTime value.
For example:
DateTime dateValue;
if (DateTime.TryParseExact(dateString, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out dateValue))
{
//Parsed Successfully
}
Hey there, I am extracting the date and time of creation of a file. the date should be 7/1/2010 2:08 PM but the format comes out as 2:08:07 01/07/2010 when called from my application. I would like it show as it does in the file explorer (7/1/2010 2:08 PM). How can I accomplish this?
string createdOnCMM = Creationtime; //this returns the 2:08:07 01/07/2010
// I think I need a modified verison of the following to reformat it
DateTime dt = Convert.ToDateTime(createdOnCMM);
String.Format("0:{dd/MM/yyyy HH:mm:ss}", dt);
Your compound format string isn't quite right. Try this:
string s = string.Format("{0:dd/MM/yyyy HH:mm:ss}", dt);
Alternatively, if you only want to format the DateTime, call ToString directly:
string s = dt.ToString("dd/MM/yyyy HH:mm:ss");
(That's a more readable approach, IMO.)
Note that this is very culture-specific at the moment. That may be okay for your intended use, but you should be aware of it.
From Microsoft's Standard Date and Time Format Strings, you should be able to get what you want by using the g format string like the following:
String.Format("{0:g}", dateTimeValue);
That should yield the format you'd like.
If you just need to format with your current culture's short date string then use the g specifier as mentioned in Eric's answer.
If you need the exact format that you mentioned, regardless of your current culture, then one of the following should do the trick:
string formatted = dt.ToString("M'/'d'/'yyyy h':'mm tt");
// or
string formatted = string.Format("{0:M'/'d'/'yyyy h':'mm tt}", dt);
How to convert the string "28/09/2009" to DateTime in a specific format?
Ex:
I want to convert "2009-09-28 17:30:40" to DateTime.
I want to convert "28/09/2009 17:30:40" to DateTime.
I want to convert "20090928 17:30:40" to DateTime.
There are multiple possible formats. I tried this:
string[] formats = new string[] {"yyyymmdd","yyyymmddThhmmss","yyyy/mm/dd hh:mm:ss","yyyy/mm/dd","yyyy-mm-dd hh:mm:ss","yyyy-mm-dd"};
IFormatProvider culture = new CultureInfo("en-US", true);
DateTime formattedDate = DateTime.ParseExact(aDate, formats, culture, DateTimeStyles.None);
This example throws an exception with the message "String was not recognized as a valid DateTime".
What's wrong in the code above?
None of your formats put the day first, like this: "dd/MM/yyyy".
Also note the capital 'M', since lower case 'm' is for 'minutes'. You have a similar problem with your hours; since your samples all use 24 hour time you need a capital 'H'.
Your format string array should look like this:
string[] formats = {"dd/MM/yyyy", "yyyy-MM-dd HH:mm:ss", "dd/MM/yyyy HH:mm:ss", "yyyyMMdd HH:mm:ss"};
Those formats exactly match your supplied sample strings.
Additionally, you probably want to use the invariant culture rather than en-US in this case. Otherwise, the '/' character in your format strings is really a culture-specific date separator, which a user might over-ride on their local system.
Finally, since you're obviously having trouble matching up the strings up, you might want to use TryParseExact(), which works just like parse exact but uses an out parameter rather than returning the value, so that it can return a boolean to indicate success or failure rather than throwing an exception.
See the complete format string reference here:
http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx