Dan*_*nna 57 c# format datetime utc
[ 更新:格式说明符与格式字符串不同; 格式说明符是自定义格式字符串的一部分,其中格式字符串为"stock",不提供自定义.我的问题是说明符不是格式 ]
我一直在尝试使用格式字符串执行往返DateTime转换,格式字符串使用'zzz'格式说明符,我知道绑定到本地时间.因此,如果我尝试使用UTC日期时间进行往返,则会抛出DateTimeInvalidLocalFormat异常,它应该使用以下文本:
正在将UTC日期时间转换为仅适用于本地时间的格式的文本.使用'z'格式说明符调用DateTime.ToString时会发生这种情况,该说明符将在输出中包含本地时区偏移量.在这种情况下,要么使用指定UTC时间的'Z'格式说明符,要么使用'o'格式字符串,这是在文本中保留DateTime的推荐方法.传递由XmlConvert或DataSet序列化的DateTime时也会发生这种情况.如果使用XmlConvert.ToString,则传入XmlDateTimeSerializationMode.RoundtripKind以正确序列化.如果使用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);
Run Code Online (Sandbox Code Playgroud)
And*_*ite 61
也许"K"格式说明符会有一些用处.这是唯一一个似乎提到使用资本"Z"的人.
"Z"是DateTimes的一种独特案例.文字"Z"实际上是UTC时间的ISO 8601日期时间标准的一部分.当"Z"(祖鲁语)在一段时间结束时被加上,它表示该时间是UTC,所以真正的文字Z是时间的一部分.这可能会为.NET中的日期格式库带来一些问题,因为它实际上是一个文字,而不是格式说明符.
使用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
Run Code Online (Sandbox Code Playgroud)
那么,当我打印包含时区的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
Run Code Online (Sandbox Code Playgroud)
dt1和dt2仅包含日期和时间信息.dt1和dt2不包含时区偏移量.
那么,如果"+2"不包含在dt1和dt2变量中,那么它来自哪里?
它来自您的机器时钟设置.
编译器告诉您,当您使用'zzz'格式时,您正在编写一个字符串,其中包含"DATE + TIME"(存储在dt1和dt2中)+ "TIMEZONE OFFSET"(不包含在dt1和dt2中,因为它们是DateTyme类型)并且它将使用它正在执行代码的服务器机器的偏移量.
编译器告诉您"警告:代码的输出取决于机器时钟偏移"
如果我在位于伦敦(+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
Run Code Online (Sandbox Code Playgroud)
正确的解决方案是使用DateTimeOffset数据类型代替DateTime.它可以在sql Server中从2008版本开始,在.Net框架中从3.5版本开始提供
MSDN 上的此页面列出了标准日期时间格式字符串,不包括使用“Z”的字符串。
更新:您需要确保日期字符串的其余部分也遵循正确的模式(您没有提供发送内容的示例,因此很难说您是否提供了)。要使 UTC 格式正常工作,它应该如下所示:
// yyyy'-'MM'-'dd HH':'mm':'ss'Z'
DateTime utcTime = DateTime.Parse("2009-05-07 08:17:25Z");
Run Code Online (Sandbox Code Playgroud)
通过字符串来回跳线一直很麻烦...但是文档指出'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 );
Run Code Online (Sandbox Code Playgroud)
我正在处理,DateTimeOffset不幸的是“o”打印出“+0000”而不是“Z”。
所以我结束了:
dateTimeOffset.UtcDateTime.ToString("o")
Run Code Online (Sandbox Code Playgroud)