我有一个问题,试图获得准确的GPS时间。看起来该问题与代码中使用的命令mktime
有关。
为了获得正确的GPS时间,我在UTC中增加了-2小时。
但目的是让代码自动计算GPS时间,并且不要在UTC-2上手动更改为例
输入文件GMT时间(当地时间> 3小时)
18/05/21 08:18:29
18/05/21 08:20:25
18/05/21 08:21:02
当我运行下面的代码时,减少了1个小时:
gawk -F'[/: ]' -v ts=$(date -d'01/06/1980' +%s) \
-v lap=18 '{$1="" d=sprintf(20$0);
print mktime(d)+lap-ts }' file
结果输出GPS时间(< 1小时)
1210922327
1210922443
1210922480
当我运行下面的代码时,得到了正确的GPS时间。
gawk -F'[/: ]' -v ts=$(TZ=UTC-2 date -d'1/6/1980 0:00' +%s) \
-v lap=18 '{$1="" d=sprintf(20$0);
print mktime(d)+lap-ts }' file
结果输出GPS TIME(确切时间:OUTPUT DESIRED)
1210925927
1210926043
1210926080
提前致谢
答案 0 :(得分:3)
您遇到的问题主要与系统的时区设置有关。由于Daylight Saving Time,您的时区会移动一小时,从而导致出现差异。可以找到一个检测DST的非常好的帖子here。复制其示例,我们可以显示,对于时区 TZ = Europe / Stockholm ,时区会根据日期更改为夏令时:
$ TZ=Europe/Stockholm date +%Z # CET or CEST depending of when its run
$ TZ=Europe/Stockholm date --date=20170101 +%Z # CET
$ TZ=Europe/Stockholm date --date=20170601 +%Z # CEST
$ TZ=CET date --date=20170101 +%Z # CET
$ TZ=CET date --date=20170601 +%Z # CEST, note that its auto adjusted to CEST
因此肯定会对 1970-01-01T00:00:00 UTC 给出的纪元时间产生影响。使用zdump
时,我们会看到DST何时生效:
$ zdump -v /usr/share/zoneinfo/Europe/Stockholm | grep 2018
/usr/share/zoneinfo/Europe/Stockholm Sun Mar 25 00:59:59 2018 UTC = Sun Mar 25 01:59:59 2018 CET isdst=0 gmtoff=3600
/usr/share/zoneinfo/Europe/Stockholm Sun Mar 25 01:00:00 2018 UTC = Sun Mar 25 03:00:00 2018 CEST isdst=1 gmtoff=7200
/usr/share/zoneinfo/Europe/Stockholm Sun Oct 28 00:59:59 2018 UTC = Sun Oct 28 02:59:59 2018 CEST isdst=1 gmtoff=7200
/usr/share/zoneinfo/Europe/Stockholm Sun Oct 28 01:00:00 2018 UTC = Sun Oct 28 02:00:00 2018 CET isdst=0 gmtoff=3600
这可以在纪元时间看到:
$ TZ=Europe/Stockholm date -d "2018-03-25 01:59:59" +%s
1521939599
$ TZ=Europe/Stockholm date -d "2018-03-25 03:00:00" +%s
1521939600
$ TZ=Europe/Stockholm date -d "2018-03-25 02:00:00" +%s
date: invalid date ‘2018-03-25 02:00:00’
如您所见,对于 TZ = Europe / Stockholm ,时间 2018-03-25T02:00:00 不存在,其他两个只有1秒开。
总结,这一切意味着什么:它实质上意味着您的系统会自动补偿DST,除非您的TZ是UTC。这会在所有与日期相关的命令中发挥作用,例如systime()
,date
甚至是Awk' mktime()
。
我们可以使用awk
来避免DST补偿吗?
由于OP需要GPS时间,即自1980-01-06T00:00:00以来的总秒数,因此基本上减去两次。因此,如果在没有DST校正的情况下在相同的TZ中计算两者,则始终获得正确的结果。有两种方法可以做到这一点:
在特定时区执行您的命令: 通过强制系统在单个TZ(例如UTC,UTC + 2,...)中工作,将不会进行DST校正。对于OP的问题,感兴趣的TZ是UTC。
$ TZ="UTC" awk 'BEGIN { ts = mktime("1980 01 06 00 00 00") }
{ datespec="20"$0; gsub(/[/:]/," ",datespec);
print mktime(datespec) + lap - ts
}' lap=18 file
或从awk 4.20
开始,您可以通过使用UTC标志告诉mktime()
假设日期是UTC。 (mktime(datespec [, utc-flag ])
)
$ awk 'BEGIN { ts = mktime("1980 01 06 00 00 00",1) }
{ datespec="20"$0; gsub(/[/:]/," ",datespec);
print mktime(datespec,1) + lap - ts
}' lap=18 file
都会产生以下输出。
1210925927
1210926043
1210926080
在这两种情况下,您都不必担心您的系统时区以及与夏令时相关的所有mumbo-jumbo。
使用mktime
停用DST更正:向DST
的{{1}}部分添加datespec
条目时,您可以告诉alwy的系统是否在DST中工作或让系统自己解决。后者是你做不想要的。 mktime
是datespec
形式的字符串。这也让它失望了:
YYYY MM DD HH MM SS [DST]
$ awk 'BEGIN { ts = mktime("1980 01 06 00 00 00 0") }
{ datespec="20"$0; gsub(/[/:]/," ",datespec);
print mktime(datespec" 0") + lap - ts
}' lap=18 file
awk 4.2.0以后的文档:
mktime(datespec [, utc-flag ])
将mktime
转换为与datespec
返回的格式相同的时间戳。它类似于ISO C中相同名称的功能。参数systime()
是datespec
形式的字符串。该字符串由六个或七个数字组成,分别代表包括世纪的全年,从1到12的月份,从1到31的月份的一天,从0到23的一天的小时,从0到0的分钟59,第二个从0到60,55和可选的夏令时标志。这些数字的值不必在指定的范围内;例如,一小时-1表示午夜前1小时。假设原点为零的公历,在第1年之前的第0年和第0年之前的第1年。如果存在
"YYYY MM DD HH MM SS [DST]"
并且非零或非空,则假定时间为在UTC时区;否则,假定时间在本地时区。如果utc-flag
夏令时标志为正,则假定时间为夏令时;如果为零,则假定时间为标准时间;如果为负数(默认值),DST
会尝试确定夏令时是否在指定时间内有效。如果
mktime()
未包含足够的元素,或者结果时间超出范围,则datespec
会返回mktime()
。