летнее время влияет на результат mktime - PullRequest
0 голосов
/ 23 мая 2018

У меня проблема с попыткой получить точное время GPS.Похоже, проблема связана с командой mktime, используемой в коде.Чтобы получить правильное время GPS, я добавил -2 часа в UTC.

Но цель состоит в том, чтобы иметь код для автоматического расчета времени GPS и не использовать ручные изменения в UTC-2 в качестве примера

Входной файл по времени по Гринвичу (> 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 часа) </strong>

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 (точно время: ВЫХОД желаемый)

1210925927
1210926043
1210926080

Заранее спасибо

1 Ответ

0 голосов
/ 23 мая 2018

То, с чем вы сталкиваетесь, в основном связано с настройками часового пояса вашей системы.Из-за перехода на летнее время ваш часовой пояс сместился на один час, что вызывает расхождение.Очень хороший пост обнаружения 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...