关于c#:给定DateTime对象,如何以字符串格式获取ISO 8601日期?

Given a DateTime object, how do I get an ISO 8601 date in string format?

鉴于:

1
DateTime.UtcNow

如何获得一个字符串,该字符串以符合ISO 8601的格式表示相同的值?

请注意,ISO 8601定义了许多类似的格式。我要找的具体格式是:

1
yyyy-MM-ddTHH:mm:ssZ

02

这给你一个类似于2008-09-22t13:57:31.2311892-04:00的日期。

另一种方法是:

1
DateTime.UtcNow.ToString("o");

给你2008-09-22t14:01:54.9571247Z

要获取指定的格式,可以使用:

1
DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")

日期时间格式选项


DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture)应该提供您想要的内容,因为"s"格式说明符被描述为可排序的日期/时间模式;符合ISO 8601。


1
DateTime.UtcNow.ToString("s")

返回类似2008-04-10t06:30:00的值

UtcNow显然返回了一个UTC时间,因此在以下方面没有损害:

1
string.Concat(DateTime.UtcNow.ToString("s"),"Z")


用途:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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/>");

}

产量

1
2
3
4
5
6
7
8
9
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)


1
System.DateTime.UtcNow.ToString("o")

= >

1
val it : string ="2013-10-13T13:03:50.2950037Z"


您可以使用以下代码获得"Z"(ISO 8601 UTC):

1
2
Dim tmpDate As DateTime = New DateTime(Now.Ticks, DateTimeKind.Utc)
Dim res as String = tmpDate.toString("o") '2009-06-15T13:45:30.0000000Z

< BR>

这就是为什么:

ISO 8601有一些不同的格式:

日期时间类型.本地

1
2009-06-15T13:45:30.0000000-07:00

日期时间类型.utc

1
2009-06-15T13:45:30.0000000Z

日期时间类型。未指定

1
2009-06-15T13:45:30.0000000

< BR>

.NET为我们提供了一个具有以下选项的枚举:

1
2
3
4
5
6
7
8
'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"Watch实用程序"应用于ToString("O")部分,可能会得到不同的结果,我不知道这是否是bug,但在这种情况下,如果正在调试,则使用字符串变量可以获得更好的结果。

来源:标准日期和时间格式字符串(msdn)


如果您必须使用日期时间到iso 8601,那么toString("o")应该生成您要查找的内容。例如,

1
2015-07-06T12:08:27

但是,datetime+timezone可能会出现其他问题,如.net中的blog post datetime和datetimeoffset中所述:良好实践和常见缺陷:

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.


我只想用XmlConvert

1
XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind);

它将自动保留时区。


这些答案中的大多数都有毫秒/微秒,这显然不受ISO 8601的支持。正确答案是:

1
2
3
System.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssK");
// or
System.DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");

参考文献:

  • ISO 8601规范
  • "K"说明符


要将datetime.utcnow转换为yy-mm-ddthh:mm:ssz的字符串表示形式,可以使用带有自定义格式字符串的datetime结构的toString()方法。在将自定义格式字符串与日期时间一起使用时,必须记住需要使用单引号来转义分隔符。

下面将返回所需的字符串表示:

1
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.

-来自MSDN


1
2
3
DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss zzz");

DateTime.Now.ToString("O");

注意:根据您在末尾所做的转换,您将使用第一行(最喜欢它)或第二行。

请确保仅在本地时间应用格式,因为"zzz"是用于UTC转换的时区信息。

image


有趣的是,自定义格式"yyyy-mm-ddthh:mm:ssk"(不带ms)是最快的格式方法。

有趣的是,"S"格式在经典上慢,在核心上快…

当然,数字非常接近,某些行之间的差异是不显著的(后缀为_Verify的测试与没有后缀的测试相同,证明了结果的可重复性)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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 |

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
    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


要格式化如2018-06-22T13:04:16,可以在API使用的URI中传递:

1
2
3
4
public static string FormatDateTime(DateTime dateTime)
{
    return dateTime.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
}


如果您在SharePoint 2010或更高版本下开发,则可以使用

1
2
3
4
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
...
string strISODate = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now)


令人惊讶的是没有人建议:

1
System.DateTime.UtcNow.ToString("u").Replace(' ','T')

UniversalSortableDateTimePattern让您几乎可以随心所欲(这更像是一个RFC3339表示)。


使用newtonsoft.json,您可以

1
JsonConvert.SerializeObject(DateTime.UtcNow)

示例:https://dotnetfiddle.net/o2xfsl