C# datetime parse issue - c#

When trying to convert date/time from string to DateTime, I'm not getting the correct value.
DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
And my result is 2012-08-09 8:51:14 PM. Why is it being offset? I just want it to be the same value going in.

You are parsing the UTC date but the DateTime.Kind is local.
You should parse with DateTimeStyles.AdjustToUniversal to mark the Kind as Utc.
DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
Trace.WriteLine(testDate); // 8/9/2012 8:51:14 PM
Trace.WriteLine(testDate.ToString()); // 8/9/2012 8:51:14 PM
Trace.WriteLine(testDate.ToUniversalTime()); // 8/10/2012 12:51:14 AM
Trace.WriteLine(testDate.Kind); // Local
testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
Trace.WriteLine(testDate);// 8/10/2012 12:51:14 AM
Trace.WriteLine(testDate.ToString());// 8/10/2012 12:51:14 AM
Trace.WriteLine(testDate.ToUniversalTime());// 8/10/2012 12:51:14 AM
Trace.WriteLine(testDate.Kind); // Utc

Aware this is an answer many years later, but came across this today and once I worked out my problem wanted to add some context I didn't see in other answers.
Going back to the OPs code snippet the reason it doesn't do what the OP expected of taking a UTC time string and storing it as a UTC DateTime is because the DateTimeStyles.AssumeUniversal only specifies that the input string is a UTC string. By default C# will create DateTime's as a DateTimeKind.Local. This was pointed out in another answer. This means the time is converted from UTC to Local time.
To make sure that your end result ends up being a UTC DateTime you need to use the DateTimeStyles of DateTimeStyles.AdjustToUniversal. This was also mentioned in other answers. However, if your input string doesn't have an obvious timezone then it may be assumed to be local and then converted from Local to UTC.
Luckily DateTimeStyles is actually a flag enum meaning we can use both the above options at the same time. E.g:
DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);

You should use DateTimeStyles.AdjustToUniversal. The input DateTime is already universal, and the AdjustToUniversal enum option will convert the input to local time though you will get a resultant Kind of DateTimeKind.Unspecified.

What is your server timezone, if you use AssumeUniversal it will convert your input time to UTC time.
You probably in EST then.

I propose simply that you want to use .AssumeLocal instead of .AssumeUniversal.
You have a time stamp with unknown time zone, and if you know that the time stamp refers to an event that happened in your local time zone, then you should tell the parse to assume that the time stamp is local to you (i.e. in your time zone).
By using .AssumeUniversal, you are instructing the parser to treat the time stamp as if it was a UTC time stamp, which when you display it using your local time zone, it's automatically offset by that amount.
Edit:
One important thing: The capital "Z" in the time stamp suggests it is a UTC time stamp, which means you do want to treat it as Universal. If you want to treat it as a local time stamp, you should remove the Z from the time stamp and the corresponding parse string.
Reference: http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx#KSpecifier

Related

Issue with datetime parsing

When I tried to parse the "2017-09-25T11:06:55+00:00" date string using TryParse method, I get the following output:
{9/25/2017 7:06:55 AM}
So, it's looks like 11 a.m. is getting converted into 7 a.m. Not sure why is this happening this? Is it because of +00:00??
What do I need to do so that parsed Datetime output is same: i.e. {9/25/2017 11:06:55 AM} ?
I tried using Current locale/culture and DateTime Styles. Assume Local but no luck.
(Note: I'm in the eastern time-zone)
Thanks.
You are using the UTC timezone (+00:00), but apparently, you or your PC is in -04:00 timezone.
If you can use DateTimeOffset, then I tend to prefer it. You get time zone info preserved, and you have access to both local and UTC datetime properties off this object.
var dt = DateTimeOffset.Parse("2017-09-25T11:06:55+00:00");
Console.WriteLine(dt.DateTime); // 9-25 at 11:06
Console.WriteLine(dt.UtcDateTime); // 9-25 at 11:06
Console.WriteLine(dt.LocalDateTime); // 9-25 at 07:06
If you know you're always going to be dealing with UTC, you can just parse by adjusting to universal like so:
var dt = DateTime.Parse("2017-09-25T11:06:55+00:00", CultureInfo.CurrentCulture, DateTimeStyles.AdjustToUniversal);
Console.WriteLine(dt); // 9-25 at 11:06
When you parse it initially it's the correct value, it's just now adjusted to be in your timezone. You can force it with ToUniversalTime :
DateTime.Parse("2017-09-25T11:06:55+00:00").ToUniversalTime().ToString("yyyy/MM/dd HH:mm:ss tt")
output
"2017/09/25 11:06:55 AM"
You want to parse correctly UTC DateTime and to have 9/25/2017 11:06:55 AM instead of 9/25/2017 7:06:55 AM. +00:00 is not correct UTC format, you need to change it to "2017-09-25T11:06:55z".
Here is working example

DateTime.ToString() not converting time

Looks like time is automatically getting changed during conversion.
My input is 17:15:25. However, it gets converted to 13:15:25
What could be the reason?
string testDate = Convert.ToDateTime("2016-03-24T17:15:25.879Z")
.ToString("dd-MMM-yyyy HH:mm:ss", CultureInfo.InvariantCulture);
The result I get for testDate is : 24-Mar-2016 13:15:25
The Z in your input indicates a UTC time, but the default behaviour of Convert.ToDateTime is to convert the result to your local time. If you look at the result of Convert.ToDateTime("2016-03-30T17:15:25.879Z").Kind you'll see it's Local.
I would suggest using DateTime.ParseExact, where you can specify the exact behaviour you want, e.g. preserving the UTC time:
var dateTime = DateTime.ParseExact(
"2016-03-30T17:15:25.879Z",
"yyyy-MM-dd'T'HH:mm:ss.FFF'Z'",
CultureInfo.InvariantCulture,
DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
Console.WriteLine(dateTime); // March 30 2016 17:15 (...)
Console.WriteLine(dateTime.Kind); // Utc
You can then convert that value to a string however you want to.
Of course I'd really suggest using my Noda Time project instead, where you'd parse to either an Instant or a ZonedDateTime which would know it's in UTC... IMO, DateTime is simply broken, precisely due to the kind of problems you've been seeing.
When you use Convert.ToDateTime (which uses DateTime.Parse internally) with Z (which means Zulu time), this method adds your current time zone offset to that DateTime value.
Looks like your current time zone is UTC -04:00 right now and that's why method returns 4 hours back as a result.
I would suggest to use DateTime.ParseExact with AdjustToUniversal and AssumeUniversal styles for prevent Kind conversion as Jon answered.
From AdjustToUniversal
Date and time are returned as a Coordinated Universal Time (UTC). If
the input string denotes a local time, through a time zone specifier
or AssumeLocal, the date and time are converted from the local time to
UTC. If the input string denotes a UTC time, through a time zone
specifier or AssumeUniversal, no conversion occurs. If the input
string does not denote a local or UTC time, no conversion occurs and
the resulting Kind property is Unspecified.
Because of the CultureInfo.InvariantCulture.
You are converting a date in your GMT
Convert.ToDateTime("2016-03-24T17:15:25.879Z")
And then you are converting it to string in an invariant culture
ToString("dd-MMM-yyyy HH:mm:ss",CultureInfo.InvariantCulture);
You should use DateTime.ParseExact, and then use the invariant culture in the conversion.

Parse Date Time from US Time zone to Datetime.

How to parse below date time string?
2014-01-17T09:59:24.000Z
I tried below code but its, not working.
DateTime.ParseExact("2014-01-17T09:59:24.000Z", "ddd MMM dd HH:mm:ss %zzzz yyyy", CultureInfo.InvariantCulture);
With a string like "2014-01-17T09:59:24.000Z"
You can just use DateTime.Parse("2014-01-17T09:59:24.000Z")
From The Documentation:
The string to be parsed can take any of the following forms:
A string that includes time zone information and conforms to ISO 8601. In the following examples, the first string designates Coordinated Universal Time (UTC), and the second string designates the time in a time zone that's seven hours earlier than UTC:
2008-11-01T19:35:00.0000000Z
2008-11-01T19:35:00.0000000-07:00
From DateTime.ParseExact
Converts the specified string representation of a date and time to its
DateTime equivalent using the specified format and culture-specific
format information. The format of the string representation must match
the specified format exactly.
Clearly your string representation and format is not the same.
You can use it like;
var date = DateTime.ParseExact("2014-01-17T09:59:24.000Z",
"yyyy-MM-dd'T'HH:mm:ss.fff'Z'",
CultureInfo.InvariantCulture);
Console.WriteLine(date);
Output will be;
1/17/2014 9:59:24 AM
Here a demonstration.
For more information, take a look at;
Custom Date and Time Format Strings
The value you have, 2014-01-17T09:59:24.000Z is an ISO8601/RFC3339 formatted timestamp. The Z at the end is significant, which means that it represents UTC.
You have two options to correctly parse it:
You could parse it to a DateTime that has DateTimeKind.Utc for it's .Kind property:
DateTime dt = DateTime.ParseExact("2014-01-17T09:59:24.000Z",
"yyyy-MM-dd'T'HH:mm:ss.fffK",
CultureInfo.InvariantCulture,
DateTimeStyles.RoundtripKind);
Or, you could parse it to a DateTimeOffset, where UTC will correspond to an offset of zero:
DateTimeOffset dt = DateTimeOffset.ParseExact("2014-01-17T09:59:24.000Z",
"yyyy-MM-dd'T'HH:mm:ss.fffK",
CultureInfo.InvariantCulture);
Some of the other answers here are close, but are forgetting to actually consider the Z in your string, using the K specifier and the DateTimeStyles.RoundtripKind parameter. These are important, for without them you will likely end up with a resulting DateTime that has DateTimeKind.Unspecified, which could get treated as local time in certain time zone conversion functions. If you use either of the options I gave you, then the meaning of the Z is preserved.

How can I parse this DateTime without losing TZ info?

I have a bunch of strings that are DateTime values dumped from some database... Probably MySql. I have no control on the structure.
The strings look like this:
2011-05-17 00:00:00 Etc/GMT
I've found solutions that involve replacing "Etc/GMT" prior to the parse. This smells bad.
Is there a one step solution to turning this string to a DateTime without stripping out the timezone info?
DateTime.ParseExact
Converts the specified string representation of a date and time to its DateTime equivalent using the specified format and culture-specific format information. The format of the string representation must match the specified format exactly.
For funky formats you can use ParseExact. And you also probably want to use DateTimeStyles.AssumeUniversal:
String original = "2011-05-17 00:00:00 Etc/GMT";
DateTime result = DateTime.ParseExact(
original,
"yyyy-MM-dd HH:mm:ss 'Etc/GMT'",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeUniversal);
Console.WriteLine(result.ToString()); // given my timezone: 5/16/2011 8:00:00 PM
Console.WriteLine(result.ToUniversalTime().ToString()); // 5/17/2011 12:00:00 AM
It appears that Noda Time contains Etc/GMT in its time zone database based on a quick look at the source.
The means by which you parse dates and times is a bit different in Noda Time than in the .Net Framework (I'm by no means an expert in Noda Time):
var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
#"yyyy'-'MM'-'dd HH':'mm':'ss z",
DateTimeZoneProviders.Tzdb);
var result = pattern.Parse(#"2011-05-17 00:00:00 Etc/GMT");
if (result.Success)
{
Console.WriteLine("{0}", result.Value);
}
"Etc/GMT" is a tz aka Olson time zone specifier. These are used pretty much everywhere but Windows, as Microsoft has their own.
So, there's nothing in .NET that will help you. You'll have to go elsewhere. As user7116 mentions, Noda Time supports tz time zones and Microsoft time zones. It's an excellent library.
Annoyingly, .NET actually does not have a DateTime type with a time zone attached. It can attach an offset, which is not quite the same (a time zone can have multiple offsets depending on DST). Noda Time does support this and will be able to preserve the statement exactly.

Why does DateTime.ToString not give timezone as expected

If I have this code:
DateTime dt = DateTime.UtcNow;
string sDate = dt.ToString("yyyy-MM-dd HH:mm:ss.fff zz");
my sDate looks like this:
"2013-04-07 21:05:15.396 +10"
which is the current UTC datetime (9:05pm), but with a "+10" on the end which is my local timezone.
I would have expected this:
"2013-04-07 21:05:15.396 +00"
what's going on?
That's because the documentation says (emphasis mine):
With DateTime values, the "zz" custom format specifier represents the
signed offset of the local operating system's time zone from UTC,
measured in hours. It does not reflect the value of an instance's
DateTimeKind property. For this reason, the "zz" format specifier is
not recommended for use with DateTime values.
So, the zz format specifier always outputs the UTC offset of your local timezone, even when used to format UTC times.
DateTime.ToString, when you don't pass a CultureInfo into it, defaults to the current culture. If your current culture is +10, then that explains why you see +10. There's various FxCop and Code Analysis rules you can turn on to warn you when you call ToString without a CultureInfo

Categories