looking at the format : "MMM d yyyy"
This is working
var t="Mar 2013 7";
DateTime dt=DateTime.Parse(t);
But
also this :"Mar 7 2013"
and this :"7 Mar 2013"
is working
looking at :
new DateTimeFormatInfo()
.GetAllDateTimePatterns()
.Select((i,n)=>n+" "+i)
.ToList()
.ForEach(f=>Console.WriteLine(f));
Which is All the standard patterns in which date and time values can be
formatted.
The result is :
0 MM/dd/yyyy
1 yyyy-MM-dd
2 dddd, dd MMMM yyyy
3 dddd, dd MMMM yyyy HH:mm
4 dddd, dd MMMM yyyy hh:mm tt
5 dddd, dd MMMM yyyy H:mm
6 dddd, dd MMMM yyyy h:mm tt
7 dddd, dd MMMM yyyy HH:mm:ss
8 MM/dd/yyyy HH:mm
9 MM/dd/yyyy hh:mm tt
10 MM/dd/yyyy H:mm
11 MM/dd/yyyy h:mm tt
12 yyyy-MM-dd HH:mm
13 yyyy-MM-dd hh:mm tt
14 yyyy-MM-dd H:mm
15 yyyy-MM-dd h:mm tt
16 MM/dd/yyyy HH:mm:ss
17 yyyy-MM-dd HH:mm:ss
18 MMMM dd
19 MMMM dd
20 yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK
21 yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK
22 ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
23 ddd, dd MMM yyyy HH':'mm':'ss 'GMT'
24 yyyy'-'MM'-'dd'T'HH':'mm':'ss
25 HH:mm
26 hh:mm tt
27 H:mm
28 h:mm tt
29 HH:mm:ss
30 yyyy'-'MM'-'dd HH':'mm':'ss'Z'
31 dddd, dd MMMM yyyy HH:mm:ss
32 yyyy MMMM
33 yyyy MMMM
Question :
I dont see in the list the MMM d yyyy format. So how does it do it ? does it try all combinations ?
What about adding a time to format MMM d yyyy ? [Mar 3 2007 13:13:13] it also works but there is no specific format . so how does it do it?
I've used Reflector to look at this. It's really complicated with hundreds of lines of parsing code!
However, ultimately it winds up tokenising the input string and trying to categorise the tokens as day names, month names, years, day numbers etc.
In particular a function called internal TokenHashValue[] CreateTokenHashTable() has this sort of thing:
for (int i = 1; i <= 12; i++)
{
this.InsertHash(dtfiTokenHash, this.GetAbbreviatedMonthName(i), TokenType.MonthToken, i);
}
It uses this (which as you can see has all the abbreviated month names) to determine if a token is a month name. There's similar code for day names.
The parsing code also checks whether one of the numbers is greater than 2 digits long. If it is, it assumes it's a year. This means (and you can verify it) that you can have a 3 digit year and it will still parse it ok. But it gets even more complicated! It also checks if the number is greater than 12, and assumes it's a year if so.
If you put two numbers each less than or equal to 12, it still works, but it assumes the first one is a day and the second a month (for the UK culture - I bet it's different for other cultures).
This does of course allow it to parse ambiguous dates without warning.
Upshot is: NEVER PARSE A DATE LIKE THIS
Always ParseExact().
I'd guess that it is using the format specifiers and not their arrangement.
From the way the literal "Mar 2013 7" is written, i doubt they can be any ambiguity in its parsing.
Mar matches MMM exactly
2003 matches yyyy exactly
7 matches d exactly
I found a link to DateTime.Parse source code here:
http://typedescriptor.net/name/members/5B57671F27DBC0AEA0EB9825243834CF-System.DateTime.Parse(String,IFormatProvider,DateTimeStyles)
You can click the links to dig deeper into the private methods, but it gets complicated. But it looks like it does lexing and parsing much like a compiler. The string is broken up into parts (tokens) and it tries to identify if each is a year, a month, whatever.
Certainly there might be some ambiguity, e.g. maybe you meant dd-MM-yyyy but it parsed as MM-dd-yyyy. But that's why you can specify a culture-specific IFormatProvider.
Related
I have an example date / time string that I need to convert to datetimeoffset.
There is one huge inconsistency - if the day of the month < 10 then there is a double space between Month and Day, otherwise just a single space.
For example: 'Tue Dec 4 22:39:38 UTC 2018' and 'Tue Dec 14 22:39:38 UTC 2018'
I currently parse it using DateTimeOffset.ParseExact(dateTime, "ddd MMM dd HH:mm:ss UTC yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) which fails for dates where the day is < 10 with the error:
FormatException: String 'Tue Dec 4 22:52:42 UTC 2018' was not recognized as a valid DateTime.
I know I can search and replace double space character with a single space, but is there a more elegant way to achieve this using the format string?
This question seemed to have a few comments (including my own erroneous one about using AllowLeadingWhite (I had meant AllowInnerWhite).
However, just using AllowInnerWhite with the existing format string still produces an error:
Console.WriteLine(DateTimeOffset.ParseExact("Tue Dec 4 22:39:38 UTC 2018", "ddd MMM dd HH:mm:ss UTC yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowInnerWhite));
Produces:
FormatException: String was not recognized as a valid DateTime.
However, looking at this from a different angle, why not change the date format itself to permit single-digit dates. Use "ddd MMM d HH:mm:ss UTC yyyy" (with a single 'd' for the actual date instead of 'dd'):
Console.WriteLine(DateTimeOffset.ParseExact("Tue Dec 4 22:39:38 UTC 2018", "ddd MMM d HH:mm:ss UTC yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowInnerWhite));
Console.WriteLine(DateTimeOffset.ParseExact("Tue Dec 11 22:39:38 UTC 2018", "ddd MMM d HH:mm:ss UTC yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowInnerWhite));
Console.WriteLine(DateTimeOffset.ParseExact("Fri Dec 14 22:39:38 UTC 2018", "ddd MMM d HH:mm:ss UTC yyyy", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AllowInnerWhite));
Note that your example data of 'Tue Dec 14 22:39:38 UTC 2018' will fail because Dec 14th 2018 is a Friday, not a Tuesday.
That's what the DateTimeStyles.Allow* flags are for: They instruct the parser to ignore whitespaces in the date string.
In your case the string starts with the abbreviated weekday name, so the flag minimally sufficient to ignore the additional space in case of a one-digit day number is
DateTimeStyles.AllowInnerWhite
This and related flags are documented here: https://learn.microsoft.com/en-us/dotnet/api/system.globalization.datetimestyles?view=netframework-4.7.2
I'm trying to parse DateTime data from podcast XML.
Basically, it comprises http header format.
(Format-A) Fri, 28 Aug 2015 00:00:00 EST
But, sometimes it has the different format with 4 digit days and month like below.
(Format-B) Thur, 30 July 2015 00:00:00 EST
I don't know why the Podcast provides 2 different formats at the same time.
I thought I could simply parse this format as this website mentioned.
https://www.dotnetperls.com/datetime-parse
But it didn't work with just DateTime.Parse() method
So I wrote this code.
try
{
dtPubDate = DateTime.ParseExact(strhttpTime,
"ddd, dd MMM yyyy HH:mm:ss 'EST'",
CultureInfo.InvariantCulture.DateTimeFormat,
DateTimeStyles.AssumeUniversal);
}
catch (FormatException)
{
dtPubDate = DateTime.ParseExact(strhttpTime,
"dddd, dd MMMM yyyy HH:mm:ss 'EST'",
CultureInfo.InvariantCulture.DateTimeFormat,
DateTimeStyles.AssumeUniversal);
}
As I wrote this code, if the first format doesn't work, try the second one.
But it still got the exception with Format-B.
This URL is what am having the problem with.
http://www.thebreathingmusic.com/podcast/podcast.xml
As you can see, there are 2 different formats with pubDate tag.
What am I missing?
The format string dddd will match against the entire day name, e.g. "Thursday", not 4 characters.
From the docs:
The "dddd" custom format specifier (plus any number of additional "d" specifiers) represents the full name of the day of the week. The localized name of the day of the week is retrieved from the DateTimeFormatInfo.DayNames property of the current or specified culture.
You could just trim everything before the comma and parse that instead.
var tidyDate = strhttpTime.Split(',')[1].Trim();
dtPubDate = DateTime.ParseExact(
tidyDate,
"ddd, dd MMM yyyy HH:mm:ss 'EST'",
CultureInfo.InvariantCulture.DateTimeFormat,
DateTimeStyles.AssumeUniversal);
var d=DateTime.Parse("03-02-2013");
Console.Write(d.Month); //2
1) How does Dateime.parse knows that :
- is the separator ? the - is not a standard separator (http://msdn.microsoft.com/en-us/library/az4se3k1.aspx)
2)How does it knows that the month is 2 and not 3 ? is it by the regional settings ? ( I changed my regional settings and it wasn't changed)... I try to find a reference with MSDN but couldn't find any.
This is my DateTimeFormatInfo.CurrentInfo data :
DateTime.Parse as opposed to DateTime.ParseExact tries to do a best effort to parse your date. This means that it allows a number of different date separators including /, -, . and (space). However, the sequence of the components of the date is still inferred from DateTimeFormatInfo.CurrentInfo which in your case dd/MM/yyyy meaning that the day comes before the month.
So with your Hebrew culture DateTime.Parse("03-02-2013") return February 3 2013 while calling DateTime.Parse("03-02-2013", CultureInfo.InvariantCulture) would return March 2 2013 because the invariant culture is based on the en-US culture which has the month before the day.
Exactly how DateTime.Parse behaves is a bit hard to figure out so the following information may not be entirely accurate. I believe that DateTime.Parse will try to look for various formats which may include D, d, y, T, t and also the pattern defined by DateTimeFormat.MonthDayPattern. Given a DateTimeFormatInfo you can get all the patterns using this code:
new[] { 'D', 'd', 'y', 'T', 't' }
.SelectMany(p => dateTimeFormatInfo.GetAllDateTimePatterns(p))
.Concat(new[] { dateTimeFormatInfo.MonthDayPattern })
For the Hebrew culture I get the following list:
dddd dd MMMM yyyy
dd MMMM yyyy
dddd dd 'ב'MMMM yyyy
ddd dd 'ב'MMMM yyyy
dd 'ב'MMMM yyyy
dd/MM/yyyy
dd MMMM yyyy
dd/MM/yy
dd/MMMM/yyyy
dd-MM-yy
dd-MM-yyyy
dd-MMMM-yyyy
yyyy-MM-dd
dd 'ב'MMMM yyyy
dd MMM yy
MMMM yyyy
HH:mm:ss
hh:mm:ss tt
HH:mm
hh:mm tt
dd MMMM
This list includes dd-MM-yyyy, but again, this list may not be entirely accurate.
DateTime.Parse based on the current culture. Here how it is impelement in .NET;
public static DateTime Parse(string s)
{
return DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None);
}
I think your current culture date seperetor is - that's why it is working.
From DateTimeFormatInfo.CurrentInfo
Gets a read-only DateTimeFormatInfo object that formats values based
on the current culture.
EDIT: Okey, I'm going to more deep in this subject. As I found on internet, DateTime.Parse supports a lot of formats. For example;
Standart Time "1/1/2000"
HTTP Header "Fri, 27 Feb 2009 03:11:21 GMT";
w3.org "2009/02/26 18:37:58";
nytimes "Thursday, February 26, 2009"
Standart Time "February 26, 2009";
ISO Standard 8601 for Dates "2002-02-10";
Windows file system Created/Modified "2/21/2009 10:35 PM";
Windows Date and Time panel "8:04:00 PM";
How does it knows that the month is 2 and not 3 ?
This is all about in your culture. With InvariantCulture it returns 3, in your culture it returns 2 because of standart date time format.
I need to format a date in RFC format for an RSS feed. I have tried taking my date and adding the following:
.ToString("ddd, dd mm yyyy HH:mm:ss zzz")
However it seems this is not valid. Any help would be great! The end result I need is, for example, Mon, 01 Jan 2013 GMT
Your question is a bit confusing because your example lacks any time (but has a time-zone).
Nevertheless, try using MMM for month:
.ToString("ddd, dd MMM yyyy HH:mm:ss zzz")
If you don't want time, simply omit that section from the string:
.ToString("ddd, dd MMM yyyy")
But since you mentioned you're generating a string for an RSS feed, you could just use the "R" format specifier to generate a RFC1123-format date / time string:
.ToString("R")
I am trying to parse date-strings to DateTime objects with the following format:
Tue, 30 Oct 2012 09:51:20 +0000
What I have tried so far is many different variants with DateTime.ParseExact().
I have tried:
DateTime.ParseExact("Mon, 29 Oct 2012 12:13:51 +0000",
"ddd, dd MM yyyy hh':'mm':'ss zzz",
CultureInfo.InvariantCulture);
With thousands different formats as second parameter, using null instead of InvarantCulture as third parameter etc etc. I can't get it to work. How should I parse a string like this?
Many thanks.
How about
var s = "Tue, 30 Oct 2012 09:51:20 +0000";
DateTime.ParseExact(s, "ddd, dd MMM yyyy hh:mm:ss zzz", CultureInfo.InvariantCulture)
The month (Oct) is actually MMM, not MM, and the time (09:51:20) should be hh:mm:ss instead of hh':'mm':'ss.
The correct parsing is
DateTime.ParseExact("Mon, 29 Oct 2012 12:13:51 +0000", "ddd, dd MMM yyyy HH:mm:ss K", CultureInfo.InvariantCulture);
Take a look here