如何将DateTime格式化为Web UTC格式?

115
我有一个DateTime对象,想要将它格式化成"2009-09-01T00:00:00.000Z",但是以下代码输出的结果是"2009-09-01T00:00:00.000+01:00"(两行代码的输出结果相同):
new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")
new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffzzz")

有什么办法让它工作起来吗?
9个回答

211
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");

2
@Downvoter:您是否愿意告诉我们,您认为这个答案有什么问题? - LukeH
16
这个方法可以运行,但如果你的日期已经在UTC时区,而你的变量yourDateTime没有指定时区,使用.ToUniversalTime()会使你现有的日期出错。我最终移除了.ToUniversalTime(),这样日期就和预期一样,在数据库和Web客户端两端都对齐了。 - Robin Vessey
14
如果您的日期时间已经是协调世界时,您可以随意调用 .ToUniversalTime() 方法,它不会改变它。但是,如果您有一个以本地时间存储的协调世界时值,那么当然它会被更改(但在这种情况下,您需要解决更大的问题!)无论如何,这个答案很糟糕。您应该使用下面答案中指定的"O"格式字符串。 - BrainSlugs83
3
@BrainSlugs83:这个“糟糕”的答案实际上给了OP他们所要求的内容:2009-09-01T00:00:00.000Z。使用“O”格式说明符会给他们带来不同的结果:2009-09-01T00:00:00.0000000Z - LukeH
自定义DateTime的字符串格式化文档 https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/custom-date-and-time-format-strings - Mark Hebert
8
请注意,'字符不是必需的,使用"yyyy-MM-ddTHH:mm:ss.fffZ"也可以,并且更加优雅。 - iJungleBoy

85

为什么不直接使用 往返格式指定符("O","o")

"O"或"o"标准格式说明符表示使用保留时区信息的模式的自定义日期和时间格式字符串,并发出符合ISO 8601的结果字符串。对于DateTime值,此格式说明符旨在在文本中保留日期和时间值以及DateTime.Kind属性。如果将styles参数设置为DateTimeStyles.RoundtripKind,则可以使用DateTime.Parse(String,IFormatProvider,DateTimeStyles)或DateTime.ParseExact方法解析格式化的字符串。
"O"或"o"标准格式说明符对应于DateTime值的"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK"自定义格式字符串和DateTimeOffset值的"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz"自定义格式字符串。在此字符串中,用于界定单个字符(例如连字符、冒号和字母"T")的成对单引号表示该单个字符是无法更改的文字。这些撇号不会出现在输出字符串中。
"O"或"o"标准格式说明符(以及"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffK"自定义格式字符串)利用ISO 8601表示时区信息的三种方式来保留DateTime值的Kind属性:
public class Example
{
   public static void Main()
   {
       DateTime dat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                   DateTimeKind.Unspecified);
       Console.WriteLine("{0} ({1}) --> {0:O}", dat, dat.Kind); 

       DateTime uDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Utc);
       Console.WriteLine("{0} ({1}) --> {0:O}", uDat, uDat.Kind);

       DateTime lDat = new DateTime(2009, 6, 15, 13, 45, 30, 
                                    DateTimeKind.Local);
       Console.WriteLine("{0} ({1}) --> {0:O}\n", lDat, lDat.Kind);

       DateTimeOffset dto = new DateTimeOffset(lDat);
       Console.WriteLine("{0} --> {0:O}", dto);
   }
}
// The example displays the following output: 
//    6/15/2009 1:45:30 PM (Unspecified) --> 2009-06-15T13:45:30.0000000 
//    6/15/2009 1:45:30 PM (Utc) --> 2009-06-15T13:45:30.0000000Z 
//    6/15/2009 1:45:30 PM (Local) --> 2009-06-15T13:45:30.0000000-07:00 
//     
//    6/15/2009 1:45:30 PM -07:00 --> 2009-06-15T13:45:30.0000000-07:00

因为它没有按照要求工作,所以你最终引用了它——"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffffffzzz"不是Zulu格式。 - astrowalker
@ astrowalker 它应该可以运行。 他在他的答案中给了你多个选项。在您的情况(以及OP的情况下),您将使用DateTimeKind.Utc生成带有“ z”结尾(也称为“ Zulu格式”或“ UTC时间”)的字符串。只需查看他的UTC示例输出即可。在我的情况下,我使用了:dtVariable.ToUniversalTime().ToString("o"),它将转换为"2019-05-26T19:50:34.4400000Z""yyyy-MM-ddTHH:mm:ss.fffffffZ"。注意:我还使用Javscript的new Date(dtDateString).getTime()方法测试了这一点,并且可以正确解析由此产生的日期字符串。 - MikeTeeVee
@MikeTeeVee,我只是指出提供的解决方案不适用于DTO。适当的方法是 dto.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF'Z'")。记录一下,仅使用 "o" 添加偏移量,它不是Zulu格式。 - astrowalker
2
对于那些试图进行字符串转换的人:$"{DateTime.UtcNow:O}" - Tiago César Oliveira
要按照问题中要求的格式进行转换,请使用 new DateTime(2009, 9, 1, 0, 0, 0, 0, DateTimeKind.Utc).ToString("o"); - Chris Halcrow
1
这应该是现在被接受的答案,因为它不依赖于正确的字符串格式来确保符合ISO8601。 - Chris Halcrow

30
string.Format("{0:yyyy-MM-ddTHH:mm:ss.FFFZ}", DateTime.UtcNow)

返回 2017-02-10T08:12:39.483Z


5
在标记点上,您需要使用 fff 而不是 FFF,否则 000 将无法精确地在一秒钟内显示。 - Ryan Lundy

9
这段代码对我有效:
var datetime = new DateTime(2017, 10, 27, 14, 45, 53, 175, DateTimeKind.Local);
var text = datetime.ToString("o");
Console.WriteLine(text);
--  2017-10-27T14:45:53.1750000+03:00

// datetime from string
var newDate = DateTime.ParseExact(text, "o", null);

9

有些人指出,使用'ToUniversalTime' 会导致意外的时间显示错误,因此并不是很安全。为了解决这个问题,在此提供一个更加详细的示例。本示例创建了 DateTime 对象的扩展方法,可以安全地返回 UTC DateTime,并且可以按需使用 ToString…。

class Program
{
    static void Main(string[] args)
    {
        DateTime dUtc = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Utc);
        DateTime dUnspecified = new DateTime(2016, 6, 1, 3, 17, 0, 0, DateTimeKind.Unspecified);

        //Sample of an unintended mangle:
        //Prints "2016-06-01 10:17:00Z"
        Console.WriteLine(dUnspecified.ToUniversalTime().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUtc.SafeUniversal().ToString("u"));

        //Prints "2016 - 06 - 01 03:17:00Z"
        Console.WriteLine(dUnspecified.SafeUniversal().ToString("u"));
    }
}

public static class ConvertExtensions
{
    public static DateTime SafeUniversal(this DateTime inTime)
    {
        return (DateTimeKind.Unspecified == inTime.Kind)
            ? new DateTime(inTime.Ticks, DateTimeKind.Utc)
            : inTime.ToUniversalTime();
    }
}

7
最佳格式为“yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK”。
如果日期是UTC或带有时区(+-hh:mm)则字符串上的最后一个K将更改为“Z”。(http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx)
如LukeH所说,如果要使所有日期都是UTC,则使用ToUniversalTime很好。
最终代码如下:
string foo = yourDateTime.ToUniversalTime()
                         .ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK");

6

你想使用DateTimeOffset类。

var date = new DateTimeOffset(2009, 9, 1, 0, 0, 0, 0, new TimeSpan(0L));
var stringDate = date.ToString("u");

抱歉,我错过了您的原始格式,其中包括毫秒。
var stringDate = date.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff'Z'");

0

如果您不介意使用 Newtonsoft.Json

string result = JsonConvert.SerializeObject(DateTime.UtcNow, new JsonSerializerSettings
        {
            DateTimeZoneHandling = DateTimeZoneHandling.Utc
        });

-4

试试这个:

DateTime date = DateTime.ParseExact(
    "Tue, 1 Jan 2008 00:00:00 UTC", 
    "ddd, d MMM yyyy HH:mm:ss UTC", 
    CultureInfo.InvariantCulture);

之前提出的问题


4
我现在不打算去解析它,而是想将其打印出来。 - Grzenio
1
@ian-p,删除你的“答案”是否值得?它更像是一条评论,甚至没有涉及问题的意图 - 或者缺少解释。 - Quality Catalyst

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接