How can I format a date in RFC format? - c#

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

Related

C# DateTime.Parse efficiently time with hour/min/sec/milis/micro/nano seconds

From third party I'm getting this string that I'd like to convert to DateTime:
"13 NOV 2018 16:08:52:000:000:000"
I've tried those options but FormatException thrown:
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:ffffff:fffffffff",
CultureInfo.InvariantCulture)
And the same exception when I've used this:
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff", CultureInfo.InvariantCulture)
Is there a clean way to parse it as is or, I need to use a dirty way such string.Split(new []{':'})?
Note:
For my business needs, I don't need the part of micro/nano seconds.
since this parsing operation occurs many times in a second, the efficiency is a key factor.
Update
I chose the #Tim's suggestion to do string manipulation:
string date = "12 NOV 2018 16:08:52:000:000:000";
date = date.Remove(date.Remove(date.LastIndexOf(':')).LastIndexOf(':'));
DateTime result = System.DateTime.ParseExact(date, "dd MMM yyyy HH:mm:ss:fff", System.Globalization.CultureInfo.InvariantCulture);
The reasons:
I can't promise the structure of the date string, since it comes from third party. So it will be very dangerous to use the format pattern dd MMM yyyy HH:mm:ss:fff:fff:fff
As #Jeroen Mostert wrote the usage of string splitting is not a key factor when you use DateTime.ParseExact()
Also, if you really think efficiency is so important, don't assume any single call to DateTime.ParseExact will be "fast", or that any string splitting you do will be a bottleneck.
Well, isn't it simply this?
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:fff:fff",
System.Globalization.CultureInfo.InvariantCulture)
This works if all groups of f have the same values, so for example all 0 or 123.
Tbh, i don't understand why you think that fff:ffffff:fffffffff matches 000:000:000
For my business needs, I don't need the part of micro/nano seconds.
You could make your second format working by cutting off the micro/nano part:
string date = "12 NOV 2018 16:08:52:000:000:000";
date = date.Remove(date.Remove(date.LastIndexOf(':')).LastIndexOf(':'));
DateTime result = System.DateTime.ParseExact(date, "dd MMM yyyy HH:mm:ss:fff", System.Globalization.CultureInfo.InvariantCulture);
Of course this assumes that there are always at least two colons. It's obvious that you need a try-catch to log invalid values and to continue with the next one.
Not an exact answer
System.DateTime.ParseExact("25 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:fff:fff", CultureInfo.InvariantCulture);
Things to consider: count of input string (000) should match with format(fff),
000 = fff good
00 = fff not good
000 = ff not good
You may need to manipulate input date string before trying to parse.
See this for more information regarding use of format specifier (fff)
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
.NET Fiddle:
https://dotnetfiddle.net/5UxCkd
I think that having same format for :fff is a key factor here
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000","dd MMM yyyy H:mm:ss:fff:fff:fff", CultureInfo.InvariantCulture) seems to work
https://dotnetfiddle.net/ZAtchu example code

Parsing Twitter Created At Date as UTC

I realize there are many threads about parsing twitter dates, but I am having a peculiar issue, and haven't been able to find any threads specific to this.
I am retrieving this post: https://twitter.com/bodegamcallen/status/1033757489567805440
which has a created date of 8/26/2018 at 9:46 AM Central Time.
The created date in the api is this: "Sun Aug 26 16:46:06 +0000 2018"
Which makes sense as 16:46pm (2:46pm) UTC is 9:46 AM Central (-500).
However, I'm parsing this using this code:
statusModel.DatePosted = DateTime.ParseExact(
this.created_at, "ddd MMM dd HH:mm:ss zzzz yyyy",
CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal);
and instead of getting the desired UTC time shown above, I'm getting this: 8/26/2018 4:46:06 PM
If I change the DateTimeStyle to None or AssumeLocal, I get this: 8/26/2018 11:46:06 AM
Neither of which is correct!
I've tried different formats from other threads like:
"ddd MMM dd HH:mm:ss K yyyy"
"ddd MMM dd HH:mm:ss Z yyyy"
"ddd MMM dd HH:mm:ss zzz yyyy"
"ddd MMM dd HH:mm:ss +ffff yyyy"
I also tried using DateTimeOffset.Parse and changing the culture to mine (en-us)
they all give me the same results.
What am I doing wrong? How do I get the datetime to be the same UTC time as the date value I'm getting from the API?
Aha! It turns out that my twitter account settings were configured to be in Pacific Time, rather than Central Time, and that would account for the two hour difference.
I changed my time zone settings for my account as described here: https://help.twitter.com/en/managing-your-account/how-to-change-time-zone-settings
And after changing to Central Time, the API data is coming in correct!
hope this helps someone else. Time zones, amirite?
A few things:
zzzz is not a valid specifier. Always check these docs if you're uncertain.
K is the only time zone specifier that is appropriate for DateTime parsing. The others (z, zz, and zzz) are for DateTimeOffset parsing.
When there is any offset or time zone information in the input string (even if it's +0000 or Z), DateTime.Parse and DateTime.ParseExact will assume by default that you want the output kind to be DateTimeKind.Local and that you want the value adjusted to local whatever it is in the input string. Examine the output .Kind if you're not certain if it's working correctly. If you want UTC instead, you should pass DateTimeStyles.AdjustToUniversal.
You don't need to pass DateTimeStyles.AssumeUniversal, because there is time zone information present in the input string.
It's not invalid, but you don't need to pass CultureInfo.InvariantCulture.DateTimeFormat. It's sufficient, and more common, to pass CultureInfo.InvariantCulture.
Putting this all together, your code should be:
statusModel.DatePosted = DateTime.ParseExact(
this.created_at, "ddd MMM dd HH:mm:ss K yyyy",
CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
And of course, you'd save some hassle and confusion if you changed your DatePosted to be a DateTimeOffset type instead. It's superior for this sort of scenario, and then you don't have to worry about DateTimeKind or DateTimeStyles.

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

Hyphens at DateTime.Parse?

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.

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