#! /usr/bin/gawk -f # Last edited on 2009-12-12 00:02:37 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, for 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; days_before[13] = 366; # Just in case. split("", month_name_to_num); # Maps month name to number 1..12 month_name_to_num["Jan"] = 1; month_name_to_num["Feb"] = 2; month_name_to_num["Mar"] = 3; month_name_to_num["Apr"] = 4; month_name_to_num["May"] = 5; month_name_to_num["Jun"] = 6; month_name_to_num["Jul"] = 7; month_name_to_num["Aug"] = 8; month_name_to_num["Sep"] = 9; month_name_to_num["Oct"] = 10; month_name_to_num["Nov"] = 11; month_name_to_num["Dec"] = 12; # check_date_conversion(); } function time_from_date(yz,yr,mo,da, tt) { # Day count since Jan 01, Year {yz}. # Accepts {mo = 13} and/or {da = 0} # 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_warning(("invalid feb/29 date [" tt "] - assuming feb/28"), 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++; } } } }