日期时间‘ Z’格式说明符在哪里?

[ 更新: 格式说明符与格式字符串不同; 格式说明符是自定义格式字符串的一部分,其中的格式字符串是“ stock”,不提供自定义。我的问题是说明符不是格式]

我一直在尝试用一个使用“ zzz”格式说明符的格式字符串执行往返 DateTime 转换,我知道这个格式字符串绑定到本地时间。因此,如果我尝试使用 UTC 日期时间来回旅行,它会抛出一个 DateTimeInvalidLocalFormat 异常,它应该这样做,如下所示:

正在将 UTC DateTime 转换为只适用于本地时间的格式的文本。当使用‘ z’格式说明符调用 DateTime.ToString 时可能会发生这种情况,该格式说明符将在输出中包含一个本地时区偏移量。或者使用‘ o’格式字符串,这是在文本中保持 DateTime 的推荐方法。在传递要由 XmlConvert 或 DataSet 序列化的 DateTime 时也可能发生这种情况。如果使用 XmlConvert.ToString,请传入 XmlDateTimeSerializationMode。正确序列化。如果使用 DataSet,请将 DataColumn 对象上的 DateTimeMode 设置为 DataSetDateTime。Utc.

基于这个建议,我所需要做的就是将‘ ZZZ’替换为‘ ZZZ’,这样我就可以使用 UTC 格式。问题是,“ Z”在文档中的任何地方都找不到,我尝试的任何“ Z”格式组合,例如“ Z”、“ ZZ”、“ ZZZ”,总是只是将 DateTime 实例转换为这些“ Z”格式的字面值。

是否有人忘记在不告诉异常消息作者的情况下实现“ Z”,或者我错过了如何在不进行黑客攻击的情况下用“ + 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);
224366 次浏览

MSDN 上的这个页面 列出了标准的 DateTime 格式字符串,不包括使用“ Z”的字符串。

更新: 您需要确保日期字符串的其余部分也遵循正确的模式(您没有提供发送内容的示例,因此很难说您是否提供了)。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小时,女巫是正确的。

如果你需要得到的 客户抵销,我建议你检查一个 小把戏,我做了。这个页面位于英国的一个服务器上,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: (

不好意思,我是不是漏掉了什么?


仔细阅读 自定义日期和时间格式字符串上的 MSDN

不支持大写字母“ Z”。

也许“ K”格式说明符会有一些用处。这是唯一一个提到大写字母“ Z”的。

“ Z”对日期时报来说是个特例。文字“ Z”实际上是用于 UTC 时间的 ISO8601日期时间标准的一部分。当“ Z”(Zulu)被添加到时间的末尾时,它表明时间是 UTC,所以字面上的 Z 实际上是时间的一部分。中的日期格式库可能会产生一些问题。NET,因为它实际上是一个文字,而不是一个格式说明符。

通过字符串进行往返日期一直是一个痛苦的问题... ... 但是文档指出‘ o’说明符是用于往返日期的说明符,它捕获 UTC 状态。在解析结果时,如果原始结果是 UTC,那么结果通常是 Kind = = UTC。我发现,最好的办法是总是在序列化之前将日期规范化为 UTC 或本地日期,然后指示解析器选择哪种规范化。

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 );

使用 DateTime 时,您可以在变量中存储日期和时间。

日期可以是当地时间,也可以是 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和 dt2时会发生什么呢?

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只包含日期和时间信息。 Dt1和 dt2不包含时区偏移量。

那么,如果“ + 2”不包含在 dt1和 dt2变量中,它从何而来呢?

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

编译器告诉你,当你使用‘ zzz’格式时,你正在编写一个字符串,将“ DATE + TIME”(存储在 dt1和 dt2中) + “ TIMEZONE OffSET”(不包含在 dt1和 dt2中,因为它们是 DateTyme 类型)组合在一起,它将使用它正在执行代码的服务器机器的偏移量。

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

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

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

正确的解决方案是使用 DateTimeOffset 数据类型代替 DateTime。 从2008版本开始,可以在 sql Server 中使用它,从3.5版本开始,可以在.Net 框架中使用它

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

所以我最后说:

dateTimeOffset.UtcDateTime.ToString("o")

如果需要强制使用 +00:00而不是 Z来指示 UTC,这将得到所需的内容:

string timeStamp = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.ffffff'+00:00'");

看起来 + 00.00发生在 DateTimekind 不是 UTC 时。指定它使“ o”正确工作:

DateTime.SpecifyKind(new DateTime(2011, 6, 27, 12, 0, 0), DateTimeKind.Utc).ToString("o");

这将返回 Z 时间