鉴于:
DateTime.UtcNow
如何以符合 ISO 8601 的格式获取代表相同值的字符串?
请注意,ISO 8601 定义了许多类似的格式。我正在寻找的具体格式是:
yyyy-MM-ddTHH:mm:ssZ
读者注意:几位评论者指出了这个答案中的一些问题(特别是与第一个建议有关)。有关更多信息,请参阅评论部分。
DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz", CultureInfo.InvariantCulture);
使用 custom date-time formatting,这将为您提供类似于
2008-09-22T13:57:31.2311892-04:00 的日期。
另一种方法是:
DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
它使用标准 "round-trip" style (ISO 8601) 为您提供
2008-09-22T14:01:54.9571247Z。
要获取指定的格式,您可以使用:
DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture)
DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture)
应该为您提供您正在寻找的内容,因为“s”格式说明符被描述为可排序的日期/时间模式;符合 ISO 8601。
编辑:要按照 OP 的要求在末尾获得额外的 Z
,请使用 "o"
而不是 "s"
。
DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.SortableDateTimePattern);
但是,由于所有这些都不包括时区等,您可能别无选择,只能使用显式格式化程序,即 "yyyy-MM-ddTHH:mm:ss.fffZ"
Z
,如下所示:DateTime.UtcNow.ToString(c, CultureInfo.InvariantCulture)) => 2012-06-26T11:55:36
并且没有非常好的毫秒分辨率,因为计算机每秒执行相当多的滴答声。
o
,您会得到 2012-06-26T11:55:36.1007668Z
意味着 36.1007668
秒,因此您可以将分辨率降低到 1/10^7
秒。来自 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 (.)
"s"
指定 CultureInfo 没有意义,因为:“"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.”
DateTime.Now.ToString("s", new CultureInfo(myCulture))
。
DateTime.UtcNow.ToString("s")
返回类似 2008-04-10T06:30:00 的内容
UtcNow
显然会返回 UTC 时间,因此在以下情况下没有害处:
string.Concat(DateTime.UtcNow.ToString("s"), "Z")
a + b
编译为与 string.Concat(a, b)
相同的中间代码(当然假设 a 和 b 是字符串),因此性能或内存消耗没有差异。
利用:
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
资料来源:
标准日期和时间格式字符串 (MSDN)
自定义日期和时间格式字符串 (MSDN)
string strLocalTimeAndOffset_custom = localTimeAndOffset.ToString("yyyy-MM-ddTHH:mm:ssK");
会导致:strLocalTimeAndOffset_custom: 2012-09-17T22:02:51-07:00
System.DateTime.UtcNow.ToString("o")
=>
val it : string = "2013-10-13T13:03:50.2950037Z"
很惊讶没有人建议:
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
UniversalSortableDateTimePattern 几乎可以让您获得想要的结果(这更像是 RFC 3339 表示)。
补充:我决定使用答案 https://stackoverflow.com/a/43793679/653058 中的基准来比较它的性能。
tl:博士;它处于昂贵的一端,但在我那破旧的笔记本电脑上仍然只有半毫秒多一点:-)
执行:
[Benchmark]
public string ReplaceU()
{
var text = dateTime.ToUniversalTime().ToString("u").Replace(' ', 'T');
return text;
}
结果:
// * 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 *****
您有几个选项,包括“往返 ("O") 格式说明符”。
var date1 = new DateTime(2008, 3, 1, 7, 0, 0);
Console.WriteLine(date1.ToString("O"));
Console.WriteLine(date1.ToString("s", System.Globalization.CultureInfo.InvariantCulture));
输出
2008-03-01T07:00:00.0000000
2008-03-01T07:00:00
但是,DateTime + TimeZone 可能会出现博文中所述的其他问题DateTime and DateTimeOffset in .NET: Good practices and common pitfalls:
DateTime 中有无数的陷阱,旨在给您的代码错误: 1.- 带有 DateTimeKind.Unspecified 的 DateTime 值是坏消息。 2.- DateTime 在进行比较时不关心 UTC/Local。 3.- DateTime 值不知道标准格式字符串。 4.- 使用 DateTime 解析具有 UTC 标记的字符串并不能保证 UTC 时间。
您可以使用以下代码获取“Z”(ISO 8601 UTC):
Dim tmpDate As DateTime = New DateTime(Now.Ticks, DateTimeKind.Utc)
Dim res as String = tmpDate.toString("o") '2009-06-15T13:45:30.0000000Z
原因如下:
ISO 8601 有一些不同的格式:
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 为我们提供了一个带有这些选项的枚举:
'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")
注意:如果您将 Visual Studio 2008“监视实用程序”应用于 toString("o") 部分,您可能会得到不同的结果,我不知道这是否是一个错误,但在这种情况下,使用 String 变量可以获得更好的结果如果你正在调试。
来源:Standard Date and Time Format Strings (MSDN)
我只会使用 XmlConvert
:
XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind);
它将自动保留时区。
这些答案中的大多数都有毫秒/微秒,ISO 8601 显然不支持。正确的答案是:
System.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssK");
// or
System.DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
参考:
ISO 8601 规范
“K”说明符
DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss zzz");
DateTime.Now.ToString("O");
注意:根据您最终进行的转换,您将使用第一行(最喜欢它)或第二行。
确保仅在本地时间应用格式,因为“zzz”是用于 UTC 转换的时区信息。
https://i.stack.imgur.com/NFhkW.png
“s”标准格式说明符表示由 DateTimeFormatInfo.SortableDateTimePattern 属性定义的自定义日期和时间格式字符串。该模式反映了定义的标准 (ISO 8601),并且该属性是只读的。因此,无论使用的文化或提供的格式提供程序如何,它总是相同的。自定义格式字符串为“yyyy'-'MM'-'dd'T'HH':'mm':'ss”。使用此标准格式说明符时,格式化或解析操作始终使用不变区域性。
– 来自 MSDN
.ToString("s")
可以吗?
要将 DateTime.UtcNow 转换为 yyyy-MM-ddTHH:mm:ssZ 的字符串表示形式,您可以使用带有自定义格式字符串的 DateTime 结构的 ToString() 方法。当使用带有 DateTime 的自定义格式字符串时,请务必记住您需要使用单引号转义分隔符。
以下将返回您想要的字符串表示形式:
DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", DateTimeFormatInfo.InvariantInfo)
有趣的是,自定义格式“yyyy-MM-ddTHH:mm:ssK”(没有 ms)是最快的格式方法。
有趣的是,“S”格式在 Classic 上速度很慢,在 Core 上速度很快......
当然数字非常接近,某些行之间的差异是微不足道的(带有后缀 _Verify
的测试与没有后缀的测试相同,证明了结果的可重复性)
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 |
代码:
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;
}
}
使用了 https://github.com/dotnet/BenchmarkDotNet
使用 Newtonsoft.Json,你可以做到
JsonConvert.SerializeObject(DateTime.UtcNow)
示例:https://dotnetfiddle.net/O2xFSl
如果您在 SharePoint 2010 或更高版本下开发,您可以使用
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
...
string strISODate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now)
.ToString("o")
,或者更好的是 $"My complicated string {dt:o}"
。
要像 2018-06-22T13:04:16 这样可以在 API 的 URI 中传递的格式,请使用:
public static string FormatDateTime(DateTime dateTime)
{
return dateTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
}
如其他答案所述,DateTime
存在设计问题。
野田时间
我建议使用 NodaTime 来管理日期/时间值:
本地时间、日期、日期时间
全球时间
时区时间
时期
期间
格式化
因此,要创建和格式化 ZonedDateTime
,您可以使用以下代码段:
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
对我来说,NodaTime
代码看起来很冗长。但是类型真的很有用。它们有助于正确处理日期/时间值。
牛顿软件.Json
要将 NodaTime 与 Newtonsoft.Json 一起使用,您需要添加对 NodaTime.Serialization.JsonNet NuGet 包的引用并配置 JSON 选项。
services
.AddMvc()
.AddJsonOptions(options =>
{
var settings=options.SerializerSettings;
settings.DateParseHandling = DateParseHandling.None;
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
});
不定期副业成功案例分享
ToString("yyyy-MM-ddTHH:mm:ssK")
才能工作(使用我正在使用的 jquery timeago 插件)。dt.ToString("s") + dt.ToString("zzz")
// 2013-12-05T07:19:04-08:00