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
Related
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);
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();
Good morning,
I have problem with format of datetime which comes in format "Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)".
var value = "Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)";
DateTime.Parse(value) throws CastException.
I have also tried use ParseExact method which is more powerfull but still without access
var date = DateTime.ParseExact(
"Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)",
"ddd MMM dd yyyy HH:mm:ss 'GMT+0000 (Central Europe Daylight Time)'",
CultureInfo.InvariantCulture);
var date = DateTime.ParseExact(
"Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)",
"ddd MMM dd yyyy HH:mm:ss 'GMT+0000 (GMT Standard Time)'",
CultureInfo.InvariantCulture);
Everything fails ...
I also wanted try hack and make a SubString(4,11) but IE returns diferent format than chrome so it's not usable ...
I am sending it from kendo filter in grid.
So my questions are:
1) Is there way how to parse this format vith C#?
2) Is there way how to say to Kendo filter "send another format"? Format and ParseFormats ignores me ...
My expected format in which I want format is dd.MM.yyyy ..
Thank you for help
Edit:
My kendo code looks like:
.....
{
field: "DateField",
type: "date",
width: "110px",
template: function (e) {
return $.format.date(e.DateField, "dd.MM.yyyy");
},
filterable: {
extra: true,
operators: {
date: {
gt: "Is greater than",
lt: "Is less than"
}
},
ui: function (element) {
element.kendoDatePicker({
format: "dd.MM.yyyy"
});
}
}
},
With ParseExact():
using System.Globalization;
var value = "Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)";
var trimedValue = value.Substring(0, value.IndexOf(" ("));
var dateTime = DateTime.ParseExact(trimedValue, "ddd MMM dd yyyy HH:mm:ss 'GMT'zzz", CultureInfo.InvariantCulture);
Your DateTime.Parse code fails because your CurrentCulture doesn't have a standard date and time format for that string. None of culture can have this kind of format. A DateTime timezone awareness by the way.
Your ParseExact examples fails because; first one has +0200 for offset but your string has +0000. This remains for second one and also your timezones are different. (Central Europe Daylight Time and GMT Standard Time)
Since you have UTC offset part in your string, I would choose DateTimeOffset parsing with "K" format specifier instead like;
string s = "Mon Jun 15 2015 00:00:00 GMT+0200 (Central Europe Daylight Time)";
DateTimeOffset dto;
if (DateTimeOffset.TryParseExact(s, "ddd MMM dd yyyy HH:mm:ss 'GMT'K '(Central Europe Daylight Time)'",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal, out dto))
{
Console.WriteLine(dto);
}
Now you have a DateTimeOffset as {15.06.2015 00:00:00 +02:00} and I think this might be the best thing you can get.
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.
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