Awk with dates until 1970

from https://www.gnu.org/software/gawk/manual/html_node/Time-Functions.html I understand that gawk has only 2 functions for working on mktime and strftime date / time.

So, I can parse any date using mktime , which return a long one, so I can do any math operator, and so I can format the output that is required with strftime

It 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 
+6
source share
2 answers

So this is a mistake ...

I am using GNU awk 4.0.2, litte look at the source and it seems easy to fix:

 glaudiston:/sources/gawk-4.0.2$ diff builtin.c.orig builtin.c 1701,1702c1701,1702 < if (clock_val < 0) < fatal(_("strftime: second argument less than 0 or too big for time_t")); --- > // if (clock_val < 0) > // fatal(_("strftime: second argument less than 0 or too big for time_t")); glaudiston:/sources/gawk-4.0.2$ echo "" | ./gawk '{ts="1969 12 31 23 00 00";format="%Y/%m/%d";tv=mktime(ts);print tv;print strftime(format, tv)}' 7200 1969/12/31 glaudiston:/sources/gawk-4.0.2$ echo "" | ./gawk '{ts="1960 01 01 00 00 00";format="%Y/%m/%d";tv=mktime(ts);print tv;print strftime(format, tv)}' -315608400 1960/01/01 

It worked for my purposes, but I'm not sure if it was a good idea. I will send this for the approval of the gallic.

Discussion has begun: https://lists.gnu.org/archive/html/bug-gawk/2015-04/msg00012.html

Solution update:

The awk dev command fixed the error, so just upgrade your awk to the new version:

https://lists.gnu.org/archive/html/bug-gawk/2015-04/msg00036.html

+1
source

Unfortunately, as you saw, gawk just can't do it directly. gawk manual says:

All well-known POSIX-compatible systems support time stamps from 0 to 2 ^ 31 - 1, which is enough to represent the time until 2038-01-19 03:14:07 UTC. Many systems support a wider range of timestamps, including negative timestamps that represent time before an era.

The manual does not indicate what strftime() does if a date is out of range.

But even on my system, which behaves reasonably for negative time_t values, the gawk strftime() function does not support them (although mktime() does), and therefore cannot process dates until 1970. I think this will be a mistake in gawk.

(My advice is to use Perl instead of Awk, but this does not answer the question you asked.)

Basically, you can invent the wheel by reimplementing a function like strftime() in awk. But that would be superfluous.

If your system has a GNU coreutils date working command, you can call it from gawk . Using your example January 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 refused to figure out the sequence of quotes and backslashes needed for this, as a single-line font from the command line).

This probably makes sense if you have a large existing awk program and you need to add this function to it. But if you are not stuck with awk with this, you might consider using something else; awk may not be the right tool for what you are trying to accomplish.

Or, if you are truly ambitious, you can change the sources of gawk to handle this case correctly.

+1
source

Source: https://habr.com/ru/post/984902/


All Articles