То, с чем вы сталкиваетесь, в основном связано с настройками часового пояса вашей системы.Из-за перехода на летнее время ваш часовой пояс сместился на один час, что вызывает расхождение.Очень хороший пост обнаружения DST, можно найти здесь .Копируя его примеры, мы можем показать, что для часового пояса TZ = Европа / Стокгольм часовой пояс меняется на летнее время в зависимости от даты:
$ 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 =Европа / Стокгольм , время 2018-03-25T02: 00: 00 не существует, а два других разнесены всего на 1 секунду.
Резюме, что все это значит: это, по сути, означает, что ваша система автоматически компенсирует DST, если ваш TZ не является UTC.И это играет роль для всех команд, связанных с датами, таких как systime()
, date
или даже Awk's mktime()
.
Можем ли мы избежать компенсации DST с помощью awk
: Поскольку OP требует времени GPS, то есть общее количество секунд с 1980-01-06T00: 00: 00, вы, по сути, вычитаете два раза.Таким образом, если оба вычисляются в одном и том же TZ без коррекции DST, вы всегда получите правильный результат.Есть 2 способа сделать это:
выполнить вашу команду в определенном часовом поясе : принудительно заставить систему работать в одном TZ (таком как UTC, UTC+2, ...), коррекции DST не будет.Для вопроса ОП интересующим 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
и далее, вы можете указать mktime()
, что предполагается, что дата указана в UTC с использованием флага 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
В обоих случаях вам не нужно беспокоиться о системном часовом поясе и обо всем этом.-jumbo, связанный с переходом на летнее время.
отключить коррекцию летнего времени с помощью mktime
: при добавлении записи DST
в datespec
часть mktime
, вы можете указать системе, чтобы она всегда работала в DST или нет, или позволить системе разобраться самому.Последнее - это то, что вы делаете , а не хотите.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
Документация для mktime
awk 4.2.0 и более поздних версий:
mktime(datespec [, utc-flag ])
Превратите datespec
в метку времени в той же форме, что и systime()
.Это похоже на функцию с тем же именем в ISO C. Аргумент datespec
- это строка вида "YYYY MM DD HH MM SS [DST]"
.Строка состоит из шести или семи чисел, представляющих, соответственно, полный год, включая столетие, месяц от 1 до 12, день месяца от 1 до 31, час дня от 0 до 23, минуты от 0 до59, второе от 0 до 60,55 и необязательный флаг перехода на летнее время.
Значения этих чисел не обязательно должны находиться в указанных диапазонах;например, час -1 означает 1 час до полуночи.Предполагается, что в исходном нулевом григорианском календаре год 0 предшествует году 1, а год -1 предшествует году 0. Если присутствует utc-flag
, и оно ненулевое или ненулевое, время считается равнымчасовой пояс UTC;в противном случае предполагается, что время находится в местном часовом поясе. Если флаг перехода на летнее время DST
положительный, предполагается, что это летнее время;если ноль, время считается стандартным временем;и если отрицательное (по умолчанию), mktime()
пытается определить, действует ли переход на летнее время в течение указанного времени.
Если datespec
не содержит достаточного количества элементов или если получающееся время выходит за пределы допустимого диапазонаmktime()
возвращает -1
.