如何在PowerShell中获取随机格式化的日期



我有一个登录跟踪器日志文件,它是多个来源的合并。来源(有很多(使用各种日期格式。我正在使用结果$objList对象将这些对象移交给SQL数据库。当我尝试使用SQL查询时,我会丢失数据。

以下是2007年9月的一小部分原始输入:

  1. 登录;用户名;Server01;2007年9月10日09:56:40
  2. 登录;用户名;服务器02;2007年9月10日11:26:20
  3. 登录;用户名;Server03;2007年9月11日上午10:16:27
  4. 登录;用户名;服务器04;2007年9月11日12:28:45

请注意,第三个是美国格式,其他是欧洲格式。我需要一种方法,让这些东西以一致的日期格式融入到脚本中。这个文件中实际上有几十万行,所以手动浏览和修改任何内容都是不现实的。

这是我迄今为止所拥有的。

IF ($SplitUsr.Count -eq '4')
{
$varAction = $SplitUsr[0]
IF ($varAction -eq 'Logon')
{
$varActionx = $SplitUsr[0].Trim()
$varUser = $SplitUsr[1].Trim()
$varHostname = $SplitUsr[2].Trim()
$varTime = $SplitUsr[3].Trim()
try {$datetime = [dateTime]::Parse("$varTime",([Globalization.CultureInfo]::CreateSpecificCulture('en-GB')))}
catch [System.Management.Automation.MethodInvocationException]
{
$datetime = [dateTime]::Parse("$varTime",([Globalization.CultureInfo]::CreateSpecificCulture('en-US')))
}
$objLogon = New-Object PSObject
$objLogon | Add-Member -Membertype NoteProperty -Name "Entry" -Value $intCount
$objLogon | Add-Member -Membertype NoteProperty -Name "Logon" -Value '1'
$objLogon | Add-Member -Membertype NoteProperty -Name "User" -Value $varUser
$objLogon | Add-Member -Membertype NoteProperty -Name "Hostname" -Value $varHostname
$objLogon | Add-Member -Membertype NoteProperty -Name "Date" -Value $datetime
$objList += $objLogon

不幸的是,这正在将它们解析为

  1. 2007年9月10日09:56:40
  2. 2007年9月10日11:26:20
  3. 2007年11月9日10:16:27
  4. 2007年9月11日12:28:45

您可以看到,第三个示例,即原始数据中具有美国格式的示例,显示为11月,而不是9月11日(反转9和11(。

同样的事情正在各地发生。当我查看12月份的SQL条目时,我得到的是:

  1. 2007年12月7日09:53:33
  2. 2007年12月7日11:37:48
  3. 2007年7月12日13:25:02
  4. 2007年12月7日13:26:38
  5. 2007年12月7日15:04:56

你可以看到第三个不知怎么把12和7倒过来了。这就是我正在努力解决的问题。

有什么建议吗?

编辑:更多示例:

  1. 登录;用户名;Server01;2008年11月18日11:19:08
  2. 登录;用户名;服务器02;2008年11月18日上午11:21:46
  3. 登录;用户名;Server03;2008年11月18日14:28:30
  4. 登录;用户名;服务器04;2008年11月19日09:55:50
  5. 登录;用户名;服务器名称;2008年11月19日14:14:09
  6. 登录;用户名;服务器名称;2008年11月19日14:19:56
  7. 登录;用户名;服务器名称;2008年11月20日下午12:19:57

不幸的是,并非所有的AM/PM都表示美式格式。

这就是您所说的"KI":

$dates = @( '10/09/2007 09:56:40',
'09/10/2007 11:26:20',
'10/09/2007 10:16:27 AM',
'10/09/2007 12:28:45' )
$cultureUS = [CultureInfo]::CreateSpecificCulture("en-US")
$cultureEU = [CultureInfo]::CreateSpecificCulture("en-GB")
$maxDays   = 2  # Max. allowed difference between current date and former date in days
for( $i = 0; $i -lt $dates.Count; $i++ ) {
$currentDate = [DateTime]::Parse( $dates[ $i ],$cultureEU )
if( $i -gt 0 ) {
$diffPast = New-TimeSpan -Start $lastDate -End $currentDate
}
else {
$diffPast = New-TimeSpan -Start $currentDate -End $currentDate
}
if( $diffPast.Days -gt $maxDays ) {
# check if month of current date is day of last date => culture issue
if( $currentDate.Day -eq $lastDate.Month -or $currentDate.Month -eq $lastDate.Day ) {
$currentDate = [DateTime]::Parse( $dates[ $i ],$cultureUS )
}
}
$currentDate
$lastDate = $currentDate
}

不幸的是,并非所有的AM/PM都表示美国日期格式。

如果没有额外的信息,您就无法解决您的问题,因为固有的模糊性:

9/11/2007 10:16:27 AM

无法判断这是指9月11日(第一个月(的en-US(美国(时间戳,还是指11月9日(第一天(的en-GB(英国(时间戳。

只有当第一个或第二个组件恰好是13或更高时,才意味着en-USen-GB,并且只有这样的时间戳才能由问题中的try/catch逻辑正确处理。


如果您提供了所有日期都必须满足的附加约束,则可以找到解决方案

例如,如果您知道所有日期都属于给定月份

# The month that all log entries are expected to fall into:
$refMonth = 9  # September, for example.
# Create an array of the cultures to use for parsing:
[cultureinfo[]] $cultures = 'en-GB', 'en-US'
'11/9/2007 17:02:15',
'9/11/2007 05:02:44 PM',
'11/9/2007 05:03:01 PM' | ForEach-Object {
$ok = $false; [datetime] $dt = 0
foreach ($culture in $cultures) {
$ok = [datetime]::TryParse($_, $culture, 'None', [ref] $dt) -and $dt.Month -eq $refMonth
if ($ok) { break }
}
if (-not $ok) { Write-Error "Not recognized as a date in the expected month: $_" }
else { $date } # Output the resulting date.
}

上面的结果如下,显示所有日期都被解析为9月(9月(日期:

Tuesday, September 11, 2007 5:02:15 PM
Tuesday, September 11, 2007 5:02:44 PM
Tuesday, September 11, 2007 5:03:01 PM

最新更新