代码之家  ›  专栏  ›  技术社区  ›  mklement0

通过Unix时间戳的System.DateTime实例的往返转换关闭1小时

  •  2
  • mklement0  · 技术社区  · 6 年前

    注意:为了方便起见,PowerShell用于演示行为,但问题是 System.DateTime System.DateTimeOffset .

    这种行为可能有一个很好的概念上的原因,但我没有想到。 如果有的话,了解为什么以及如何避免这种陷阱将是有帮助的。

    DateTime 实例通过其Unix时间等价物以本地时间表示:

    # Get midnight 1 Jul 2018 in local time.
    $date = Get-Date '2018-07-01'
    
    # Convert to Unix time (seconds since midnight 1 Jan 1970 UTC)
    # Note: In PowerShell Core this command could be simplified to: Get-Date -Uformat %s $date
    $unixTime = [int] (Get-Date -Uformat %s $date.ToUniversalTime())
    
    # Reconvert the Unix time stamp to a local [datetime] instance.
    # Note that even though the input string is a UTC time, the cast creates
    # a *local* System.DateTime instance (.Kind equals Local)
    $dateFromUnixTime1 = ([datetime] '1970-01-01Z').AddSeconds($unixTime)
    
    # Reconvert the Unix time stamp to a local [datetime] instance via 
    # a [System.DateTimeOffset] instance:
    $dateFromUnixTime2 = ([datetimeoffset ] '1970-01-01Z').AddSeconds($unixTime).LocalDateTime
    
    # Output the results
    @"
    original:                           $date
    Unix time:                          $unixTime
    reconstructed via [datetime]:       $dateFromUnixTime1
    reconstructed via [datetimeoffset]: $dateFromUnixTime2
    "@
    

    以上(关于我的美国英语系统 Eastern Timezone ):

    original:                           07/01/2018 00:00:00
    Unix time:                          1530417600
    reconstructed via [datetime]:       06/30/2018 23:00:00
    reconstructed via [datetimeoffset]: 07/01/2018 00:00:00
    

    如你所见 [datetime] 通过 ([datetime] '1970-01-01Z') 实例-其 .Kind 价值是 Local ,即 地方的 日期-关闭1小时,而 [datetimeoffset]

    我怀疑这和夏令时有关-不会发生在 2018-12-01

    1 回复  |  直到 6 年前
        1
  •  1
  •   mklement0    6 年前

    最终问题是由于 AddSeconds 以当地时间为基础 DateTime . The .net docs

    时区之间的转换操作(例如,在UTC和本地时间之间,或在一个时区和另一个时区之间)将夏令时考虑在内, 但是算术和比较运算不能


    我不是一个重能量地狱专家,但看起来 [datetime] 'somestring' 相当于打电话 DateTime.Parse("somestring") Z ,输入将被视为UTC,然后将值转换为本地时间。这就是产生差异的原因。

    在C#(与 )可以传递参数来控制解析和输出行为:

    DateTime.Parse("1970-01-01Z", CultureInfo.InvariantCulture, DateTimeStyles.RoundTripKind)
    

    这个 RoundTripKind style说(部分地)输出类型应该由输入字符串中的信息决定。自从 Z轴 日期时间 在输出中。

    我不知道如何将这些参数传递到速记(类型加速器?)在powershell中,但是长手是这样的:

    [datetime]::Parse('1970-01-01Z', [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind)
    

    DateTimeOffset.FromUnixTimeSeconds(unixTime)
    

    你可以得到一个 日期时间 DateTimeOffset.UtcDateTime 保留UTC类型 DateTimeOffset.DateTime 总是有未指明的种类,然而 DateTimeOffset.LocalDateTime 返回本地类型)。

    [datetimeoffset]::FromUnixTimeSeconds($unixTime).UtcDateTime