DateTime to RFC-1123 gives inaccurate timezone - c#

If I get the RFC-1123 formatted date of a DateTime object, it gives the current local time, but gives the timezone as GMT (which is inaccurate).
DateTime.Now.ToString("r");
returns
Fri, 12 Feb 2010 16:23:03 GMT
At 4:23 in the afternoon, but my timezone is UTC+10 (plus, we're currently observing daylight saving time).
Now, I can get a return value that's "correct" by converting to UTC first:
DateTime.UtcNow.ToString("r");
returns
Fri, 12 Feb 2010 05:23:03 GMT
However, ideally, I'd like to get the right timezone, which I guess would be
Fri, 12 Feb 2010 16:23:03 +1100
Passing in the current CultureInfo doesn't change anything. I could get a UTC offset with TimeZoneInfo.Local.GetUtcOffset(...) and format a timezone string from that, but stripping out the GMT bit and replacing it seems gratutiously messy.
Is there a way to force it to include the correct timezone?

The .NET implementation always expresses the result as if it were GMT, irrespective of the time offset of the actual date.
By using DateTime.Now.ToString("r"); you're essentially saying String.Format("ddd, dd MMM yyyy HH':'mm':'ss 'GMT'", DateTime.Now);, which is the .NET RFC1123 format string, as indicated on MSDN - The RFC1123 ("R", "r") Format Specifier.
To get the behaviour you require, you should probably use String.Format, and replace the fixed 'GMT' section of the specifier with a time offset specifier:
The "z" Custom Format Specifier
The "zz" Custom Format Specifier
The "zzz" Custom Format Specifier

You could just do DateTime.UtcNow.ToString ("R"), you will still get GMT timezone but the time is correctly offset then.

Related

Bug in .NET's DateTime.ToString("R") with UTC dates?

I'm based in the UK (GMT+1 time at the moment).
If I run this:
> DateTime.UtcNow.ToString("R") // Or...
> DateTime.Now.ToUniversalTime().ToString("R")
"Mon, 06 Oct 2014 10:20:00 GMT"
Correct answer.
If I now run the same, without UTC DateTime conversion:
> DateTime.Now.ToString("R")
"Mon, 06 Oct 2014 11:20:00 GMT"
The time printed is correct, but the timezone is wrong. I would expect instead:
"Mon, 06 Oct 2014 11:20:00" // Or..
"Mon, 06 Oct 2014 11:20:00 BST"
Question: Is this behaviour by design? Can I get the same output as with the "R" format, but with the correct timezone indicator?
It's definitely not a bug, it's the documented behaviour:
The custom format string is "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'". When this standard format specifier is used, the formatting or parsing operation always uses the invariant culture.
...
Although the RFC 1123 standard expresses a time as Coordinated Universal Time (UTC), the formatting operation does not modify the value of the DateTime object that is being formatted. Therefore, you must convert the DateTime value to UTC by calling the DateTime.ToUniversalTime method before you perform the formatting operation. In contrast, DateTimeOffset values perform this conversion automatically; there is no need to call the DateTimeOffset.ToUniversalTime method before the formatting operation.
As I noted in a comment on the question, 10:20 GMT is correct, assuming that you ran the code shortly before asking the question: 11:20 GMT has not occurred yet.
So basically, when you follow the guidance in the documentation and call ToUniversalTime, it does the right thing. When you don't, it gives a misleading value - that's unfortunate, but part of the broken design of DateTime IMO.
You should consider at least using DateTimeOffset, or potentially using my Noda Time project instead.

Troubles parsing DateTime from string

I am currently trying to parse a string that is obtained from an xml that is downloaded from the web every few minutes. The string looks like this:
Thu Jul 12 08:39:56 GMT+0100 2012
At first I just did a string.split and took out everything after the time (GMT+0100 2012) and inserted 2012 after the date.
This worked great until the date changed to:
Thu Jul 12 08:39:56 GMT+0000 2012
So I would like to dynamically pasre the GMT+ whatever as they send me that string in c#.
Any advice would be appreciated.
You can use DateTime.ParseExact with a custom date and time format string:
DateTime.ParseExact("Thu Jul 12 08:39:56 GMT+0000 2012",
"ddd MMM dd hh:mm:ss 'GMT'K yyyy",
CultureInfo.InvariantCulture)
This will throw a format exception if the string and format string do not match exactly, so you may want to use DateTime.TryParseExact that will return a false if it fails.
Instead of DateTime you may want to use DateTimeOffset that preserved timezone information , as #Keith commented - this may be important to your application.
Two things you can do: First, you should be able to use a custom format string with a ParseExact method, either from DateTime or DateTimeOffset (I would use DateTimeOffset if the actual time zone of the stamp is important, and not just the equivalent time in UTC or your local time zone).
Have a look: DateTime custom format string
The format string would probably be something like #"ddd MMM dd HH:mm:ss 'GMT'zzzz yyyy".
However, there's one snag; the .NET time zone offset ("zzzz" or simply "K") always includes a colon between the hour and minute when expressed as a string, which your input strings do not have. There is no way I know of to specify that the time zone offset doesn't/shouldn't have this colon, and I'm pretty sure that trying to parse it without a colon would cause an error.
The simplest workaround is to remove that specific colon from the string prior to parsing it. The code for that given your input is simply to remove the last colon character in the string:
var updatedString = inputString.Remove(inputString.LastIndexOf(':'), 1);
Try DateTime.Parse method to parse your date.
This should work:
XmlConvert.ToDateTime(textBox1.Text, "ddd MMM dd HH:mm:ss 'GMT'zzzz yyyy");

Twitter time to local time c#

How do i convert the time of tweets made by the user to localtime? The created_at gives me the time of the tweet created and is based on the user's country, how to i change it to my localtime using c#. The format of the time is "Fri Jul 27 15:14:11 +0000 2012". What do they mean by utc_offset and how can it be used to change the timezone?
I am not really familiar with the timezone stuff, thank you for your help :)
You'll want to use the DateTimeOffset structure. This allows you to capture a date and a time as well as offset from UTC as well.
The format that you want to use for Twitter times is:
string twitterDate = "Fri Jul 27 15:14:11 +0000 2012";
DateTimeOffset dt = DateTimeOffset.ParseExact(twitterDate,
"ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture);
Note that while not documented, zzzz does work as a custom date time format and succeeds in parsing the offset correctly. This means you should be careful in relying on it in the future (unless the documentation changes to reflect this functionality).
Once you have the DateTimeOffset, you know the offset from UTC. If you want to get it in your local time, you can call the ToLocalTime method on the DateTimeOffset that was parsed and it will return an instance that has an offset based on your local settings.
This should be it:
DateTime localDateTime = DateTime.ParseExact(dateString, "ddd MMM dd HH:mm:ss zzz yyyy", new CultureInfo("en-US"));
Unless you give a DateTimeKind in the constructor of a DateTime, the DateTime will be in the timezone the administrator of the workstation/server has selected for Windows.

Need help with C# ParseExact syntax and moving between timezones

Okay, I have decided to let the magic of Stackoverflow work for me!
I have a date in the format: "Apr 18 2011 19:30 EDT" that I need to push into a DateTime object in C#. One caviat, I also want to shift it to UTC too. Obivisouly when DST is over it'll come over as EST.
I know that I need a statement like:
DateTime.ParseExact("Apr 18 2011 19:30 EDT", "MMM DD yyyy something something ", CultureInfo.InvariantCulture, DateTimeStyles.None, out convertedDate);
But getting it over to UTC is above my knowlwedge level.
So in summary, I need:
To turn Apr 18 2011 19:30 EDT into a DateTime
Convert the EDT timezone to UTC time.
End up with a DateTime object.
What's the code, wizards?
Well, if it's always going to be in Eastern Daylight Time, you can do something like:
// Parse string. We don't need escaping since E,D and T
// are not considered special characters by ParseExact.
var dateTimeInEasternTime = DateTime.ParseExact("Apr 18 2011 19:30 EDT",
"MMM dd yyyy HH:mm EDT",
CultureInfo.InvariantCulture);
// Convert from the relevant timezone to UTC.
var dateTimeInUTC = TimeZoneInfo.ConvertTime
(dateTimeInEasternTime,
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"),
TimeZoneInfo.Utc);
You can cache the TimeZoneInfo representing EST (which becomes EDT while daylight savings is on) to prevent the lookup.
If the string could end with a three letter code representing some arbitrary time-zone, it's going to be a lot more difficult since there are many conventions for them, none of which (AFAIK) are currently supported by .NET. Your best bet would be to first build a lookup from the code to the relevant TimeZoneInfo (perhaps through the Id property) after which you can do the conversion with TimeZoneInfo.ConvertTime as usual.
I'm not sure exactly where you're getting hung up. It sounds like you have successfully parsed the string into a DateTime.
To convert the value to UTC, call the ToUniversalTime() method. Note that this will assume the current time value is relative to your system's current time zone.
ToUniversalTime() converts to a DateTime value.

Getting exception when using DateTime.Parse method

So, i have this string "Date: Mon Jan 03 2011 19:29:44 GMT+0200", and when i use DateTime.Parse(date).ToString(); i'm getting "String was not recognized as a valid DateTime."
If i remove the '+0200' part it works ok, but ofcourse it doesn't show the correct local time.
What's wrong with that?
From the documentation, it seems that DateTime.Parse() only understands:
The GMT designator, used alone, e.g. Mon, Jan 03 2011 17:29:44 GMT, or
A time zone offset specified without the GMT designator, e.g. Mon, Jan 03 2011 19:29:44+02:00.
You might want to convert your date string to the second form.
It just means that the time zone offset isn't an expected part of the default format strings.
If you know what format you're expecting, I suggest you call DateTime.ParseExact (or DateTime.TryParseExact), specifying the format(s) to try. Look at the documentation for custom date/time format strings for more details.
You have two mistakes.
First - don`t use Parse method. More correct is TryParse.
Second - you will have globalisation issues, when you use Parse or TryParse without arguments.
For example, see this code:
DateTime.Parse( "01.02.2011" ); In the USA it is 2nd of January. In the Germany it is 1st of February.
So, I recomment you to use formats from this article.

Categories

Resources