# function to convert from Local time zone date/time to
# Universal Coordinated Time, UCT, formly
# known as GMT. Environment string of form:
# SET TZ=EST5EDT
# necssary.
# Parameters:
# sjdn == local date as Julian Day Number
# lsecs == local time as returned by '_time'
# built-in function, seconds since midnight
# Returns
# gmtime == array
# gmtime[0] == Julian Day Number, UCT
# gmtime[1] == seconds since midnight UCT
# gmtime[2] == Time Zone name
# gmtime[3] == Daylight Savings Time Zone name, if any
#
function to_UCT(sjdn,lsecs)
{
local TZ = /TZ{_w}*={_w}*/;
local tzn = /([A-Za-z]{3,3})/;
local digits = /({_d}{1,2})/;
local hrs = /([-+]?){digits}/;
local min_sec = /(:{digits})?/;
local time_zone_setting = /{TZ}{tzn}{hrs}{min_sec}{min_sec}{tzn}?/;
local tz;
local conversion_factor, sign;
local gmtime;
# determine if time zone information in environment, specifically
# environment variable 'TZ'
for ( tz in ENVIRON ) {
if ( ENVIRON[tz] ~~ time_zone_setting ) {
# Found time zone environment variable with time zone correction.
# Correction in tagged strings for "ENVIRON[tz]"
# time zone name in: ENVIRON[tz][<1>][<1>]
# correction sign in: ENVIRON[tz][<1>][<2>]
# hour correction in: ENVIRON[tz][<1>][<3>]
# optional minute correction in: ENVIRON[tz][<2>][<2>]
# optional seconds correction in: ENVIRON[tz][<2>][<3>]
# optional daylight saving time name in: ENVIRON[tz][<1>][<6>]
gmtime[2] = ENVIRON[tz][<1>][<1>];
gmtime[3] = ENVIRON[tz][<1>][<6>];
sign = (ENVIRON[tz][<1>][<2>] >< "1") + 0;
conversion_factor = ((ENVIRON[tz][<1>][<3>] * 60) + ENVIRON[tz][<2>][<2>]) * 60
+ ENVIRON[tz][<2>][<3>];
conversion_factor *= sign;
break;
}
} ## endfor
if ( conversion_factor ) {
# test for DST in local time zone
if ( gmtime[3] ) {
conversion_factor += DST_Adjust(sjdn,lsecs) * 3600;
} ## endif
if ( (gmtime[1] = lsecs + conversion_factor) < 0 ) gmtime[1] += 86400;
else gmtime[1] %= 86400;
gmtime[0] = sjdn;
if ( (conversion_factor > 0) && (gmtime[1] < lsecs) ) {
gmtime[0]++;
} else if ( (conversion_factor < 0) && (gmtime[1] > lsecs) ) {
gmtime[0]--;
} ## endif
} ## endif
return gmtime;
}
# Function to determine if Daylight Savings Time, DST,
# in effect. In the US, DST starts at 0200 hours on the
# first Sunday in April and ends at 0200 Hours on the last
# Sunday of October
function DST_Adjust(sjdn,lsecs)
{
# break specified JDN into calender date
local cdate = jdn(sjdn);
local AS, OS;
local DST_adj;
# compute JDN for 1st Sunday of April
AS = jdn(cdate[0],3,31) + month_day_date(4,1,0,cdate[0]);
# compute JDN for last Sunday of October
OS = jdn(cdate[0],9,30) + last_dow_of_month(10,0,cdate[0]);
# assume DST in effect
DST_adj = 1;
# test if assumption correct
if ( (sjdn < AS) || (sjdn > OS) ) DST_adj = 0;
else if ( (sjdn == AS) && (lsecs < 7200) ) DST_adj = 0;
else if ( (sjdn == OS) && (lsecs > 7200) ) DST_adj = 0;
return DST_adj;
}
#
# Function to compute day of month for the nth occurrence
# of a specified day of the week, dow, for the month and
# year specified.
# Parameters:
# month, 1 <= m <= 12
# occurrence, 1 <= w <= 5
# day of week (0 == Sunday, 6 == Saturday)
# year
# e.g., want day of month for the second Thursday
# in September for 1996. Pass:
# month == 9 (September)
# occurrence == 2
# dow == 4 (Thursday)
# year == 1996
function month_day_date(month,occur,dow,year)
{
local day_incr = (occur - 1) * 7,
dow_first = (auto_jdn(year,month,1) + 1) % 7;
local addit = (dow_first <= dow) ? 1 : 8;
return (dow - dow_first + addit + day_incr);
}
# Function to compute day of month for the day of week, dow, specified
# Parameters:
# month, 1 <= month <= 12
# dow, 0 <= dow <= 6
# year
# E.g., find last thursday in month of October, 1996. Pass:
# month == 10
# dow == 4
# year == 1996
function last_dow_of_month(month,dow,year)
{
local jdn_first = auto_jdn(year,month,1); # compute JDN of first day of desired month
local dow_first = (jdn_first + 1) % 7; # compute DoW of first day of desired month
local jdn_nfirst, # JDN of first day of next month
dow_last, # DoW of last day of desired month
dm, # number of days in desired month
nm = (month + 1) % 13, # next month number
ny = year, # year of next month
addit; # additive factor
# set year and month number for month after desired month, next month
if ( !nm ) {
nm++;
ny++;
} ## endif
# compute JDN for first day of next month
jdn_nfirst = auto_jdn(ny,nm,1);
# compute DOW for last day of desired month
dow_last = jdn_nfirst % 7;
# compute number of days in desired month
dm = jdn_nfirst - jdn_first;
addit = (dow <= dow_last) ? 0 : 7;
return (dm - addit - (dow_last - dow));
}