#! /usr/bin/gawk -f # Last edited on 2009-12-12 00:01:40 by stolfi # GAWK library ment to be included in other GAWk programs with "-f" function date_time_init() { # To be called before any other proc of this package. split("", days_before); # Days in year before 1st of each month, leap years. days_before[ 1] = 0; days_before[ 2] = 31; days_before[ 3] = 60; days_before[ 4] = 91; days_before[ 5] = 121; days_before[ 6] = 152; days_before[ 7] = 182; days_before[ 8] = 213; days_before[ 9] = 244; days_before[10] = 274; days_before[11] = 305; days_before[12] = 335; # check_date_conversion(); } function time_from_date(yz,yr,mo,da, tt) { # Day count since Jan 01, Year {yz}. # First assume that all years are leap years: tt = (yr-yz)*366 + days_before[mo] + (da-1); tt = unleap_year_adjust(yz,tt); return tt; } function date_from_time(yz,tt, tx,yr,mo,da) { # Convert day count back to date in format "{YEAR} {MONTH} {DAY}". # Adjust {tt} by inserting a feb/29 in eevry non-leap year: tx = unleap_year_unadjust(yz,tt); # Now split {tt} assuming all years are leap years: yr = yz + int(tx/366); tx = tx % 366; mo = 1; while ((mo < 12) && (tx >= days_before[mo+1])) { mo++; } da = tx - days_before[mo] + 1; # Consistency check: tz = time_from_date(yz,yr,mo,da); if (tz != tt) { data_error(("date bug [" tt " --> " yr "-" mo "-" da "]"), lin); } return sprintf("%04d %02d %02d", yr, mo, da); } function unleap_year_adjust(yz,tt, k,yk,tk) { # The leap years were ..., 2000, 2004, 2008, 2012, ... # Slow but at least it works. for (k = 30; k >= 0; k--) { yk = yz + k; if ((yk % 4) != 0) { # Compute and exclude 29 feb: tk = k*366 + 31 + 28; if (tt == tk) { data_error(("invalid date [" tt " --> " yr "-" mo "-" da "]"), lin); } if (tt > tk) { tt--; } } } return tt; } function unleap_year_unadjust(yz,tt, k,yk,tk) { # The leap years were ..., 2000, 2004, 2008, 2012, ... # Slow but at least it works. for (k = 0; k <= 30; k++) { yk = yz + k; if ((yk % 4) != 0) { # Compute and include dummy 29 feb: tk = k*366 + 31 + 28; if (tt >= tk) { tt++; } } } return tt; } function date_time_sanity_check(yz, yr,mo,da,du,tt,dt1,dt2,tk) { # Testing date conversion printf "\n" > "/dev/stderr"; tk = 0; for (yr = yz; yr < yz + 10; yr++) { printf "--- %s ---\n", yr > "/dev/stderr"; for (mo = 1; mo <= 12; mo++) { # Compute month's duration {du}: du = 31; if (mo == 2) { du = 28 + (yr % 4 == 0); } else if ((mo == 4) || (mo == 6) || (mo == 9) || (mo == 11)) { du = 30; } for (da = 1; da <= du; da++) { tt = time_from_date(yz,yr,mo,da); dt1 = sprintf("%04d %02d %02d", yr, mo, da) dt2 = date_from_time(yz,tt); printf "%s --> %8d --> %s\n", dt1, tt, dt2 > "/dev/stderr"; if (tk != tt) { data_error(("date bug [" tk "] [" tt "]"), lin); } if (dt1 != dt2) { data_error(("date bug [" dt1 "] [" dt2 "]"), lin); } tk++; } } } }