我有一个登录跟踪器日志文件,它是多个来源的合并。来源(有很多(使用各种日期格式。我正在使用结果$objList对象将这些对象移交给SQL数据库。当我尝试使用SQL查询时,我会丢失数据。
以下是2007年9月的一小部分原始输入:
- 登录;用户名;Server01;2007年9月10日09:56:40
- 登录;用户名;服务器02;2007年9月10日11:26:20
- 登录;用户名;Server03;2007年9月11日上午10:16:27
- 登录;用户名;服务器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
不幸的是,这正在将它们解析为
- 2007年9月10日09:56:40
- 2007年9月10日11:26:20
- 2007年11月9日10:16:27
- 2007年9月11日12:28:45
您可以看到,第三个示例,即原始数据中具有美国格式的示例,显示为11月,而不是9月11日(反转9和11(。
同样的事情正在各地发生。当我查看12月份的SQL条目时,我得到的是:
- 2007年12月7日09:53:33
- 2007年12月7日11:37:48
- 2007年7月12日13:25:02
- 2007年12月7日13:26:38
- 2007年12月7日15:04:56
你可以看到第三个不知怎么把12和7倒过来了。这就是我正在努力解决的问题。
有什么建议吗?
编辑:更多示例:
- 登录;用户名;Server01;2008年11月18日11:19:08
- 登录;用户名;服务器02;2008年11月18日上午11:21:46
- 登录;用户名;Server03;2008年11月18日14:28:30
- 登录;用户名;服务器04;2008年11月19日09:55:50
- 登录;用户名;服务器名称;2008年11月19日14:14:09
- 登录;用户名;服务器名称;2008年11月19日14:19:56
- 登录;用户名;服务器名称;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-US
或en-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