Reputation: 8711
I'm converting sql logic for finding the last working day in each month of a given year using awk. Here is my code which looks correct but runs infinitely,
awk -v year=2020 ' function dtp(_dt) { return strftime("%F", mktime(_dt " 0 0 0")) } function dtday(_dt) { return strftime("%a", mktime(_dt " 0 0 0")) } function dtmon(_dt) { return strftime("%b", mktime(_dt " 0 0 0")) }
BEGIN { ldy=strftime("%j",mktime(year " 12 31 0 0 0" ))
for(i=1;i<=ldy+0;i++)
{
df=year " " 1 " " i
if(dtday(df) != "Sun" && dtday(df) != "Sat" )
a[dtmon(df)]=dtp(df) "|" dtday(df)
}
}
END { for(i in a) print i,a[i] }
'
I think I ended up with a convoluted way of doing it. Can this be fixed or are any other simpler awk solutions possible? I'm looking for output like below.
Fri 2020-01-31 :: 2020-01-31
Sat 2020-02-29 :: 2020-02-28 # 29 is sat, so 28
Tue 2020-03-31 :: 2020-03-31
Thu 2020-04-30 :: 2020-04-30
Sun 2020-05-31 :: 2020-05-29 # 31 is Sun, so 29
Tue 2020-06-30 :: 2020-06-30
Fri 2020-07-31 :: 2020-07-31
Mon 2020-08-31 :: 2020-08-31
Wed 2020-09-30 :: 2020-09-30
Sat 2020-10-31 :: 2020-10-30 # 31 is Sat, so 30th
Mon 2020-11-30 :: 2020-11-30
Thu 2020-12-31 :: 2020-12-31
Upvotes: 0
Views: 150
Reputation: 203358
Using GNU awk for time functions, the following works because in mktime() arguments the 0th day of the next month is actually considered the last day of the current month, -1th day of next month is the 2nd-last day of the current month, the 13th month of this year is considered the 1st month of next year, etc. so invalid dates like 2021 13 -1
or the equivalent 2022 1 -1
are treated by mktime() like the valid date 2021 12 30
.
$ cat tst.awk
BEGIN {
oneDaySecs = 24 * 60 * 60
weekEndSecs["Sat"] = oneDaySecs
weekEndSecs["Sun"] = 2 * oneDaySecs
for (mthNr=2; mthNr<=13; mthNr++) {
lastDaySecs = mktime(year " " mthNr " " "0 12 0 0",1)
lastDayName = strftime("%a",lastDaySecs)
weekDaySecs = lastDaySecs - weekEndSecs[lastDayName]
print lastDayName, strftime("%F",lastDaySecs), "::", strftime("%F",weekDaySecs)
}
}
$ awk -v year=2020 -f tst.awk file
Fri 2020-01-31 :: 2020-01-31
Sat 2020-02-29 :: 2020-02-28
Tue 2020-03-31 :: 2020-03-31
Thu 2020-04-30 :: 2020-04-30
Sun 2020-05-31 :: 2020-05-29
Tue 2020-06-30 :: 2020-06-30
Fri 2020-07-31 :: 2020-07-31
Mon 2020-08-31 :: 2020-08-31
Wed 2020-09-30 :: 2020-09-30
Sat 2020-10-31 :: 2020-10-30
Mon 2020-11-30 :: 2020-11-30
Thu 2020-12-31 :: 2020-12-31
See also awk next month last date logic issue for other day-of-month calculations.
Upvotes: 3