【问题标题】:Cannot convert value "Mon, 02 Nov 2020 06:39:24 PST" to type "System.DateTime"无法将值“星期一,2020 年 11 月 2 日 06:39:24 PST”转换为类型“System.DateTime”
【发布时间】:2020-11-14 05:08:00
【问题描述】:

我正在尝试使用以下内容解析 RSS 提要以提取最近一小时内更新的帖子:

ForEach ($item in $items) {
If (($Now - [datetime]$item.updated).TotalMinutes -le 60) {
    $link = $item.link
    $updated = [datetime]$item.updated
    $finalnews = new-object PSCustomObject -prop @{link=$link;updated=$updated}
    $news += $finalnews
}

}

但是,这继续失败并出现错误:

无法将值“周一,2020 年 11 月 2 日 06:39:24 PST”转换为类型“System.DateTime”。错误:“字符串未被识别为有效的日期时间。

我认为这是因为 item.updated 属性中日期末尾的 PST 或 PDT

如何重新格式化或替换每个项目中的现有日期时间,以免引发错误?

要替换或重新格式化的属性是:

$rssfeed.rss.channel.Item.updated

感谢您的任何帮助或建议。

【问题讨论】:

  • $updated = [datetime]($item.updated -replace '.{4}$')$finalnews updated 属性的目标是什么?应该是什么时区,应该是什么格式?
  • 谢谢,我希望 updated 属性显示为例如 Mon, 02 Nov 2020 06:39:24 - 所以最后没有 PST 或 PDT 时区。我在哪里可以放置您建议的代码,该脚本目前似乎在 IF 语句行上失败。

标签: powershell datetime


【解决方案1】:

如果您可以假设时区缩写后缀(例如,PST)总是指本地时区

您可以简单地去掉后缀并直接转换为[datetime]

# Sample input.
$dateStr = 'Mon, 02 Nov 2020 06:39:24 PST'

# Strip a 3-letter suffix preceded by a space, if present.
# If there is no such suffix, the input string is used as-is.
# Note: Resulting [datetime] instance has .Kind value Unspecified.
[datetime] ($dateStr -creplace '^(.+) [A-Z]{3}$', '$1')

请注意,结果将以本地时间表示,但生成的[datetime] 实例将具有.KindUnspecified 而不是Local,当您调用.ToLocalTime() 时,此类实例的行为类似于UTC他们。

为确保您获得明确表示本地时间的Local 实例(尽管相对于本地机器的时区),请使用[datetimeoffset] 进行转换并使用生成的实例的.LocalDateTime 属性:

$dateStr = 'Mon, 02 Nov 2020 06:39:24 PST'

# Resulting [datetime] instance has .Kind value Local.
([datetimeoffset] ($dateStr -creplace '^(.+) [A-Z]{3}$', '$1')).LocalDateTime

如果可行,使用[datetimeoffset] (System.DateTimeOffset) 而不是[datetime] (System.DateTime)通常更可取,因为[datetimeoffset] 实例明确代表一个具体的、独立的时间点。


如果时区缩写后缀可以代表任意时区:

不幸的是,[System.TimeZoneInfo]::GetSystemTimeZones()) 返回的预定义时区信息对象确实包含诸如PST 之类的缩写,但是,这是有充分理由的:此类缩写没有全球标准,所以PST 可以指代世界不同地区的不同时区。

这意味着您必须创建自己的这些后缀到它们所代表的 UTC 偏移量的映射,例如 -08:00 代表 PST,如果解释为美国 Pacific (Standard) Time时区:

# Sample input.
$dateStr = 'Mon, 02 Nov 2020 06:39:24 PST'

# Map time-zone abbreviations such as 'PST' to their UTC offset.
# IMPORTANT: Be sure to define mappings for all suffixes you may encounter
#            in your input.
$tzAbbrevToUtcOffsetSuffix = @{
  'PST' = '-08:00'
}

if ($dateStr -cmatch '^(.+) ([A-Z]{3})$') { # Time-zone suffix present.

  # Map the suffix to its UTC offset.
  $utcOffset = $tzAbbrevToUtcOffsetSuffix[$Matches.2]
  if (-not $utcOffset) { Throw "No UTC offset defined for timze-zone abbreviation: $($Matches.2)" }

  # Replace the suffix with its UTC offset in the input string.
  $dateStr = $Matches.1 + ' ' + $utcOffset
  # Tell ::ParseExact() below to expect a UTC offset.
  $formatSuffix = ' K'

} else { # No time-zone suffix.
  # Assume it is a local date without time-zone suffix.
  $formatSuffix = ''
}

# Use [datetimeoffset] for parsing, so we can create a [datetime] instance
# with .Kind 'Local'.
[datetimeoffset]::ParseExact(
  $dateStr, 
  ('ddd, dd MMM yyyy HH:mm:ss' + $formatSuffix), 
  [cultureinfo]::InvariantCulture
).LocalDateTime

【讨论】:

    【解决方案2】:

    如果要比较时间,则需要在同一时区进行比较。您可以使用-replace 删除字符串的最后 4 个字符(空格加区域字母)。

    $Now = Get-Date
    $news = Foreach ($item in $items) {
        $time = $item.updated -replace '.{4}$'
        $converted = [timezoneinfo]::ConvertTime([datetime]$time,[timezoneinfo]::FindSystemTimeZoneById('Pacific Standard Time'),[timezoneinfo]::local)
        if (($Now - $converted).TotalMinutes -le 60) {
            $link = $item.link
            $updated = $time
            [pscustomobject]@{link=$link;updated=$updated}
        }
    }
    

    说明:

    += 无需附加到数组。您可以简单地分配 foreach 循环的数组输出。

    如果您当地的时区是 PST/PDT,那么您不需要转换时间。

    由于$nowDateTime 对象,您需要先将任何日期字符串转换为DateTime 对象,然后再进行比较或日期数学运算。所以如果你跳过$converted转换步骤,那么你必须使用$now - [datetime]$time

    【讨论】:

    • 谢谢,添加 $time = $item.updated -replace '.{4}$' 效果很好,但我仍然在 if 语句的 foreach 循环中遇到错误。现在的错误略有不同,说明Multiple ambiguous overloads found for "op_Subtraction" and the argument count: "2". At line:5 char:9 + If (($Now - $time).TotalMinutes -le 60) {
    • @terrahawk80 如果你在做$now - $time,那么$time需要先转换成datetime对象。所以应该是$now - [datetime]$time
    • 啊哈,是的!我省略了[datetime],谢谢。我认为这一切现在都可以正常工作了,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    • 2020-12-07
    • 2020-09-30
    • 2020-06-05
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多