timezone - 在 jq 中可靠地解析日期字符串
问题描述
总体目标:将 GMT 中的字符串解析为时间,jq
并将格式化时间和该时间的差异输出到“现在”。但是,jq
s(1.6 版,Debian 测试)时区处理对我来说似乎很困惑:
$ jq --version
jq-1.6
$ date
Sa 4. Jul 19:36:08 BST 2020
$ echo '""' | jq 'now | strftime("%H:%M")'
"18:36" // OK, strftime is supposed to give GMT
$ echo '""' | jq 'now | strflocaltime("%H:%M")'
"19:36" // also OK, British Summer time is one hour ahead, strflocaltime should give local time
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | strftime("%H:%M")'
"18:14" // strptime parses GMT, so this is fine
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | strflocaltime("%H:%M")'
"18:14" // but why is this not 19:14?!
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | mktime | strftime("%H:%M")'
"19:14" // and why does "mktime" change things around?
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | mktime | strflocaltime("%H:%M")'
"20:14" // and why does strflocaltime kick in after, but not before mktime?
$ echo '"2020-07-04T18:14:12Z"' | jq 'fromdate | strftime("%H:%M")'
"19:14" // I thought fromdate was synonymous to strptime?
$ echo '"2020-07-04T18:14:12Z"' | jq 'fromdate | strflocaltime("%H:%M")'
"20:14" // I suppose this is the same issue as above with mktime
更长的版本:我正在使用 API 来显示附近火车站的到达时间,特别是我想显示接下来的几列火车以及从现在开始它们将离开的分钟数。我想用来jq
解析这些数据。数据包含格式的时间字符串"2020-07-04T18:14:12Z"
。我的理解是,两者都应该fromdate
将该数据解析为 GMT 时间戳(来自手册页:“在所有情况下,这些内置函数都专门处理 UTC 时间。”,手册页似乎可以互换使用 GMT 和 UTC)和任何操作在使用 UTC 范围内,如果使用,则只有最终输出位于本地时区。strptime
jq
jq
strflocaltime
但是,鉴于jq
上面显示的各种输入的输出,这种理解肯定是错误的。特别是,我不明白如何正确和可靠地将时间字符串解析为 GMT 时间戳,并且 b) 一旦完成,当传递到生成上面看到的输出数组时fromdate
,mktime
、now
和的输出如何分别不同。strptime
strf[local]time
编辑:进一步玩弄前两个答案的信息,主要问题似乎是fromdate
夏令时的应用(或不应用),具体取决于TZ
环境变量的设置:
$ TZ=BST jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593934737
$ TZ=Etc/UTC jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593934737
$ TZ=Europe/London jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593938337
$ TZ=Asia/Tokyo jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593934737
$ TZ=America/Los_Angeles jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593938337
$ TZ=Asia/Kathmandu jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593934737
$ unset TZ; jq -n '"2020-07-05T07:38:57Z" | fromdate'
1593938337
请注意,伦敦、洛杉矶和未设置的 TZ 获得的 Unix 纪元时间戳与东京、加德满都、UTC 和(我认为格式错误?)BST 不同。我相信这不应该发生,因为时间戳应该与时区无关。不幸的是,目前它似乎忽略了永久时区偏移(东京和加德满都给出与 UTC 相同的结果,两者都没有 DST)但它确实考虑了 DST,除非在不遵守 DST 的时区运行。
strflocaltime
,当给定时间戳时,似乎根据TZ
.
不幸的是,这似乎意味着我首先需要将 TZ 设置Etc/Utc
为才能fromdate
正常运行,然后当我想打印本地时间时,我需要重新设置TZ
为本地时区。
解决方案
我想在这里开始建立一个答案,结合不同的块:
首先,mktime
在采用“分解时间结构”时考虑 DST 但不考虑其他时区信息:
$ TZ=Etc/Utc jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593934737
$ TZ=Europe/London jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593938337
$ TZ=America/Los_Angeles jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593938337
$ TZ=Asia/Tokyo jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593934737
$ TZ=Asia/Kathmandu jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593934737
$ unset TZ; jq -n '[2020,6,5,7,38,57,0,186] | mktime'
1593938337
请注意,仅有的两个输出是 15939 34 737 或 15939 38 337,两者的差正好是 3600。
第二,fromdate
等同于strptime() | mktime
。
第三,strflocaltime
将时区偏移(永久和 DST)应用于 unix 时间戳输入,但不适用于分解时间输入:
$ TZ='Europe/London' jq -n '[2020,6,5,7,38,57,0,186] | strflocaltime("%H:%M")'
"07:38"
$ TZ='Asia/Tokyo' jq -n '[2020,6,5,7,38,57,0,186] | strflocaltime("%H:%M")'
"07:38"
$ TZ='Europe/London' jq -n '1593934737 | strflocaltime("%H:%M")'
"08:38"
$ TZ='Asia/Tokyo' jq -n '1593934737 | strflocaltime("%H:%M")'
"16:38"
第四,now
产生一个受strflocaltime
' 调整影响的 unix-timestamp 输出。
按顺序检查我原来的混淆顺序:
$ echo '""' | jq 'now | strftime("%H:%M")'
"18:36" // OK, strftime is supposed to give GMT
$ echo '""' | jq 'now | strflocaltime("%H:%M")'
"19:36" // also OK, British Summer time is one hour ahead, strflocaltime should give local time
上面的 (3) 和 (4) 对此进行了解释:now
生成一个 unix 时间戳,strflocaltime
将其调整为本地时间。
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | strftime("%H:%M")'
"18:14" // strptime parses GMT, so this is fine
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | strflocaltime("%H:%M")'
"18:14" // but why is this not 19:14?!
在这里,通过上面的 (3)strptime
产生一个不通过 , 调整的故障时间。strflocaltime
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | mktime | strftime("%H:%M")'
"19:14" // and why does "mktime" change things around?
$ echo '"2020-07-04T18:14:12Z"' | jq 'strptime("%Y-%m-%dT%H:%M:%SZ") | mktime | strflocaltime("%H:%M")'
"20:14" // and why does strflocaltime kick in after, but not before mktime?
strptime
产生故障时间,mktime
理论上应该将其转换为 unix-timestamp 时间,假设它是 UTC,但mktime
错误地应用一小时 DST 偏移量(由上面的(1)),导致strftime
产生(意外正确)本地时间和strflocaltime
– 修正永久和 DST 偏移量(通过上述 (3) ) – 再给出一个(总共两个)小时偏移量。
$ echo '"2020-07-04T18:14:12Z"' | jq 'fromdate | strftime("%H:%M")'
"19:14" // I thought fromdate was synonymous to strptime?
$ echo '"2020-07-04T18:14:12Z"' | jq 'fromdate | strflocaltime("%H:%M")'
"20:14" // I suppose this is the same issue as above with mktime
这只是 (2) 的结果,它在内部fromdate
使用mktime
。
编译 master 分支 ( a17dd32 )上的最新提交,此问题不再出现,因为mktime
不再应用一小时偏移量。这可能是由于提交3c5b1419 所致。
作为一种临时解决方法,我们可以得到mktime
with:引入的偏移量jq -n 'now | gmtime | mktime - (now | trunc)'
。从任何出现中减去此偏移量fromdate
将可靠地产生 UTC 时间戳。
推荐阅读
- javascript - wordpress 插件 JS 禁用
- java - 用java对csv文件中唯一的货币货币求和
- tomcat - 在 server.xml 中加密密钥库密码
- node.js - 使用其他路径的节点 JS 服务器代理不起作用
- c# - 我是否正确理解端口和适配器/六角架构?
- jira - Jira 搜索 - 工单 ID 以“”和其他过滤器开头
- python - Python:FileNotFoundError:[Errno 2] 没有这样的文件或目录:当目录确实存在时
- java - 如何防止使用任意方法,例如 String.lastIndexOf()
- kubernetes - 大使 API 网关不提供服务
- python - 为python程序生成突变体