from https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html
I understand that gawk
has only 2 functions to work on date/time
mktime
and strftime
.
So, I can parse any date using mktime
that return a long, so I can make any math op, and so I can format the output desired with strftime
This works like a charm for any date after "1970 01 01 00 00 00"
Using awk, how can I format dates before 1970 ?
$ awk 'BEGIN{t=mktime("1970 01 01 00 00 00"); print t; print strftime("%Y-%m-%d", t) }'
10800
1970-01-01
$ awk 'BEGIN{t=mktime("1960 01 01 00 00 00"); print t; print strftime("%Y-%m-%d", t) }'
-315608400
awk: cmd. line:1: (FILENAME=- FNR=1) fatal: strftime: second argument less than 0 or too big for time_t
Unfortunately, as you've seen, gawk just can't do this directly. The gawk manual says:
All known POSIX-compliant systems support timestamps from 0 through 2^31 - 1, which is sufficient to represent times through 2038-01-19 03:14:07 UTC. Many systems support a wider range of timestamps, including negative timestamps that represent times before the epoch.
The manual doesn't say what strftime()
does if given an out-of-range date.
But even on my system, which does behave sensibly for negative time_t
values, gawk's strftime()
function doesn't support them (though mktime()
does), and so can't handle dates before 1970. I consider this to be a bug in gawk.
(My advice would be to use Perl instead of Awk, but that doesn't answer the question you asked.)
In principle, you could reinvent the wheel by re-implementing a function like strftime()
in awk. But that would be overkill.
If your system has a working GNU coreutils date
command, you can invoke it from gawk
. Using your example of Jan 1, 1960:
$ cat 1960.awk
#!/usr/bin/awk -f
BEGIN {
timestamp = mktime("1960 00 00 00 00 00")
print "mktime() returned " timestamp
if (0) {
# This doesn't work
s = strftime("%Y-%m-%d %H:%M:%S", timestamp)
print "strftime() returned ", s
}
else {
# This works
"date '+%Y-%m-%d %H:%M:%S' -d @" timestamp | getline t
print "The date command printed \"" t "\""
}
}
$ ./1960.awk
mktime() returned -318355200
The date command printed "1959-11-30 00:00:00"
$
(I gave up on figuring out the sequence of quotes and backslashes needed to do this as a one-liner from a shell prompt.)
This probably makes sense if you have a large existing awk program and you need to add this one feature to it. But if you're not stuck with doing this in awk, you might consider using something else; awk may not be the right tool for what you're trying to accomplish.
Or, if you're really ambitious, you could modify the gawk
sources to handle this case correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With