How can I parse dates with a suffix "th", "st" or "nd" on the day of the month?
I'm having trouble using DateTime.Parse
I'm handling a variety of formats of dates and some of which are of the formatJanuary 11th
or February 22nd
and so on.
DateTime.Parse
throws an exception trying to parse these sort of dates.
I was wondering if there is a built in functionality in DateTime that I am missing, like a flag I can set that will make Parse behave in a more acceptable way.
I am aware that this is solvable with a relatively simple regular expression, moreover I already have a class that fuzzy matches dates that I wrote, however I would like to know if there is a built in way to perform this sort of extraction since it will more likely be easier to maintain in the long run than reinventing the wheel.
There isn't anything inbuilt in .Net framework to parse dates in format of January 11th or February 22nd
etc. You have to remove the suffix characters and then you can use DateTime.TryParseExact
.
For dates with Suffix st
, th
, you can use string.Replace
to remove that part and then use DateTime.TryParseExact
. Like.
string str = "1st February 2013";
DateTime dtObject;
string replacedStr = str.Substring(0,4)
.Replace("nd","")
.Replace("th","")
.Replace("rd","")
.Replace("st","")
+ str.Substring(4);
if (DateTime.TryParseExact(replacedStr,
"dd MMMMM yyyy",
CultureInfo.InstalledUICulture,
DateTimeStyles.None,
out dtObject))
{
//valid date
}
For multiple formats, you can specify the formats in a string array and later you can use that. It returns a bool
value indicating if the parsing was successful or not.
Example from MSDN:
string[] formats= {"M/d/yyyy h:mm:ss tt", "M/d/yyyy h:mm tt",
"MM/dd/yyyy hh:mm:ss", "M/d/yyyy h:mm:ss",
"M/d/yyyy hh:mm tt", "M/d/yyyy hh tt",
"M/d/yyyy h:mm", "M/d/yyyy h:mm",
"MM/dd/yyyy hh:mm", "M/dd/yyyy hh:mm"};
string[] dateStrings = {"5/1/2009 6:32 PM", "05/01/2009 6:32:05 PM",
"5/1/2009 6:32:00", "05/01/2009 06:32",
"05/01/2009 06:32:00 PM", "05/01/2009 06:32:00"};
DateTime dateValue;
foreach (string dateString in dateStrings)
{
if (DateTime.TryParseExact(dateString, formats,
new CultureInfo("en-US"),
DateTimeStyles.None,
out dateValue))
Console.WriteLine("Converted '{0}' to {1}.", dateString, dateValue);
else
Console.WriteLine("Unable to convert '{0}' to a date.", dateString);
This is a very old question, however for anyone still looking into complex natural language date parsing I'd recommend using nChronic, a .NET port of the amazing (ruby based) chronic date parser.
The source for it is here: nChronic Github
It's also in Nuget as Chronic: Chronic in Nuget
Some very simple example code using this library would be like such:
using Chronic;
var parser = new Chronic.Parser ();
Span ParseObj;
DateTime ParsedDateTime;
ParseObj = parser.Parse ("January 11th");
ParsedDateTime = ParseObj.Start;
Here are some examples of what it can handle:
Simple
- thursday
- november
- summer
- friday
- 13:00
- mon 2:35
- 4pm
- 10 to 8
- 10 past 2
- half past 2
- 6 in the morning
- friday 1pm
- sat 7 in the evening
- yesterday
- today
- tomorrow
- last week
- next week
- this tuesday
- next month
- last winter
- this morning
- last night
- this second
- yesterday at 4:00
- last friday at 20:00
- last week tuesday
- tomorrow at 6:45pm
- afternoon
- yesterday
- thursday last week
Complex
- 3 years ago
- a year ago
- 5 months before now
- 7 hours ago
- 7 days from now
- 1 week hence
- in 3 hours
- 1 year ago tomorrow
- 3 months ago saturday at 5:00 pm
- 7 hours before tomorrow at noon
- 3rd wednesday in november
- 3rd month next year
- 3rd thursday this september
- 4th day last week
- fourteenth of june 2010 at eleven o'clock in the evening
- may seventh '97 at three in the morning
Specific Dates
- January 5
- 22nd of june
- 5th may 2017
- February twenty first
- dec 25
- may 27th
- October 2006
- oct 06
- jan 3 2010
- february 14, 2004
- february 14th, 2004
- 3 jan 2000
- 17 april 85
- 5/27/1979
- 27/5/1979
- 05/06
- 1979-05-27
- Friday
- 5
- 4:00
- 17:00
- 0800
Specific Times (many of the above with an added time)
- January 5 at 7pm
- 22nd of june at 8am
- 1979-05-27 05:00:00
- 03/01/2012 07:25:09.234567
etc
I had similar problem here's better way
stringdate="August 19th 2000"
string pattern = @"\b(\d+)(?:st|nd|rd|th)\b";
Regex rgx = new Regex(pattern);
DateTime.Parse(String.Format("{0:MMMM, d, yyyy}", rgx.Replace(stringdate, "$1"))
**result** {19/08/2000 00:00:00} System.DateTime
From Microsoft and regex to remove ordinals and How can I visualize the way various DateTime formats will display?
EDIT
If the year is not specified:
stringdate= rgx.Replace(stringdate, "$1");
DateTime datetime;
if (!DateTime.TryParseExact(stringdate, "MMMM dd yyyy", System.Globalization.DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.None, out datetime))
{
// assuming no gap exist
datetime = DateTime.Parse(stringdate += " "+DateTime.Now.Year);
}
Now if the input string text is "June 11th"
, it will be 11/6/2021
.
There are More functions and ways to handle dates at DateTime Documentation.
If you dont want the year at all, then you can add the following line:
datetime.ToString("MM/dd");
Now the output will be "11/6"