反序列化 Invoke-Restmethod 的响应后禁用转换为 UTC 时区

问题描述 投票:0回答:2

我正在使用 Invoke-RestMethod 从 REST API 获取数据。响应的属性之一是日期。当使用 Postman 或其他工具获取数据时,日期会正确返回,但是当我使用 PowerShell(版本 5.1.19041.906)及其 Invoke-RestMethod 时,如下所示:

$response = Invoke-RestMethod -Method Get -Uri $url -Headers $requestHeaders

日期属性中的所有值都会自动转换为 UTC。有什么办法可以禁用这种转变吗?我需要从 API 返回的原始值。

powershell datetime-format
2个回答
7
投票

Invoke-RestMethod
,当给出 JSON 响应时,自动将其解析为
[pscustomobject]
图表;从某种意义上说,它具有
ConvertFrom-Json
内置

ConvertFrom-Json
确实识别出输入 JSON 中日期的不变 string 表示形式时,它将它们转换为
[datetime]
实例。

Windows PowerShell(v5.1,最新也是最终版本)和直至 PowerShell (Core) 7.4.x 中,您无法控制构建 [datetime] 实例的

kind
,如下所示反映在他们的.Kind
属性
:

  • Windows PowerShell中,需要自定义日期字符串格式(例如"\/Date(1633984531266)\/"

    ),您
    总是获得Utc
    实例。

  • PowerShell (Core) 7+ 中,还可以识别 ISO 8601 日期时间字符串(的变体)(例如 "2021-10-11T13:27:12.3318432-04:00"

    ),
    .Kind
     值取决于
    字符串值的细节

      如果字符串以
    • Z
       结尾(表示 UTC),您将获得一个 
      Utc
       实例。
    • 如果字符串以 UTC
    • offset 结尾,例如-04:00
       你会得到一个 
      Local
       实例(即使偏移值为 
      00:00
        请注意,这意味着时间戳会转换为
      • 调用者的本地时区,因此原始偏移信息丢失(除非调用者的时区偏移恰好匹配)。
    • 否则你会得到一个
    • Unspecified
       实例。

更新:

虽然

Windows PowerShell 不会看到任何新功能,但在 PowerShell 7.5+[1] 中,根据 GitHub 问题 #13598 中的功能请求,ConvertFrom-Json

 将具有 
-DateKind
 参数,因此以便允许明确请求感兴趣的日期类型,并可选择构造 
[datetimeoffset]
 实例,这些实例通常优于 
[datetime]
如果给定调用中缺少
-DateKind
 参数,上述 (PowerShell (Core)) 行为将继续适用。


解决方法

    注意:如果您需要完全按照定义访问
  • 原始字符串值,则以下解决方案将不起作用。您必须检索原始 JSON 文本并使用 Invoke-WebRequest
     和响应的 
    .Content
     属性执行您自己的解析,如 
    Mathias R. Jessen 所说。
以下代码片段

遍历从[pscustomobject]

返回的
Invoke-RestMethod
图,并显式地将遇到的任何
[datetime]实例转换为
Local
实例
就地
Unspecified
实例被视为
Local
) ):
# Call Invoke-RestMethod to retrieve and parse a web service's JSON response.
$fromJson = Invoke-RestMethod ... 

# Convert any [datetime] instances in the object graph that aren't already 
# local dates (whose .Kind value isn't already 'Local') to local ones.
& {
  # Helper script block that walks the object graph.
  $sb = {
    foreach ($el in $args[0]) { # iterate over elements (if an array)
      foreach ($prop in $el.psobject.Properties) {
        # iterate over properties
        if ($dt = $prop.Value -as [datetime]) {
          switch ($dt.Kind) {
            'Utc' { $prop.Value = $dt.ToLocalTime() }
            # Note: calling .ToLocalTime() is not an option, because it interprets
            #       an 'Unspecified' [datetime] as UTC.
            'Unspecified' { $prop.Value = [datetime]::new($dt.Ticks, 'Local') }
          }
        }
        elseif ($prop.Value -is [Array] -or $prop.Value -is [System.Management.Automation.PSCustomObject]) { 
          & $sb $prop.Value # recurse
        }
      }
    }
  }
  # Start walking.
  & $sb $args[0]
} $fromJson

# Output the transformed-in-place object graph
# that now contains only Local [datetime] instances.
$fromJson


[1] 请参阅

GitHub PR #20925。它应该首先在 PowerShell 7.5.0-preview.3 中可用


0
投票
© www.soinside.com 2019 - 2024. All rights reserved.