I'm trying to convert a DateTime object to a ISO8601 string but keep getting wrong results. I've looked around on stackoverflow, but couldn't find the right solution.
I start with a date time string of "2017-06-26T20:45:00.070Z" which deserialized by newtonsoft from json and converted to a DateTime object in C# equivalent to :
var theTime = new DateTime(2017, 6, 26, 20, 45, 00, 70, DateTimeKind.Utc);
Now i need the convert that time back to it's original UTC format string to use it in another algorithm, but every conversion i try doesn't return it to that original string. Not sure what i'm doing wrong.
i've tried:
var newTime = theTime.UtcNow.ToString("o");
// returns "2017-06-26T00:00:00.0000000Z"
var newTime2 = theTime.Date.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.sssZ");
// returns "2017-06-26T00:00:00.00Z"
what am i doing wrong? I want the equivalent to what js will do using toISOString() which is what i have listed in the newTime2 date time format, but it's not showing times either.
thanks!
Observe:
// Your input
DateTime dt = new DateTime(2017, 6, 26, 20, 45, 0, 70, DateTimeKind.Utc);
// ISO8601 with 7 decimal places
string s1 = dt.ToString("o", CultureInfo.InvariantCulture);
//=> "2017-06-26T20:45:00.0700000Z"
// ISO8601 with 3 decimal places
string s2 = dt.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", CultureInfo.InvariantCulture);
//=> "2017-06-26T20:45:00.070Z"
A few things:
Don't use Z
in the format string. That's not a valid format specifier, so it is treated as just a character to output. It will be in every string, regardless of .Kind
setting of the input datetime.
With DateTime
, use K
- which properly conveys the .Kind
by appending a Z
to the output for DateTimeKind.Utc
, or an offset from UTC for DateTimeKind.Local
, or nothing at all for DateTimeKind.Unspecified
.
Though T
will output as a character because it's not a valid format specifier, I suggest always being explicit about those things, so prefer 'T'
.
Using fff
will always give you back three decimals (milliseconds). If you want the decimals omitted when zero, use FFF
instead. Your use of sss
is not valid.
Passing CultureInfo.InvariantCulture
is a good practice, as it helps you avoid problems where the current culture might use a different calendar system. For example ar-SA
uses the UmAlQuraCalendar
, rather than the proleptic Gregorian calendar required by ISO 8601.
In your code you tried, you had called theTime.UtcNow
- that won't compile. UtcNow
is a static property, not an instance property.
Also in your code you called theTime.Date.ToUniveralTime()
- Don't do that either. .Date
will set the time components to zero, and .ToUniversalTime()
will have no effect since the input value already has DateTimeKind.Utc
.
The problem is that you are losing accuracy by using a cultural standard such as UTC
or UniversalTime
. If you just print your DateTime
:
var theTime = new DateTime(2017, 6, 26, 20, 45, 00, 70,
DateTimeKind.Utc);
Console.WriteLine(theTime);
6/26/2017 8:45:00 PM
You can read more about this issue here.
The solution is to not use any "culture". (For example, UniversalTime
, or UtcNow
). These cultural standards never include milliseconds ... because there is no culture where people really care all that often about milliseconds.
Solution:
var newTime = theTime.ToString("o");
Console.WriteLine(newTime);
2017-06-26T20:45:00.0700000Z
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With