最近,我受命以从后端到前端的特定格式提供日期,我注意到我发现自己的行为有些奇怪。 private static void OutputDateInfo(string value){
Console.WriteLine($"Input: {value}"); if (DateTime.TryParse(value, out DateTime dateTimeValue))
{
Console.WriteLine($"Setialized to universal format
{dateTimeValue.ToString("yyyy-MM-dd'T'HH:mm:ssZ")}");
}
Console.WriteLine();
}//somewhere in mainOutputDateInfo("2021-04-15T21:01:00.0000000Z");
OutputDateInfo("2021-04-15T21:01:00.0000000");1234567891011121314复制代码类型:[cpp] 
产生输出: Input: 2021-04-15T21:01:00.0000000Z
Setialized to universal format 2021-04-16T00:01:00Z
Input: 2021-04-15T21:01:00.0000000Setialized to universal format 2021-04-15T21:01:00Z12345复制代码类型:[cpp] 因此,就像我在UTC+3时区的Kyiv一样,它看起来像Z字母强制ToString方法,将日期转换为本地时间。 正如文档所述: 引用: 如果s不包含任何时区信息,则result包含一个DateTime值,该方法的返回值时其Kind属性为DateTimeKind.Unspecified。如果要解析的字符串包含时区信息,则方法返回时,结果包含DateTime值,其Kind属性为DateTimeKind.Local。 这DateTimeKind使得ToString投日期为本地时区?让我们记录更多属性以查看是否存在这种情况: private static void OutputDateInfo(string value){
Console.WriteLine($"Input: {value}"); if (DateTime.TryParse(value, out DateTime dateTimeValue))
{
Console.WriteLine($"Setialized to universal format
{dateTimeValue.ToString("yyyy-MM-dd'T'HHssZ")}");
Console.WriteLine($"Setialized to default format {dateTimeValue}");
Console.WriteLine($"Setialized with conversion to universal time
{dateTimeValue.ToUniversalTime()}");
Console.WriteLine($"Kind: {dateTimeValue.Kind}");
}
Console.WriteLine();
}1234567891011121314复制代码类型:[csharp] 现在我们在控制台中看到: Input: 2021-04-15T21:01:00.0000000Z
Setialized to universal format 2021-04-16T00:01:00Z
Setialized to default format 16.04.2021 0:01:00Setialized with conversion to universal time 15.04.2021 21:01:00Kind: Local
Input: 2021-04-15T21:01:00.0000000Setialized to universal format 2021-04-15T21:01:00Z
Setialized to default format 15.04.2021 21:01:00Setialized with conversion to universal time 15.04.2021 18:01:00Kind: Unspecified1234567891011复制代码类型:[cpp] 因此,我们确实当我们调用ToString一个DateTimeKind.Local实例,它会根据服务器时区调整。 但是,为什么将字母Z视为时区信息?上面提到的文档没有带Z字母的示例。答案是有问题的格式是ISO-8601格式,Z代表“零UTC偏移量”。是否将此格式的字符串与指定时区的任何其他字符串一样对待,还是这种特殊处理?通过比较它们,我们将得到答案。 OutputDateInfo("2021-04-15T2100.0000000Z");
OutputDateInfo("2021-04-15T2100.0000000");
OutputDateInfo("2021-04-15T1400.0000000 -7:00");123复制代码类型:[cpp] 产量: Input: 2021-04-15T21:01:00.0000000Z
Setialized to universal format 2021-04-16T00:01:00Z
Setialized to default format 16.04.2021 0:01:00Setialized with conversion to universal time 15.04.2021 21:01:00Kind: Local
Input: 2021-04-15T21:01:00.0000000Setialized to universal format 2021-04-15T21:01:00Z
Setialized to default format 15.04.2021 21:01:00Setialized with conversion to universal time 15.04.2021 18:01:00Kind: Unspecified
Input: 2021-04-15T14:01:00.0000000 -7:00Setialized to universal format 2021-04-16T00:01:00Z
Setialized to default format 16.04.2021 0:01:00Setialized with conversion to universal time 15.04.2021 21:01:00Kind: Local1234567891011121314151617复制代码类型:[cpp] 如您所见,ISO-8601格式的字符串与指定了时区的任何其他日期字符串一样对待。 我的意图不是将其视为本地时间,而是将其视为UTC时间。我的目标是为前端提供通用时间,以便将其调整为最终用户的本地时间。我们如何欺骗.NET认为这是没有任何时区的通用时间?答案是接受的过载DateTimeStyles: private static void OutputDateInfo(string value){
Console.WriteLine($"Input: {value}"); if (DateTime.TryParse(value, null, DateTimeStyles.AdjustToUniversal,
out DateTime universalTime))
{
Console.WriteLine($"Adjusted to universal {universalTime}");
}
Console.WriteLine();
}1234567891011复制代码类型:[cpp] 输出: Input: 2021-04-15T21:01:00.0000000Z
Adjusted to universal 15.04.2021 21:01:00Input: 2021-04-15T21:01:00.0000000Adjusted to universal 15.04.2021 21:01:00Input: 2021-04-15T14:01:00.0000000 -7:00Adjusted to universal 15.04.2021 21:01:0012345678复制代码类型:[cpp] 我认为,DateTimeKind在文学和博客中代表性不足。但是,在解析日期字符串并将日期转换回字符串时,绝对应该考虑到这一点。另外,值得记住的是,ISO-8601格式的日期字符串与指定了时区信息的任何其他字符串一样,尽管乍一看可能并不明显。
|