What you are encountering is mostly related to the time-zone settings of your system. Due to Daylight Saving Time, your time-zone shifted one hour which causes the discrepancy. A very nice post of detecting DST, can be found here. Copying its examples, we can show that for the time-zone TZ=Europe/Stockholm, the time-zone changes to summer time depending on the date :
$ 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
and therefore it will for sure have an effect on the epoch time which is given from 1970-01-01T00:00:00 UTC. With zdump
we see when DST comes into affect :
$ 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
and this is seen in the epoch time as :
$ 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’
As you see, for TZ=Europe/Stockholm, the time 2018-03-25T02:00:00 does not exist and the other two are only 1 sec apart.
Summary, what does this all mean: it essentially means that your system automatically compensates for DST, unless your TZ is UTC. And this play a role on all date related command such as systime()
, date
or even Awk's mktime()
.
Can we avoid DST compensation with awk
:
Since the OP wants the GPS-time, i.e. the total seconds since 1980-01-06T00:00:00, you essentially subtract two times. So if both are computed in the same TZ without DST correction, you always get the correct result. There are 2 ways to do this :
execute your command in a specific timezone:
By forcing the system to work in a single TZ (such as UTC, UTC+2, ...), there will be no DST correction. For the OP's question, the TZ of interest is 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
or from awk 4.20
onwards you can tell mktime()
to assume that the date is in UTC by using the UTC flag. (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
both result in the following output.
1210925927
1210926043
1210926080
In both cases, you don't need to worry about your system-timezone and all the mumbo-jumbo related to daylight savings time.
disable DST correction with mktime
: When adding a DST
entry to the datespec
part of mktime
, you can tell the system to alwyas work in DST or not or let the system figure it out by himself. The latter is what you do not want. datespec
is a string of the form YYYY MM DD HH MM SS [DST]
. And this brings it down too:
$ 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
Documentation for mktime
awk 4.2.0 onwards:
mktime(datespec [, utc-flag ])
Turn datespec
into a timestamp in the same form as is returned by systime()
. It is similar to the function of the same name in ISO C. The argument, datespec
, is a string of the form "YYYY MM DD HH MM SS [DST]"
. The string consists of six or seven numbers representing, respectively, the full year including century, the month from 1 to 12, the day of the month from 1 to 31, the hour of the day from 0 to 23, the minute from 0 to 59, the second from 0 to 60,55 and an optional daylight-savings flag.
The values of these numbers need not be within the ranges specified; for example, an hour of -1 means 1 hour before midnight. The origin-zero Gregorian calendar is assumed, with year 0 preceding year 1 and year -1 preceding year 0. If utc-flag
is present and is either non-zero or non-null, the time is assumed to be in the UTC time zone; otherwise, the time is assumed to be in the local time zone. If the DST
daylight-savings flag is positive, the time is assumed to be daylight savings time; if zero, the time is assumed to be standard time; and if negative (the default), mktime()
attempts to determine whether daylight savings time is in effect for the specified time.
If datespec
does not contain enough elements or if the resulting time is out of range, mktime()
returns -1
.