考虑到:

DateTime.UtcNow

我如何获得一个字符串,它表示在ISO 8601兼容的格式相同的值?

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

yyyy-MM-ddTHH:mm:ssZ

当前回答

DateTime.UtcNow。ToString("s", System.Globalization.CultureInfo.InvariantCulture)应该给你你想要的,因为"s"格式说明符被描述为一个可排序的日期/时间模式;符合ISO 8601标准。

编辑:为了得到OP要求的额外Z,使用“o”而不是“s”。

其他回答

惊讶于没有人提出这个建议:

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表示)。


补充道: 我决定使用answer https://stackoverflow.com/a/43793679/653058中的基准测试来比较其性能。

tl:博士;这是最昂贵的,但在我的破旧笔记本电脑上仍然只有650纳秒多一点:-)

实现:

[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 *****

有趣的是,自定义格式“yyyy-MM-ddTHH:mm:ssK”(不带ms)是最快的格式方法。

而且有趣的是,“S”格式在经典上很慢,在核心上很快……

当然,数字是非常接近的,在一些行之间的差异是不重要的(带有后缀_Verify的测试与没有后缀_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

大多数答案都是毫秒/微秒,这显然是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”说明符

您有一些选项,包括“往返(“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和DateTimeOffset in .NET:良好实践和常见陷阱中所述:

DateTime有无数的陷阱,旨在给你的代码错误: 1.- DateTime值与DateTimeKind。不确定是坏消息。 2.- DateTime在比较时不关心UTC/Local。 3.- DateTime值不支持标准格式字符串。 4.—解析带DateTime的UTC标记的字符串不能保证UTC时间。

转换DateTime。UtcNow转换为yyyy-MM-ddTHH:mm:ssZ的字符串表示形式,您可以使用DateTime结构的ToString()方法与自定义格式化字符串。在使用带有DateTime的自定义格式字符串时,重要的是要记住需要使用单引号转义分隔符。

下面将返回你想要的字符串表示:

DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", DateTimeFormatInfo.InvariantInfo)