PowerShell使用-like匹配可排序格式JSON日期为何需用美式日期格式?
PowerShell日期筛选格式不匹配问题
我在JSON文件中存储了符合-s(可排序)规范的日期数据,首条记录的对应字段为:
"DTSlocal": "2012-11-10T08:09:35"
该时间对应本地时间2012年11月10日08:09:35。
加载文件并通过ConvertFrom-Json转换为PowerShell对象(赋值为$data)后,查看上述样本值的返回结果为:
$data[0].DTSlocal Saturday, 10 November 2012 8:09:35 AM
转换结果看似正常,但尝试筛选该日期的所有数据时,执行以下语句出现异常:
$data | Where-Object -Property DTSlocal -LIKE '10/11/2012*' # 执行失败,无返回结果 $data | Where-Object -Property DTSlocal -LIKE '11/10/2012*' # 可以正常返回结果
当前系统区域文化已正确设置为“澳大利亚”,日期格式配置为d-MM-yyyy等本地规范。
为何必须使用“美式”日期格式才能完成搜索,是操作方式有误吗?
补充测试示例
更新01: 应要求补充测试示例,以下为此前测试时使用的操作方式(未采用后续给出的解决方案),可供其他用户参考了解问题成因,后续会测试建议方案并反馈结果。
测试用样本文件 tinySample.json 内容如下:
[ { "DTSorig": "2012-11-09T21:09:35.612Z", "DTSlocal": "2012-11-10T08:09:35", "Latitude": -39.9526772, "Longitude": 146.8924461, "Source": "WIFI", "Accuracy": 24 }, { "DTSorig": "2012-11-09T21:11:32.285Z", "DTSlocal": "2012-11-10T08:11:32", "Latitude": -36.8526772, "Longitude": 142.8924487, "Source": "WIFI", "Accuracy": 23 } ]
PowerShell测试操作如下:
$data = Get-Content .\tinySample.json | ConvertFrom-Json # 快速查看PS对象的属性值: $data DTSorig : 9/11/2012 9:09:35 PM DTSlocal : 10/11/2012 8:09:35 AM Latitude : -39.9526772 Longitude : 146.8924461 Source : WIFI Accuracy : 24 DTSorig : 9/11/2012 9:11:32 PM DTSlocal : 10/11/2012 8:11:32 AM Latitude : -36.8526774 Longitude : 142.8924487 Source : WIFI Accuracy : 23 # 查找2012年11月10日的所有值 $data | Where-Object -Property DTSlocal -LIKE '10/11/2012*' # 无返回结果 $data | Where-Object -Property DTSlocal -LIKE '11/10/2012*' # 返回上述全部2条记录
问题原因
该现象是PowerShell中-like操作符处理DateTime类型值的默认行为导致,与系统区域设置无关:
ConvertFrom-Json识别到ISO 8601格式的日期字符串时,会自动将其转换为[DateTime]类型的结构化对象,不会保留原始字符串值- 对
DateTime类型属性使用-like做字符串匹配时,PowerShell会先调用该对象的无参.ToString()方法做隐式字符串转换,这个转换默认使用PowerShell进程级别的固定文化设置(en-US美式文化),不会跟随系统配置的澳大利亚区域格式 - 控制台直接输出
$data时看到的10/11/2012 8:09:35 AM格式,是PowerShell输出系统针对当前会话文化做的格式化展示结果,和-like匹配时隐式转换使用的格式不是同一套逻辑,因此会出现“展示为日/月/年格式,匹配时却需按月/日/年书写”的错位问题。
解决方法
不要依赖隐式字符串转换做日期筛选,直接按日期时间类型做判断,既不受区域格式影响,逻辑也更可靠:
# 筛选2012年11月10日当天的所有记录 $targetDate = Get-Date '2012-11-10' $data | Where-Object { $_.DTSlocal.Date -eq $targetDate.Date }
如果确实需要用字符串匹配的方式,要显式指定目标格式做转换,避免隐式转换的文化问题:
# 显式按dd/MM/yyyy格式转字符串后再匹配 $data | Where-Object { $_.DTSlocal.ToString('dd/MM/yyyy') -eq '10/11/2012' }
内容的提问来源于stack exchange,提问作者dwids
相关产品推荐
相关产品推荐

