【问题标题】:PowerShell CSV file conversion errors due PC with different DateTime format that the input file由于 PC 与输入文件的 DateTime 格式不同,PowerShell CSV 文件转换错误
【发布时间】:2021-12-01 14:41:00
【问题描述】:

我正在使用带有脚本的 PowerShell 将 .CSV 原始数据文件转换为更易于管理的数据格式,其中包含单独的列、更清晰的视图等。而且由于原始数据的源文件采用美国日期和时间格式(例如 21 年 11 月 23 日下午 1:00),那么如果 PC 采用相同的美国格式,则转换过程运行正常,错误为 0。但是,如果 PC 使用不同的国家/地区日期和时间格式,则 PowerShell 在此过程中会显示红色错误。

当 PC 采用其他 DateTime 格式时,我看到的主要错误是:

使用“1”个参数解析:“字符串未被识别为有效的日期时间。

问题是将使用它的 PC 不是美国格式(仅更改为美国格式进行测试),所以这里有人可以帮我在转换过程中添加语法或句子以简单直接在代码中指定一个固定格式,该格式独立于 PC 时钟日期和时间格式保持静态输出格式,如果文件的输入之一是“11/23/21, 1:00 PM”,则在您希望以“dd-MMM-yyyy hh:mm”格式输出的代码具有类似“23-Nov-2021 01:00 PM”的结果

用于转换的脚本中的代码部分是:

…
$data = $csvData | ? {$_ -match "\(DTRE"}

dtreFileData = New-Object System.Collections.Generic.List[PSCustomObject]

foreach ($item in $data)
{
  $null = $item.Strategy -match "\(DTRE\|(.*)\)"
  $v = $Matches[1] -split '\|'

  $resultvalue = $v[0] | Convert-CurrencyStringToDecimal
  $expectedvalue = $v[1] | Convert-CurrencyStringToDecimal

  $dtreData = [PSCustomObject]@{
    'DateTime' = ([datetime]::Parse($item.'Date/Time'))
    'ResultValue' = [decimal]$resultvalue
    'ExpectedValue' = [decimal]$expectedvalue
    }
  
  $null = $dtreFileData.Add($dtreData)
  $null = $dtreAllData.Add($dtreData)
}

$dtreFileData | Export-Csv -Path (Join-Path (Split-Path -Path $f -Parent) ($outFile + '.csv')) -Force -NoTypeInformation -Encoding ASCII
…

原始源数据示例(在 CVS 文件中有几十行类似下一行):

...(DTRE|49.0|48.2);...;11/23/21, 12:58 PM...;

...(DTRE|52.1|52.0);...;11/23/21, 1:00 PM...;

...

...

输出看起来像:

我尝试使用此处 (stackoverflow.com) 的其他帖子中的 DateTime 示例来调整代码以在没有美国日期和时间格式的 PC 中工作,并获得上述 DateTime 格式结果。例如:

'DateTime' = ([datetime]::Parse($item.'yyyy-MM-dd:HH:mm:ss'))

'DateTime' = ([datetime]::ParseExact($item.'yyyy-MM-dd:HH:mm:ss'))

…
$culture = [Globalization.CultureInfo]::InvariantCulture
…
  'DateTime' = ([datetime]::ParseExact($item.'yyyy-MM-dd:HH:mm:ss', $culture))
…

但是对于这些示例,PowerShell 显示错误“无法将参数绑定到参数 'InputObject',因为它为空

@Seth 回答后更新:

尝试下一次修改代码时,PC 系统日期格式为“24-Nov-21”,其余如上:

…
$resultvalue = $v[0] | Convert-CurrencyStringToDecimal
$expectedvalue = $v[1] | Convert-CurrencyStringToDecimal
$cultureInfo= New-Object System.Globalization.CultureInfo("es-ES")

$dtreData = [PSCustomObject]@{
  'DateTime' = ([System.DateTime]::Parse($item.'Date/Time', $cultureInfo))
  'ResultValue' = [decimal]$resultvalue
  'ExpectedValue' = [decimal]$expectedvalue
…

然后,PowerShell 显示下一个错误:

【问题讨论】:

  • CSV 文件应该有一个规范,明确显示日期和时间的格式。使用 ISO-8601 是个好主意。目前尚不清楚问题中的$item 是什么。 ([datetime]::ParseExact('2021-11-01', 'yyyy-MM-dd', $null)) 有效。在问题中显示一些示例日期会很有帮助。
  • 谢谢@lit。我更新了显示 3 次 $item 进入脚本文件的帖子。我尝试使用 'DateTime' = ([datetime]::Parse($item.'yyyy-MM-dd')),但 PowerShell 给出错误:“Export-Csv:无法将参数绑定到参数 'InputObject',因为它为空。” 我不知道是否可能是 @987654334 的部分@ 可能导致格式问题,但我尝试将其更改为 -Encoding BigEndianUnicode-Encoding UTF32 以及同样的错误。我还展示了“原始数据”中的格式以及转换后的外观,但问题是我不使用美国格式。
  • 请注意,当 PC 日历/时钟为美国格式时,脚本可以完美运行,进行完美转换,除了因为它以美国格式显示日期,月份在首位。当 PC 是另一种日历/时钟格式时,转换问题就出现了,这正是需要使用脚本的情况。所以我需要的是一种“通用”方式,我可以在代码中指定将每个 DateTime 项转换为特定格式,例如 dd-MMM-yyyy hh:mm23-Nov-2021 01:00 PM)。一种通用且固定的方式,无论 PC 中的日期和时间格式如何。
  • 对这种情况最直接的解决方案是控制创建 CSV 数据的过程。它必须始终以特定格式创建它。使用yyyy-MM-DD 作为日期。总是。如果您无法控制 CSV 数据的创建,那么您可以为您的阅读脚本指定一个参数来指示日期格式。您还可以对几种格式使用 try/catch 来查看其中一种是否有效,但这并不可靠。解决方案是更正 CSV 数据的创建。
  • 感谢您的评论@lit。代码不是我创建的,我不知道您是否说要修改最后一行:$dtreFileData | Export-Csv -Path (Join-Path (Split-Path -Path $f -Parent) ($outFile + '.csv')) -Force -NoTypeInformation -Encoding ASCII 可能会更改 -Encoding ASCII。我尝试将 ASCII 更改为其他人,但当我这样做时 PowerShell 会出错。您能否将您的解决方案作为答案显示您的意思是什么?需要添加什么以及需要修改什么。您可以获取代码并执行所需的操作来展示操作方法。

标签: powershell datetime


【解决方案1】:

正如已经解释的那样,修复 CSV 以获得更好的日期格式是个好主意。一个示例是 ISO 8601,它可以与 Get-Date -Format "o" 一起使用。

也就是说Get-Date 依赖于后台的 C# 内容。所以你可以使用 C# 代码来阅读that in a particular culture。如您所知,这应该有效。修复时间戳仍然是一个更好的主意。

$cultureInfo= New-Object System.Globalization.CultureInfo("en-US")
$dateString = "11/23/21, 12:58 PM";
$dateTime = [System.DateTime]::Parse($dateString, $cultureInfo);
Get-Date -Format "o" $dateTime

使用此示例代码,您可以将$item.' Date/Time' 的值分配给$dateString,而您可能想要的结果将是Get-Date 的结果。因此,您将分配$dtreData.'DateTime' Get-Date 调用的结果。或者,可以使用 .NET DateTime 对象直接转换为特定区域性。例如通过调用$dateTime.ToString((New-Object System.Globalization.CultureInfo("en-ES")))。虽然不是很有用,但您也可以将格式标识符传递给此方法。如果您想避免创建其他对象,这可能是相关的。有点不必要的调用是$dateTime.ToString("o", (New-Object System.Globalization.CultureInfo("en-ES")))(因为格式 o 在每种文化中都是相同的)。

【讨论】:

  • 感谢您的回复@Seth,但还没有解决方案。我尝试使用您的行修改代码,但我仍然无法以代码中直接指定的格式获取日期和时间,并说“获取 CSV 输入文件中的每个 DateTime 值并将它们转换为格式 dd-MMM-yyyy hh:mm ,或者例如文化名称es-ES,或类似的东西”,即直接在代码中指定为通用/通用方式,无论PC是英文日期和时间格式,还是PC是西班牙日期和时间格式,或者如果 PC 是法国日期和时间格式
  • 用你的台词,我尝试了下一次修改代码,PC系统日期为美国格式:$resultvalue = $v[0] | Convert-CurrencyStringToDecimal$expectedvalue = $v[1] | Convert-CurrencyStringToDecimal$cultureInfo= New-Object System.Globalization.CultureInfo("en-US")$dtreData = [PSCustomObject]@{$dtreData = [PSCustomObject]@{'DateTime' = ([System.DateTime]::Parse($item.'Date/Time', $cultureInfo))'ResultValue' = [decimal]$resultvalue@987654341 @ 并且转换工作没有错误,但以美国格式给出结果并取决于操作系统日期格式。
  • 我也试了下代码修改,PC系统日期格式为“24-Nov-21”:…$resultvalue = $v[0] | Convert-CurrencyStringToDecimal$expectedvalue = $v[1] | Convert-CurrencyStringToDecimal$cultureInfo= New-Object System.Globalization.CultureInfo("es-ES")$dtreData = [PSCustomObject]@{'DateTime' = ([System.DateTime]::Parse($item.'Date/Time', $cultureInfo))@987654347 @'ExpectedValue' = [decimal]$expectedvalue 此处 PowerShell 给出错误消息:“Export-Csv : Cannot bind argument to parameter 'InputObject' because it is null”
  • 关于Get-Date -Format "o" $dateTime 我真的不知道它在问题中发布的代码中的位置。我试图把它放在多个地方,比如最后一行,或者在'DateTime' = ([System.DateTime]::Parse($item.'Date/Time', $cultureInfo)) 之后,或者放到里面,但是 PowerShell 给出了错误。关于$dateString = "11/23/21, 12:58 PM"; 我没有使用这部分,因为我认为这将是一个输入示例,在这种情况下,输入的 DateTime 值已经在 CSV 文件中,这些值是需要处理的值。
  • 如果您知道@Seth,您能否修改上述问题中发布的代码并添加所需的修改以获得我需要的日期和时间结果。非常感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-11
  • 2015-02-26
  • 2017-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多