Awk day of the week function

Yet another in my series of awk functions no-one but me will ever use:

function dow(year, month, day) {
# Modified from C Snippets "calsupp.c" public domain by Ray McVay 
# http://www8.cs.umu.se/~isak/snippets/calsupp.c
# returns 0-6 where 0 == sunday
# tested over 24000 days in range of unix timestamp, 1970-2035

    day_of_week = 0;

    if (month <= 2) {
        month += 12;
        year--;
    }
    day_of_week = (day + month * 2 + int(((month + 1) * 6) / 10) + year + int(year / 4) - int(year / 100) + int(year / 400) + 2);
    day_of_week = day_of_week % 7;
    return ((day_of_week ? day_of_week : 7) - 1);
}

Basically, all this does is calculate a Julian day number, then take its remainder modulo 7. I’d seen an example that parsed the output of ‘cal’. That’s one way of doing it; not necessarily mine.

4 comments

  1. Thank you so much.

    I write nearly everything I do in awk and I needed the day of the week for my dates.

  2. No probs. No idea if awks are Y2038 compliant. Of course I chickened out and only tested to 2035 …

  3. Scruss,
    I got a Sunday instead of Monday.

    2020 MAR 16 SUNDAY

    week_day = (day_of_week ? day_of_week : 7) – 1
    line = day_of_week ” ” week_day
    printf(string_nl, day_of_week)
    1 0

  4. Are you sure? Don’t see enough of your code to tell what you’re doing. It did pass a test harness I just wrote:

     ./testdow.sh
    Testing /usr/bin/awk from 2010-03-19 to 2030-03-19 ...
    PASSED: interpreter /usr/bin/awk over 7306 days.
    $ ./testdow.sh
    Testing /usr/bin/gawk from 2010-03-19 to 2030-03-19 ...
    PASSED: interpreter /usr/bin/gawk over 7306 days.
    $ ./testdow.sh
    Testing /usr/bin/mawk from 2010-03-19 to 2030-03-19 ...
    PASSED: interpreter /usr/bin/mawk over 7306 days.
    $ ./testdow.sh
    Testing /usr/bin/original-awk from 2010-03-19 to 2030-03-19 ...
    PASSED: interpreter /usr/bin/original-awk over 7306 days.
    

    And yes, I gave it a quick Y2038 check by running from 2000-03-19 to 2040-03-19 (14611 days) with /usr/bin/awk.

    Here’s the test harness bash script:

    #!/bin/bash
    # test awk date function for a decent time period
    # scruss - 2020-03
    
    # could be awk, gawk, mawk, original-awk
    awkbin=$(which awk)
    # awkscript is code from
    #  https://scruss.com/blog/2012/02/15/awk-day-of-the-week-function/
    # but with this line (uncommented) added:
    #  { print dow($1, $2, $3); }
    awkscript="./dow.awk"
    
    # years, split evenly
    period=20
    
    # probably don't need to change these
    count=0
    fail=0
    first=$(TZ='UTC0' date --date="$((period / 2)) years ago" +'%Y %m %d')
    last=$(TZ='UTC0' date --date="$((period / 2)) years hence" +'%Y %m %d')
    # initial value
    today=$(TZ='UTC0' date --date="${first// /-} -1 day" +'%Y %m %d')
    
    echo Testing "$awkbin" from "${first// /-}" to "${last// /-}" ...
    # compare dates as numeric YYYMMDD instead of strings
    while
        [ "${today// /}" -lt "${last// /}" ]
    do
        today=$(TZ='UTC0' date --date="${today// /-} +1 day" +'%Y %m %d')
        ddow=$(TZ='UTC0' date --date="${today// /-}" +'%w')
        adow=$(echo "$today" | "$awkbin" -f "$awkscript")
    
        if
    	[ "$ddow" -ne "$adow" ]
        then
    	fail=1
    	echo "FAILED:" "${today// /-}" "- date:" "$ddow" "- awk" "$adow" \
    	     "interpreter" "$awkbin"
        fi
        count=$((count + 1))
    done
    
    if
        [ "$fail" -eq 0 ]
    then
        echo "PASSED: interpreter" "$awkbin" "over" "$count" "days."
    fi
    

Leave a comment

Your email address will not be published. Required fields are marked *