DateTime“Z”格式说明符在哪里?

[ 更新格式说明符与格式string不一样, 格式说明符是自定义格式string的一部分,格式string是“stock”,不提供自定义。 我的问题是与说明符不格式 ]

我一直在尝试使用“zzz”格式说明符来执行往返DateTime转换,我知道它是绑定到本地时间。 所以,如果我尝试使用UTCdate时间往返,它会抛出一个DateTimeInvalidLocalFormatexception,它应该与此文本一起:

UTCdate时间正在被转换为仅在当地时间正确的格式的文本。 使用'z'格式说明符调用DateTime.ToString时会发生这种情况,这将在输出中包含本地时区偏移量。 在这种情况下,请使用指定UTC时间的“Z”格式说明符,或者使用“o”格式string,这是推荐的将文本保留为DateTime的方式。 当传递一个DateTime以被XmlConvert或DataSet序列化时,也会发生这种情况。 如果使用XmlConvert.ToString,则传入XmlDateTimeSerializationMode.RoundtripKind以正确序列化。 如果使用DataSet,请将DataColumn对象上的DateTimeMode设置为DataSetDateTime.Utc。

根据这个build议,我所需要做的就是用'ZZZ'代替'zzz',这样我就可以站在UTC格式。 问题是,在文档的任何地方都找不到'Z',我尝试的任何'Z'格式组合,例如'Z','ZZ','ZZZ',总是把DateTime实例转换为像文字一样的Z 。

有人忘记实现“Z”而不告诉exception消息的作者,或者我错过了如何换出一个有效的本地时间偏移量“+0000”没有黑客?

代码示例:

// This is the format with 'zzzzz' representing local time offset const string format = "ddd MMM dd HH:mm:ss zzzzz yyyy"; // create a UTC time const string expected = "Fri Dec 19 17:24:18 +0000 2008"; var time = new DateTime(2008, 12, 19, 17, 24, 18, 0, DateTimeKind.Utc); // If you're using a debugger this will rightfully throw an exception // with .NET 3.5 SP1 because 'z' is for local time only; however, the exception // asks me to use the 'Z' specifier for UTC times, but it doesn't exist, so it // just spits out 'Z' as a literal. var actual = time.ToString(format, CultureInfo.InvariantCulture); Assert.AreEqual(expected, actual); 

也许“K”格式说明符会有一些用处。 这是唯一似乎提到使用资本“Z”的。

对于DateTime,“Z”是一种独特的情况。 文字“Z”实际上是UTC时间的ISO 8601date时间标准的一部分。 当“Z”(Zulu)在某个时间结束时被添加,这表明那个时间是UTC,所以文字Z实际上是时间的一部分。 这可能会在.NET中为date格式库创build一些问题,因为它实际上是一个文字,而不是格式说明符。

当您使用DateTime时,您可以在variables中存储date和时间。

date可以是当地时间或UTC时间,这取决于你。

例如,我在意大利(+2 UTC)

 var dt1 = new DateTime(2011, 6, 27, 12, 0, 0); // store 2011-06-27 12:00:00 var dt2 = dt1.ToUniversalTime() // store 2011-06-27 10:00:00 

那么,当我打印包括时区在内的dt1和dt1时会发生什么?

 dt1.ToString("MM/dd/yyyy hh:mm:ss z") // Compiler alert... // Output: 06/27/2011 12:00:00 +2 dt2.ToString("MM/dd/yyyy hh:mm:ss z") // Compiler alert... // Output: 06/27/2011 10:00:00 +2 

dt1和dt2仅包含date和时间信息。 dt1和dt2不包含时区偏移量。

那么如果“+2”来自dt1和dt2variables中不包含的地方呢?

它来自你的机器时钟设置。

编译器告诉你,当你使用'zzz'格式时,你正在写一个string,结合“DATE + TIME”(存储在dt1和dt2中)+ “TIMEZONE OFFSET”(不包含在dt1和dt2中,因为他们是DateTymetypes) ,它将使用它执行代码的服务器机器的偏移量。

编译器告诉你“警告:代码的输出取决于机器时钟偏移量”

如果我在位于伦敦(+1 UTC)的服务器上运行此代码,结果将完全不同:而不是“ +2 ”将写入“ +1

 ... dt1.ToString("MM/dd/yyyy hh:mm:ss z") // Output: 06/27/2011 12:00:00 +1 dt2.ToString("MM/dd/yyyy hh:mm:ss z") // Output: 06/27/2011 10:00:00 +1 

正确的解决scheme是使用DateTimeOffset数据types来代替DateTime。 它在2008版本以及从3.5版本开始的.Net框架中可用

通过string的往返date一直是一个痛苦…但文档指出“o”说明符是用于捕捉UTC状态的往返跳动。 当parsing结果通常会有Kind == Utc,如果原来是UTC。 我发现最好的做法是在序列化之前将date标准化为UTC或本地,然后指示parsing器select哪种标准化。

 DateTime now = DateTime.Now; DateTime utcNow = now.ToUniversalTime(); string nowStr = now.ToString( "o" ); string utcNowStr = utcNow.ToString( "o" ); now = DateTime.Parse( nowStr ); utcNow = DateTime.Parse( nowStr, null, DateTimeStyles.AdjustToUniversal ); Debug.Assert( now == utcNow ); 

MSDN上的这个页面列出了标准的DateTime格式string,使用'Z'来排除string。

更新:你需要确保datestring的其余部分遵循正确的模式(你没有提供你发送的东西的例子,所以很难说你是否做了)。 UTC格式的工作应该是这样的:

 // yyyy'-'MM'-'dd HH':'mm':'ss'Z' DateTime utcTime = DateTime.Parse("2009-05-07 08:17:25Z"); 
 Label1.Text = dt.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z"); 

会输出:

 07 Mai 2009 | 08:16 | 13 | +02:00 | +02 | +2 

我在丹麦,我的格林尼治标准时间是+2小时,女巫是正确的。

如果你需要获得CLIENT Offset ,我build议你检查一下我做的一个小窍门 。 该页面在英国的GMT服务器是+00:00,你可以看到你将得到你当地的GMT偏移量。


关于你的评论,我做了:

 DateTime dt1 = DateTime.Now; DateTime dt2 = dt1.ToUniversalTime(); Label1.Text = dt1.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z"); Label2.Text = dt2.ToString("dd MMM yyyy | hh:mm | FF | ZZZ | ZZ | Z"); 

我得到这个:

 07 Mai 2009 | 08:24 | 14 | +02:00 | +02 | +2 07 Mai 2009 | 06:24 | 14 | ZZZ | ZZ | Z 

我没有得到任何例外,只是…它没有与大写Z 🙁

我很抱歉,但我错过了什么?


仔细阅读自定义date和时间格式string上的MSDN

不支持大写字母“Z”。

我正在处理DateTimeOffset ,不幸的是“o”打印出“+0000”而不是“Z”。

所以我结束了:

 dateTimeOffset.UtcDateTime.ToString("o")