代码之家  ›  专栏  ›  技术社区  ›  Daniel Crenna

日期时间“z”格式说明符在哪里?

  •  50
  • Daniel Crenna  · 技术社区  · 15 年前

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

    我一直试图用一个使用“zzz”格式说明符的格式字符串执行往返日期时间转换,我知道它绑定到了本地时间。因此,如果我尝试使用UTC日期时间往返,它将抛出一个datetimeinvalidlocalformat异常,它应该使用以下文本:

    正在将UTC日期时间转换为仅适用于本地时间的文本格式。使用“z”格式说明符调用datetime.toString时可能会发生这种情况,该说明符将在输出中包含本地时区偏移量。 在这种情况下,要么使用“z”格式说明符,它指定一个UTC时间 或者使用“o”格式字符串,这是在文本中持久化日期时间的推荐方法。当传递要由xmlconvert或dataset序列化的日期时间时,也可能发生这种情况。如果使用xmlconvert.toString,请传入xmldateTimeSerializationMode.RoundTripKind以正确序列化。如果使用DataSet,请将DataColumn对象的DateTimeMode设置为DataSetDateTime.utc。

    基于这个建议,我需要做的就是把代码替换为“zzz”,这样我就可以使用UTC格式。问题是,在文档中的任何地方都找不到“z”,我尝试的任何“z”格式组合(即“z”、“z z”、“z z z”)总是使用被视为文本的那些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);
    
    6 回复  |  直到 6 年前
        1
  •  55
  •   Andy White    15 年前

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

    “Z”是日期时间的一种独特情况。字面“z”实际上是UTC时间的ISO 8601日期时间标准的一部分。当“z”(zulu)附加在时间的末尾时,它表示时间是UTC,所以实际上Z是时间的一部分。这可能会给.NET中的日期格式库带来一些问题,因为它实际上是一个文本,而不是格式说明符。

        2
  •  6
  •   Marco Staffoli    6 年前

    使用date time时,可以将日期和时间存储在变量中。

    日期可以是当地时间或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”格式时,您正在编写一个组合“日期+时间”(存储在DT1和DT2中)的字符串。+ “时区偏移量”(DT1和DT2中不包含,因为它们是日期类型) 它将使用执行代码的服务器机器的偏移量。

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

    如果我在位于伦敦(+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
    

    正确的解决方案是使用datetimeoffset数据类型代替datetime。 它从2008版开始在SQL Server中可用,从3.5版开始在.NET框架中可用。

        3
  •  4
  •   Paul Alexander    15 年前

    通过字符串的往返日期一直是一个难题……但要指出“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 );
    
        4
  •  2
  •   Fredrik Mörk    15 年前

    This page 在msdn上列出标准的日期时间格式字符串,使用“z”取消对字符串的编码。

    更新:您需要确保日期字符串的其余部分也遵循正确的模式(您没有提供发送内容的示例,因此很难说您是否提供了)。要使UTC格式正常工作,应该如下所示:

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

    意志产出:

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

    我在丹麦,我和格林尼治标准时间的时差是+2小时,女巫说的对。

    如果你需要 客户端偏移 ,我建议您检查 little trick 我做到了。该页面位于英国的一个服务器上,这里的格林尼治标准时间是+00:00,如您所见,您将获得当地的格林尼治标准时间偏移量。


    关于你的评论,我做到了:

    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 Custom Date and Time Format Strings

    不支持大写“Z”。

        6
  •  0
  •   Kugel    10 年前

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

    所以我最终得到了:

    dateTimeOffset.UtcDateTime.ToString("o")