Hyphens at DateTime.Parse? - c#

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.

Related

Datetime format issue: how to convert datetime with 4 digit days or months

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);

Convert timezone specific datetime string to datetime in C#

How can I convert Tue, 01 Nov 2016 02:00 PM EET datetime string to DateTime in C#? What is a good practice to do it?
Use DateTime.TryParseExact with a format string that represents a generic datetime.
If you can have multiple formats then use the DateTime.TryParseExact overload that takes an array of formats.
You can find all the format strings here:
Custom Date and Time Format Strings
For example, "Tue" is represented by "ddd", "Nov" by "MMM" etc.
NOTE: The string formats are case sensitive so while "M" represents the month number, "m" represents the minute number. Getting them mixed up will cause the parse to fail.
By replacing timezone abbreviation with zone offset you can convert using DateTime.ParseExact
string date = "Tue, 01 Nov 2016 02:00 PM EET";
DateTime dt = DateTime.ParseExact(date.Replace("EET", "+2"), "ddd, dd MMM yyyy hh:mm tt z", CultureInfo.InvariantCulture);
and if you want more safer way by checking exception then you can using DateTime.TryParseExact method
Use DateTime.TryParseExact where the format string is built using this table.
Custom date and time formats does not recognize timezone abbrevations. You need to escape them as a string literal delimiter.
var dt = DateTime.ParseExact("Tue, 01 Nov 2016 02:00 PM EET",
"ddd, dd MMM yyyy hh:mm tt 'EET'",
CultureInfo.InvariantCulture);
dt.Dump();

How to parse default git date format in C#

How do you parse the default git format to a DateTime in C#?
As per What is the format for --date parameter of git commit
The default date format from git looks like Mon Jul 3 17:18:43 2006 +0200.
Right now I don't have control over the output, this strings comes from another tool that printed the date and I need to parse it.
I wouldn't parse this to DateTime, I would parse it to DateTimeOffset since it has a UTC offset value inside of it.
Why? Because if you parse it to DateTime, you will get a DateTime as Local and it might generate different results for different machines since they can have timezone offsets of that time.
For example, I'm in Istanbul and we use Eastern European Time which use UTC+02:00. If I run the example of your code with ParseExact method, I will get the 07/03/2006 18:18:43 as a Local time.
Why? Because in 3 July 2006, my timezone was in a daylight saving time which is UTC+03:00. That's why it generates 1 hour forwarded result. That's the part makes it ambiguous when you parse it to DateTime.
string s = "Mon Jul 3 17:18:43 2006 +0200";
DateTimeOffset dto;
if (DateTimeOffset.TryParseExact(s, "ddd MMM d HH:mm:ss yyyy K",
CultureInfo.InvariantCulture,
DateTimeStyles.None, out dto))
{
Console.WriteLine(dto);
}
Now, you have a DateTimeOffset as 07/03/2006 17:18:43 +02:00. You can still get the DateTime part with it's .DateTime property but it's Kind will be Unspecified in that case.
But of course, I suggest to use Noda Time instead which can solve most of the DateTime weirdness.
So far the best format string I found is ddd MMM d HH:mm:ss yyyy K.
DateTime date;
DateTime.TryParseExact(
gitDateString,
"ddd MMM d HH:mm:ss yyyy K",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out date
);

How can I format a date in RFC 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")

Datetime.Parse() swappable formats?

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.

Categories

Resources