c# convert datetime object to iso 8601 string
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
, useK
- which properly conveys the.Kind
by appending aZ
to the output forDateTimeKind.Utc
, or an offset from UTC forDateTimeKind.Local
, or nothing at all forDateTimeKind.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, useFFF
instead. Your use ofsss
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 examplear-SA
uses theUmAlQuraCalendar
, 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 hasDateTimeKind.Utc
.
How to parse and generate DateTime objects in ISO 8601 format
The format you're describing is ISO 8601.
Since you're working with timestamps that inclulde a time zone component, I'd strongly recommend using DateTimeOffset
instead of DateTime
. It makes things so much easier!
To create a DateTimeOffset
for a given date, time, and time zone offset, use this syntax:
var date = new DateTimeOffset(2016, 3, 29, 12, 20, 35, 93, TimeSpan.FromHours(-5));
// March 29, 2016 at 12:20:35.93 GMT-5
This code will format a DateTimeOffset
as ISO 8601:
public static string FormatIso8601(DateTimeOffset dto)
{
string format = dto.Offset == TimeSpan.Zero
? "yyyy-MM-ddTHH:mm:ss.fffZ"
: "yyyy-MM-ddTHH:mm:ss.fffzzz";
return dto.ToString(format, CultureInfo.InvariantCulture);
}
And, to parse a string back to a DateTimeOffset
:
public static DateTimeOffset ParseIso8601(string iso8601String)
{
return DateTimeOffset.ParseExact(
iso8601String,
new string[] { "yyyy-MM-dd'T'HH:mm:ss.FFFK" },
CultureInfo.InvariantCulture,
DateTimeStyles.None);
}
If you must get back to a DateTime
you can get this from the DateTimeOffset
.UtcDateTime
property.
How do I translate an ISO 8601 datetime string into a Python datetime object?
I prefer using the dateutil library for timezone handling and generally solid date parsing. If you were to get an ISO 8601
string like: 2010-05-08T23:41:54.000Z
you'd have a fun time parsing that with strptime, especially if you didn't know up front whether or not the timezone was included. pyiso8601
has a couple of issues (check their tracker) that I ran into during my usage and it hasn't been updated in a few years. dateutil, by contrast, has been active and worked for me:
from dateutil import parser
yourdate = parser.parse(datestring)
Python: How to compare date string in ISO 8601 format with current time
Try using datetime.fromisoformat(date_string)
to parse date_str
and then passing the determined timezone info into datetime.now(tz=None)
:
>>> from datetime import datetime
>>> date_str = '2022-03-29T17:49:35.914417-04:00'
>>> dt = datetime.fromisoformat(date_str)
>>> dt
datetime.datetime(2022, 3, 29, 17, 49, 35, 914417, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))
>>> dt_now = datetime.now(dt.tzinfo)
>>> dt_now
datetime.datetime(2022, 5, 20, 15, 50, 58, 525908, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000)))
>>> dt_now > dt
True
>>> dt_now - dt
datetime.timedelta(days=51, seconds=79282, microseconds=611491)
Converting ISO 8601-compliant String to java.util.Date
Unfortunately, the time zone formats available to SimpleDateFormat (Java 6 and earlier) are not ISO 8601 compliant. SimpleDateFormat understands time zone strings like "GMT+01:00" or "+0100", the latter according to RFC # 822.
Even if Java 7 added support for time zone descriptors according to ISO 8601, SimpleDateFormat is still not able to properly parse a complete date string, as it has no support for optional parts.
Reformatting your input string using regexp is certainly one possibility, but the replacement rules are not as simple as in your question:
- Some time zones are not full hours off UTC, so the string does not necessarily end with ":00".
- ISO8601 allows only the number of hours to be included in the time zone, so "+01" is equivalent to "+01:00"
- ISO8601 allows the usage of "Z" to indicate UTC instead of "+00:00".
The easier solution is possibly to use the data type converter in JAXB, since JAXB must be able to parse ISO8601 date string according to the XML Schema specification. javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
will give you a Calendar
object and you can simply use getTime() on it, if you need a Date
object.
You could probably use Joda-Time as well, but I don't know why you should bother with that (Update 2022; maybe because the entire javax.xml.bind
section is missing from Android's javax.xml
package).
Related Topics
An Async/Await Example That Causes a Deadlock
How to Update the Gui from Another Thread
How to Implement Custom Jsonconverter in Json.Net
How to Convert a Byte Array to a Hexadecimal String, and Vice Versa
Difference Between a Field and a Property
C# Variance Problem: Assigning List≪Derived≫ as List≪Base≫
Webbrowser Control in a New Thread
How and When to Use 'Async' and 'Await'
Why Saving Changes to a Database Fails
What Does the [Flags] Enum Attribute Mean in C#