Given:
DateTime.UtcNow
How do I get a string which represents the same value in an ISO 8601-compliant format?
Note that ISO 8601 defines a number of similar formats. The specific format I am looking for is:
yyyy-MM-ddTHH:mm:ssZ
Given:
DateTime.UtcNow
How do I get a string which represents the same value in an ISO 8601-compliant format?
Note that ISO 8601 defines a number of similar formats. The specific format I am looking for is:
yyyy-MM-ddTHH:mm:ssZ
Note to readers: Several commenters have pointed out some problems in this answer (related particularly to the first suggestion). Refer to the comments section for more information.
// Do not use this
DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz", CultureInfo.InvariantCulture);
Using custom date-time formatting, this gives you a date similar to
2008-09-22T13:57:31.2311892-04:00.
Another way is:
// Prefer this, to avoid having to manually define a framework-provided format
DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
which uses the standard "round-trip" style (ISO 8601) to give you
2008-09-22T14:01:54.9571247Z.
To get the specified format, you can use:
DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture)
ToString("yyyy-MM-ddTHH:mm:ssK")
for this to work (with the jquery timeago plugin I was using). –
Breastpin dt.ToString("s") + dt.ToString("zzz")
// 2013-12-05T07:19:04-08:00 –
Macur "o"
first. –
Cockloft DateTimeOffset
, the ToString("o")
format is different than DateTime
. dateTime.ToString("o")
=> as above, ending in Z
. dateTimeOffset.ToString("o")
=> date ending in +00:00
. So coming from DateTimeOffset
you want to use dateTimeOffset.UtcDateTime.ToString("o");
. –
Zeph DateTime.Now
instead of DateTime.UtcNow
. The second option with the "o"
format is correct and less error-prone. –
Bobcat +00:00
as an offset to represent UTC is valid according to ISO8601 specs (section 3.4.2): "represents a plus sign [+] if in combination with the following element a positive value or zero needs to be represented. So simply use the o
format with both DateTime
and DateTimeOffset
. –
Adjudication ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz")
, will produce wrong results in non-Gregorian cultures such as new CultureInfo("ar-SA")
. Demo fiddle here: dotnetfiddle.net/RNvaPr. You need to pass an additional parameter CultureInfo.InvariantCulture
. Since this is the top-voted answer, I'd like to make the correction. –
Innominate .ToString("yyyy-MM-dd'T'HH:mm:ss.fffK", CultureInfo.InvariantCulture)
is the most complete way. Referring to Official Docs the 'K' formatter works the best. If you call it on DateTime.Now
(local time), it shows the offset to the UTC, and if you call it on DateTime.UtcNow
(reference time), it appends the character 'Z' as an indicator. –
Gamba $"...{Datetime.UtcNow:o}..."
will do the trick –
Exaggerated DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture)
should give you what you are looking for as the "s" format specifier is described as a sortable date/time pattern; conforms to ISO 8601.
EDIT: To get the additional Z
at the end as the OP requires, use "o"
instead of "s"
.
DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.SortableDateTimePattern);
However, since all of these exclude the time zone, etc., you might have no choice but to use the explicit formatter, i.e. "yyyy-MM-ddTHH:mm:ss.fffZ"
–
Provisional Z
, looking like this: DateTime.UtcNow.ToString(c, CultureInfo.InvariantCulture)) => 2012-06-26T11:55:36
and there's no millisecond resolution that is very nice to have since computers do a fair number of ticks per second. –
Dulse o
you get 2012-06-26T11:55:36.1007668Z
meaning 36.1007668
seconds, so you get resolution down to 1/10^7
of a second. From ISO8601:2004 If a decimal fraction is included, lower order time elements (if any) shall be omitted and the decimal fraction shall be divided from the integer part by the decimal sign [...] the comma (,) or full stop (.)
–
Dulse "s"
makes no sense because: “"O" (or "o"), "R" (or "r"), "s", and "u". These strings correspond to custom format strings defined by the invariant culture. They produce string representations of date and time values that are intended to be identical across cultures.” –
Cockloft s
is invariant? From your link (jump to format strings) it says s
uses SortableDateTimePattern
, which states "property defines the culture-specific format of date strings that are...supplied the "s" standard format string." Same for R
. U
and O
on the other hand are invariant. –
Jidda DateTimeFormatInfo
is a sealed
class. In the enumeration of types of format strings, SortableDateTimePattern
is not listed as “Properties that define culture-sensitive result strings.” Instead, further down in the table, "s"
is documented “to define a result string that conforms to the ISO 8601 standard”. ISO 8601 has no localization considerations AFAIK. Just hoping that the class library actually does as its documentation says ;-). –
Cockloft DateTime.Now.ToString("s", new CultureInfo(myCulture))
. –
Jidda CultureInfo
object, even something that isn’t InvariantCulture
, and get the same results. I.e., ISO8601 gets you the same string regardless of culture. Then you don’t have to bother with InvariantCulture
(?). But it just does seem out of place in a class where most other members should differ depending on the culture. –
Cockloft "o"
is superior. –
Cockloft "s"
is confusing. Definition vs. implementation? "The SortableDateTimePattern property defines the culture-specific format of date strings", but it is implemented as a defined standard that does not change per culture: "The format string returned by the SortableDateTimePattern property reflects a defined standard (ISO 8601) [...] Therefore, it is always the same, regardless of the culture." Quotes are from the documentation, msdn.microsoft.com/en-us/library/…. –
Botulinus "o"
or "s"
depends on your usage and it's worth reading the documentation on both (links herein). But in short, "o"
is useful where you want to preserve the Kind
property when parsing the result in reverse (hence "round-trip"). This is useful when storing the value in a database for later retrieval for example. –
Elemi DateTime.UtcNow.ToString("s")
Returns something like 2008-04-10T06:30:00
UtcNow
obviously returns a UTC time so there is no harm in:
string.Concat(DateTime.UtcNow.ToString("s"), "Z")
a + b
compiles to the same intermediate code as string.Concat(a, b)
(assuming that a and b are strings, of course) so there is no difference in performance or memory consumption. –
Zane o
instead to get the timezone? Granted, this will include microseconds like 2014-04-09T09:38:29.7562176-04:00
(from DateTime.Now
) or 2014-04-09T13:38:29.7562176Z
(UtcNow
). Compare format options –
Jidda string.Concat
gets a performance effect when concatenating at least 3 strings in one step. –
Koopman "o"
. Also, the difference with using string.Concat()
is that you have more code on the screen when it isn’t needed (i.e., your strings aren’t coming from an IEnumerable
or dynamically built array), making it less readable. –
Cockloft Use:
private void TimeFormats()
{
DateTime localTime = DateTime.Now;
DateTime utcTime = DateTime.UtcNow;
DateTimeOffset localTimeAndOffset = new DateTimeOffset(localTime, TimeZoneInfo.Local.GetUtcOffset(localTime));
//UTC
string strUtcTime_o = utcTime.ToString("o");
string strUtcTime_s = utcTime.ToString("s");
string strUtcTime_custom = utcTime.ToString("yyyy-MM-ddTHH:mm:ssK");
//Local
string strLocalTimeAndOffset_o = localTimeAndOffset.ToString("o");
string strLocalTimeAndOffset_s = localTimeAndOffset.ToString("s");
string strLocalTimeAndOffset_custom = utcTime.ToString("yyyy-MM-ddTHH:mm:ssK");
//Output
Response.Write("<br/>UTC<br/>");
Response.Write("strUtcTime_o: " + strUtcTime_o + "<br/>");
Response.Write("strUtcTime_s: " + strUtcTime_s + "<br/>");
Response.Write("strUtcTime_custom: " + strUtcTime_custom + "<br/>");
Response.Write("<br/>Local Time<br/>");
Response.Write("strLocalTimeAndOffset_o: " + strLocalTimeAndOffset_o + "<br/>");
Response.Write("strLocalTimeAndOffset_s: " + strLocalTimeAndOffset_s + "<br/>");
Response.Write("strLocalTimeAndOffset_custom: " + strLocalTimeAndOffset_custom + "<br/>");
}
UTC
strUtcTime_o: 2012-09-17T22:02:51.4021600Z
strUtcTime_s: 2012-09-17T22:02:51
strUtcTime_custom: 2012-09-17T22:02:51Z
Local Time
strLocalTimeAndOffset_o: 2012-09-17T15:02:51.4021600-07:00
strLocalTimeAndOffset_s: 2012-09-17T15:02:51
strLocalTimeAndOffset_custom: 2012-09-17T22:02:51Z
string strLocalTimeAndOffset_custom = localTimeAndOffset.ToString("yyyy-MM-ddTHH:mm:ssK");
would result in: strLocalTimeAndOffset_custom: 2012-09-17T22:02:51-07:00
–
Papeete Use the o
standard format specifier to produce an ISO 8601 compliant date string.
If it has to end with Z
instead of the timezone offset (-00:00, +05:00, -07:00
) then use a DateTime having Kind = DateTimeKind.Utc:
System.DateTime.UtcNow.ToString("o")
// 2013-10-13T13:03:50.2950037Z
To control the number of digits in fractional seconds part, edit and use the expanded form of the standard format specifier which is:
"yyyy-MM-ddTHH:mm:ss.fffffffK"
// the T above is a literal, not a format specifier
DateTime
(not a DateTimeOffset
) to get the trailing Z
. You might need to call .ToUniversalTime()
if your DateTime
isn't UTC –
Clapper 2024-01-22T00:00:00.0000000
and 2024-01-22T10:16:31.5474794Z
–
Wyne Surprised that no one suggested it:
System.DateTime.UtcNow.ToString("u").Replace(' ','T')
# Using PowerShell Core to demo
# Lowercase "u" format
[System.DateTime]::UtcNow.ToString("u")
> 2020-02-06 01:00:32Z
# Lowercase "u" format with replacement
[System.DateTime]::UtcNow.ToString("u").Replace(' ','T')
> 2020-02-06T01:00:32Z
The UniversalSortableDateTimePattern gets you almost all the way to what you want (which is more an RFC 3339 representation).
Added: I decided to use the benchmarks that were in answer https://mcmap.net/q/48592/-given-a-datetime-object-how-do-i-get-an-iso-8601-date-in-string-format to compare how this performs.
tl:dr; it's at the expensive end but still just a little over 650 nanoseconds on my crappy old laptop :-)
Implementation:
[Benchmark]
public string ReplaceU()
{
var text = dateTime.ToUniversalTime().ToString("u").Replace(' ', 'T');
return text;
}
Results:
// * Summary *
BenchmarkDotNet=v0.11.5, OS=Windows 10.0.19002
Intel Xeon CPU E3-1245 v3 3.40GHz, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100
[Host] : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
DefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
| Method | Mean | Error | StdDev |
|--------------------- |---------:|----------:|----------:|
| CustomDev1 | 562.4 ns | 11.135 ns | 10.936 ns |
| CustomDev2 | 525.3 ns | 3.322 ns | 3.107 ns |
| CustomDev2WithMS | 609.9 ns | 9.427 ns | 8.356 ns |
| FormatO | 356.6 ns | 6.008 ns | 5.620 ns |
| FormatS | 589.3 ns | 7.012 ns | 6.216 ns |
| FormatS_Verify | 599.8 ns | 12.054 ns | 11.275 ns |
| CustomFormatK | 549.3 ns | 4.911 ns | 4.594 ns |
| CustomFormatK_Verify | 539.9 ns | 2.917 ns | 2.436 ns |
| ReplaceU | 615.5 ns | 12.313 ns | 11.517 ns |
// * Hints *
Outliers
BenchmarkDateTimeFormat.CustomDev2WithMS: Default -> 1 outlier was removed (668.16 ns)
BenchmarkDateTimeFormat.FormatS: Default -> 1 outlier was removed (621.28 ns)
BenchmarkDateTimeFormat.CustomFormatK: Default -> 1 outlier was detected (542.55 ns)
BenchmarkDateTimeFormat.CustomFormatK_Verify: Default -> 2 outliers were removed (557.07 ns, 560.95 ns)
// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
1 ns : 1 Nanosecond (0.000000001 sec)
// ***** BenchmarkRunner: End *****
You have a few options including the "Round-trip ("O") format specifier".
var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("O"));
Console.WriteLine(date1.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
Output
2008-03-01T07:00:00.0000000
2008-03-01T07:00:00
However, DateTime + TimeZone may present other problems as described in the blog post DateTime and DateTimeOffset in .NET: Good practices and common pitfalls:
DateTime has countless traps in it that are designed to give your code bugs:
1.- DateTime values with DateTimeKind.Unspecified are bad news.
2.- DateTime doesn't care about UTC/Local when doing comparisons.
3.- DateTime values are not aware of standard format strings.
4.- Parsing a string that has a UTC marker with DateTime does not guarantee a UTC time.
You can get the "Z" (ISO 8601 UTC) with the next code:
Dim tmpDate As DateTime = New DateTime(Now.Ticks, DateTimeKind.Utc)
Dim res as String = tmpDate.toString("o") '2009-06-15T13:45:30.0000000Z
Here is why:
The ISO 8601 have some different formats:
DateTimeKind.Local
2009-06-15T13:45:30.0000000-07:00
DateTimeKind.Utc
2009-06-15T13:45:30.0000000Z
DateTimeKind.Unspecified
2009-06-15T13:45:30.0000000
.NET provides us with an enum with those options:
'2009-06-15T13:45:30.0000000-07:00
Dim strTmp1 As String = New DateTime(Now.Ticks, DateTimeKind.Local).ToString("o")
'2009-06-15T13:45:30.0000000Z
Dim strTmp2 As String = New DateTime(Now.Ticks, DateTimeKind.Utc).ToString("o")
'2009-06-15T13:45:30.0000000
Dim strTmp3 As String = New DateTime(Now.Ticks, DateTimeKind.Unspecified).ToString("o")
Note: If you apply the Visual Studio 2008 "watch utility" to the toString("o") part you may get different results, I don't know if it's a bug, but in this case you have better results using a String variable if you're debugging.
Source: Standard Date and Time Format Strings (MSDN)
I would just use XmlConvert
:
XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind);
It will automatically preserve the time zone.
Most of these answers have milliseconds / microseconds which clearly isn't supported by ISO 8601. The correct answer would be:
System.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssK");
// or
System.DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
References:
DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss zzz");
DateTime.Now.ToString("O");
NOTE: Depending on the conversion you are doing on your end, you will be using the first line (most like it) or the second one.
Make sure to applied format only at local time, since "zzz" is the time zone information for UTC conversion.
It is interesting that custom format "yyyy-MM-ddTHH:mm:ssK" (without ms) is the quickest format method.
Also it is interesting that "S" format is slow on Classic and fast on Core...
Of course numbers are very close, between some rows difference is insignificant (tests with suffix _Verify
are the same as those that are without that suffix, demonstrates results repeatability)
BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233539 Hz, Resolution=309.2587 ns, Timer=TSC
[Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
Clr : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
Core : .NET Core 4.6.25009.03, 64bit RyuJIT
Method | Job | Runtime | Mean | Error | StdDev | Median | Min | Max | Rank | Gen 0 | Allocated |
--------------------- |----- |-------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|-----:|-------:|----------:|
CustomDev1 | Clr | Clr | 1,089.0 ns | 22.179 ns | 20.746 ns | 1,079.9 ns | 1,068.9 ns | 1,133.2 ns | 8 | 0.1086 | 424 B |
CustomDev2 | Clr | Clr | 1,032.3 ns | 19.897 ns | 21.289 ns | 1,024.7 ns | 1,000.3 ns | 1,072.0 ns | 7 | 0.1165 | 424 B |
CustomDev2WithMS | Clr | Clr | 1,168.2 ns | 16.543 ns | 15.474 ns | 1,168.5 ns | 1,149.3 ns | 1,189.2 ns | 10 | 0.1625 | 592 B |
FormatO | Clr | Clr | 1,563.7 ns | 31.244 ns | 54.721 ns | 1,532.5 ns | 1,497.8 ns | 1,703.5 ns | 14 | 0.2897 | 976 B |
FormatS | Clr | Clr | 1,243.5 ns | 24.615 ns | 31.130 ns | 1,229.3 ns | 1,200.6 ns | 1,324.2 ns | 13 | 0.2865 | 984 B |
FormatS_Verify | Clr | Clr | 1,217.6 ns | 11.486 ns | 10.744 ns | 1,216.2 ns | 1,205.5 ns | 1,244.3 ns | 12 | 0.2885 | 984 B |
CustomFormatK | Clr | Clr | 912.2 ns | 17.915 ns | 18.398 ns | 916.6 ns | 878.3 ns | 934.1 ns | 4 | 0.0629 | 240 B |
CustomFormatK_Verify | Clr | Clr | 894.0 ns | 3.877 ns | 3.626 ns | 893.8 ns | 885.1 ns | 900.0 ns | 3 | 0.0636 | 240 B |
CustomDev1 | Core | Core | 989.1 ns | 12.550 ns | 11.739 ns | 983.8 ns | 976.8 ns | 1,015.5 ns | 6 | 0.1101 | 423 B |
CustomDev2 | Core | Core | 964.3 ns | 18.826 ns | 23.809 ns | 954.1 ns | 935.5 ns | 1,015.6 ns | 5 | 0.1267 | 423 B |
CustomDev2WithMS | Core | Core | 1,136.0 ns | 21.914 ns | 27.714 ns | 1,138.1 ns | 1,099.9 ns | 1,200.2 ns | 9 | 0.1752 | 590 B |
FormatO | Core | Core | 1,201.5 ns | 16.262 ns | 15.211 ns | 1,202.3 ns | 1,178.2 ns | 1,225.5 ns | 11 | 0.0656 | 271 B |
FormatS | Core | Core | 993.5 ns | 19.272 ns | 24.372 ns | 999.4 ns | 954.2 ns | 1,029.5 ns | 6 | 0.0633 | 279 B |
FormatS_Verify | Core | Core | 1,003.1 ns | 17.577 ns | 16.442 ns | 1,009.2 ns | 976.1 ns | 1,024.3 ns | 6 | 0.0674 | 279 B |
CustomFormatK | Core | Core | 878.2 ns | 17.017 ns | 20.898 ns | 877.7 ns | 851.4 ns | 928.1 ns | 2 | 0.0555 | 215 B |
CustomFormatK_Verify | Core | Core | 863.6 ns | 3.968 ns | 3.712 ns | 863.0 ns | 858.6 ns | 870.8 ns | 1 | 0.0550 | 215 B |
Code:
public class BenchmarkDateTimeFormat
{
public static DateTime dateTime = DateTime.Now;
[Benchmark]
public string CustomDev1()
{
var d = dateTime.ToUniversalTime();
var sb = new StringBuilder(20);
sb.Append(d.Year).Append("-");
if (d.Month <= 9)
sb.Append("0");
sb.Append(d.Month).Append("-");
if (d.Day <= 9)
sb.Append("0");
sb.Append(d.Day).Append("T");
if (d.Hour <= 9)
sb.Append("0");
sb.Append(d.Hour).Append(":");
if (d.Minute <= 9)
sb.Append("0");
sb.Append(d.Minute).Append(":");
if (d.Second <= 9)
sb.Append("0");
sb.Append(d.Second).Append("Z");
var text = sb.ToString();
return text;
}
[Benchmark]
public string CustomDev2()
{
var u = dateTime.ToUniversalTime();
var sb = new StringBuilder(20);
var y = u.Year;
var d = u.Day;
var M = u.Month;
var h = u.Hour;
var m = u.Minute;
var s = u.Second;
sb.Append(y).Append("-");
if (M <= 9)
sb.Append("0");
sb.Append(M).Append("-");
if (d <= 9)
sb.Append("0");
sb.Append(d).Append("T");
if (h <= 9)
sb.Append("0");
sb.Append(h).Append(":");
if (m <= 9)
sb.Append("0");
sb.Append(m).Append(":");
if (s <= 9)
sb.Append("0");
sb.Append(s).Append("Z");
var text = sb.ToString();
return text;
}
[Benchmark]
public string CustomDev2WithMS()
{
var u = dateTime.ToUniversalTime();
var sb = new StringBuilder(23);
var y = u.Year;
var d = u.Day;
var M = u.Month;
var h = u.Hour;
var m = u.Minute;
var s = u.Second;
var ms = u.Millisecond;
sb.Append(y).Append("-");
if (M <= 9)
sb.Append("0");
sb.Append(M).Append("-");
if (d <= 9)
sb.Append("0");
sb.Append(d).Append("T");
if (h <= 9)
sb.Append("0");
sb.Append(h).Append(":");
if (m <= 9)
sb.Append("0");
sb.Append(m).Append(":");
if (s <= 9)
sb.Append("0");
sb.Append(s).Append(".");
sb.Append(ms).Append("Z");
var text = sb.ToString();
return text;
}
[Benchmark]
public string FormatO()
{
var text = dateTime.ToUniversalTime().ToString("o");
return text;
}
[Benchmark]
public string FormatS()
{
var text = string.Concat(dateTime.ToUniversalTime().ToString("s"),"Z");
return text;
}
[Benchmark]
public string FormatS_Verify()
{
var text = string.Concat(dateTime.ToUniversalTime().ToString("s"), "Z");
return text;
}
[Benchmark]
public string CustomFormatK()
{
var text = dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
return text;
}
[Benchmark]
public string CustomFormatK_Verify()
{
var text = dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
return text;
}
}
To convert DateTime.UtcNow to a string representation of yyyy-MM-ddTHH:mm:ssZ, you can use the ToString() method of the DateTime structure with a custom formatting string. When using custom format strings with a DateTime, it is important to remember that you need to escape your seperators using single quotes.
The following will return the string represention you wanted:
DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", DateTimeFormatInfo.InvariantInfo)
The
"s"
standard format specifier represents a custom date and time format string that is defined by the DateTimeFormatInfo.SortableDateTimePattern property. The pattern reflects a defined standard (ISO 8601), and the property is read-only. Therefore, it is always the same, regardless of the culture used or the format provider supplied. The custom format string is"yyyy'-'MM'-'dd'T'HH':'mm':'ss"
.When this standard format specifier is used, the formatting or parsing operation always uses the invariant culture.
– from MSDN
.ToString("s")
? –
Pinite Using Newtonsoft.Json, you can do
JsonConvert.SerializeObject(DateTime.UtcNow)
Example: https://dotnetfiddle.net/O2xFSl
If you're developing under SharePoint 2010 or higher you can use
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
...
string strISODate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now)
.ToString("o")
or, better, $"My complicated string {dt:o}"
. –
Cockloft To format like 2018-06-22T13:04:16 which can be passed in the URI of an API use:
public static string FormatDateTime(DateTime dateTime)
{
return dateTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
}
As mentioned in other answer, DateTime
has issues by design.
I suggest to use NodaTime to manage date/time values:
So, to create and format ZonedDateTime
you can use the following code snippet:
var instant1 = Instant.FromUtc(2020, 06, 29, 10, 15, 22);
var utcZonedDateTime = new ZonedDateTime(instant1, DateTimeZone.Utc);
utcZonedDateTime.ToString("yyyy-MM-ddTHH:mm:ss'Z'", CultureInfo.InvariantCulture);
// 2020-06-29T10:15:22Z
var instant2 = Instant.FromDateTimeUtc(new DateTime(2020, 06, 29, 10, 15, 22, DateTimeKind.Utc));
var amsterdamZonedDateTime = new ZonedDateTime(instant2, DateTimeZoneProviders.Tzdb["Europe/Amsterdam"]);
amsterdamZonedDateTime.ToString("yyyy-MM-ddTHH:mm:ss'Z'", CultureInfo.InvariantCulture);
// 2020-06-29T12:15:22Z
For me NodaTime
code looks quite verbose. But types are really useful. They help to handle date/time values correctly.
To use
NodaTime
withNewtonsoft.Json
you need to add reference toNodaTime.Serialization.JsonNet
NuGet package and configure JSON options.
services
.AddMvc()
.AddJsonOptions(options =>
{
var settings=options.SerializerSettings;
settings.DateParseHandling = DateParseHandling.None;
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
});
DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")
Here you have your answer in its 'glorious' simplicity 😂!
© 2022 - 2025 — McMap. All rights reserved.