time utilities (#44)(an instance of Generic Utilities Package made by Hacker)      Converting from seconds-since-1970      dhms (time) => string ...DD:HH:MM:SS      english_time (time[, reference time)=> string of y, m, d, m, s             Converting to seconds      to_seconds ("hh:mm:ss") => seconds since 00:00:00      from_ctime (ctime) => corresponding time-since-1970      from_day (day_of_week, which) => time-since-1970 for the given day*      from_month (month, which) => time-since-1970 for the given month*       (* the first midnight of that day/month)      parse_english_time_interval("n1 u1 n2 u2...")       => seconds in interval      seconds_until_time("hh:mm:ss") => number of seconds from now until then      seconds_until_date("month",day,"hh:mm:ss",flag       => number of seconds from now until then       (see verb help for details)             Converting to some standard English formats      day ([c]time) => what day it is      month ([c]time) => what month it is      ampm ([c]time[, precision]) => what time it is, with am or pm      mmddyy ([c]time) => date in format MM/DD/YY      ddmmyy ([c]time) => date in format DD/MM/YY             Substitution      time_sub (string, time) => substitute time information             Miscellaneous      sun ([time]) => angle between sun and zenith      dst_midnight (time) VERB SOURCE CODE: day:
"Given a time() or ctime()-style date, this returns the full name of the day.";
if (typeof(args[1]) == NUM)
time = ctime(args[1]);
elseif (typeof(args[1]) == STR)
time = args[1];
else
return E_TYPE;
endif
dayabbr = $string_utils:explode(time)[1];
return this.days[dayabbr in this.dayabbrs];
.
month:
"Given a time() or ctime()-style date, this returns the full name";
"of the month.";
if (typeof(args[1]) == NUM)
time = ctime(args[1]);
elseif (typeof(args[1]) == STR)
time = args[1];
else
return E_TYPE;
endif
monthabbr = $string_utils:explode(time)[2];
return this.months[monthabbr in this.monthabbrs];
.
ampm:
"Return a time in the form [h]h[:mm[:ss]] {a.m.|p.m.}. Args are";
"[1] either a time()- or a ctime()-style date, and";
"[2] (optional) the precision desired--1 for hours, 2 for minutes,";
" 3 for seconds. If not given, precision defaults to minutes";
if (typeof(args[1]) == NUM)
time = ctime(args[1]);
elseif (typeof(args[1]) == STR)
time = args[1];
else
return E_TYPE;
endif
if (length(args) > 1)
precision = args[2];
else
precision = 2;
endif
time = $string_utils:explode(time)[4];
hour = tonum(time[1..2]);
if (hour == 0)
time = ("12" + time[3..(precision * 3) - 1]) + " a.m.";
elseif (hour == 12)
time = time[1..(precision * 3) - 1] + " p.m.";
elseif (hour > 12)
time = (tostr(hour - 12) + time[3..(precision * 3) - 1]) + " p.m.";
else
time = (tostr(hour) + time[3..(precision * 3) - 1]) + " a.m.";
endif
return time;
.
to_seconds: "Given string hh:mm:ss ($string_utils:explode(ctime(time))[4]), this returns"; "the number of seconds elapsed since 00:00:00. I can't remember why I"; "created this verb, but I'm sure it serves some useful purpose."; return (((60 * 60) * tonum(args[1][1..2])) + (60 * tonum(args[1][4..5]))) + tonum(args[1][7..8]); . sun:
r = 10000;
h = (r * r) + (r / 2);
time = (args == {}) ? time() | args[1];
t = ((time + 120) % 86400) / 240;
s = (5 * ((time - 14957676) % 31556952)) / 438291;
phi = (s + t) + this.corr;
cs = $trig_utils:cos(s);
spss = ((($trig_utils:sin(phi) * $trig_utils:sin(s)) + h) / r) - r;
cpcs = ((($trig_utils:cos(phi) * cs) + h) / r) - r;
return (((((this.stsd * cs) - (this.ctcd * cpcs)) - (this.ct * spss)) + h) / r) -
r;
.
from_ctime:
"Given a string such as returned by ctime(), return the corresponding time-in-seconds-since-1970
time returned by time(), or E_DIV if the format is wrong in some essential way.";
words = $string_utils:explode(args[1]);
if (length(words) == 5)
"Arrgh! the old ctime() didn't return a time zone, yet it arbitrarily decides
whether it's standard or daylight savings time. URK!!!!!";
words = listappend(words, "PST");
endif
if ((((length(words) != 6) || (length(hms = $string_utils:explode(words[4], ":"))
!= 3)) || (!(month = words[2] in this.monthabbrs))) || (!(zone = $list_utils:assoc(words[6],
this.timezones))))
return E_DIV;
endif
year = tonum(words[5]);
day = ({-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}[month] + tonum(words[3]))
+ (year * 366);
zone = zone[2];
return (((((((((((((day - ((day + 1038) / 1464)) - ((day + 672) / 1464)) - ((day
+ 306) / 1464)) - ((day + 109740) / 146400)) - ((day + 73140) / 146400)) - ((day
+ 36540) / 146400)) - 719528) * 24) + tonum(hms[1])) + zone) * 60) + tonum(hms[2]))
* 60) + tonum(hms[3]);
.
dhms dayshoursminutesseconds:
s = args[1];
if (s < 0)
return "-" + this:(verb)(-s);
endif
m = s / 60;
s = s % 60;
if (m)
ss = tostr((s < 10) ? ":0" | ":", s);
h = m / 60;
m = m % 60;
if (h)
ss = tostr((m < 10) ? ":0" | ":", m, ss);
d = h / 24;
h = h % 24;
return tostr(@d ? {d, (h < 10) ? ":0" | ":"} | {}, h, ss);
else
return tostr(m, ss);
endif
else
return tostr(s);
endif
.
english_time:
"english_time(time [,reference time]): returns the time as a string of";
"years, months, days, minutes and seconds using the reference time as the";
"start time and incrementing forwards. it can be given in either ctime() or";
"time() format. if a reference time is not given, it is set to time().";
"suspend(0)";
if ((_time = args[1]) < 1)
return "0 seconds";
endif
reftime = (length(args) > 1) ? args[2] | time();
_ctime = (typeof(reftime) == NUM) ? ctime(reftime) | reftime;
seclist = {60, 60, 24};
units = {"year", "month", "day", "hour", "minute", "second"};
timelist = {};
for unit in (seclist)
timelist = {_time % unit, @timelist};
_time = _time / unit;
endfor
months = 0;
month = _ctime[5..7] in $time_utils.monthabbrs;
year = tonum(_ctime[21..24]);
"the following should really be a verb/property. attribution: the ";
"algorithm used is from the eminently eminent g7.";
monthlen = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
while (_time >= (days = monthlen[month] + (((month == 2) && ((year % 4) == 0)) &&
(!((year % 400) in {100, 200, 300})))))
_time = _time - days;
months = months + 1;
if ((month = month + 1) > 12)
year = year + 1;
month = 1;
endif
endwhile
timelist = {months / 12, months % 12, _time, @timelist};
for unit in (units)
i = unit in units;
if (timelist[i] > 0)
units[i] = ((tostr(timelist[i]) + " ") + units[i]) + ((timelist[i] == 1)
? "" | "s");
else
units = listdelete(units, i);
timelist = listdelete(timelist, i);
endif
endfor
"suspend(0)";
return $string_utils:english_list(units);
.
from_day:
"from_day(day_of_week,which)";
"numeric time (seconds since 1970) corresponding to midnight (PST) of the given weekday.
Use either the name of the day or a 1..7 number (1==Sunday,...)";
" which==-1 => use most recent such day.";
" which==+1 => use first upcoming such day.";
" which==0 => use closest such day.";
"larger (absolute) values for which specify a certain number of weeks into the future
or past.";
if (!(tonum(day = args[1]) || (day = $string_utils:find_prefix(day, this.days))))
return E_DIV;
endif
delta = {288000, 374400, 460800, 547200, 28800, 115200, 201600}[tonum(day)];
time = time() - delta;
dir = {@args, 0}[2];
if (dir)
time = (time / 604800) + ((dir > 0) ? dir | (dir + 1));
else
time = (time + 302400) / 604800;
endif
return (time * 604800) + delta;
.
from_month:
"from_month(month,which[,d])";
"numeric time (seconds since 1970) corresponding to midnight (PST) of the dth (first)
day of the given month. Use either the month name or a 1..12 number (1==January,...)";
" which==-1 => use most recent such month.";
" which==+1 => use first upcoming such month.";
" which==0 => use closest such month.";
"larger (absolute) values for which specify a certain number of years into the future
or past.";
if (!(tonum(month = args[1]) || (month = $string_utils:find_prefix(month, this.months))))
return E_DIV;
endif
delta = ({0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}[month] + {@args,
1}[3]) - 1;
day = (time() - 28800) / 86400;
day = (day - ((day + 672) / 1461)) - delta;
dir = {@args, 0}[2];
if (dir)
day = ((day / 365) + dir) + (dir <= 0);
else
day = ((2 * day) + 365) / 730;
endif
day = (day * 365) + delta;
day = day + ((day + 671) / 1460);
return (day * 86400) + 28800;
.
dst_midnight: "Takes a time that is midnight PST and converts it to the nearest PDT midnight time if it's during that part of the year where we use PDT."; time = args[1]; return time - (3600 * (((tonum(ctime(time)[12..13]) + 12) % 24) - 12)); . time_sub:
"Works like pronoun substitution, but substitutes time stuff.";
"Call with time_sub(string, time). returns a string.";
"time is an optional integer in time() format. If omitted, time() is used.";
"Macros which are unknown are ignored. $Q -> the empty string.";
"Terminal $ are ignored.";
"$H -> hour #. $M -> min #. $S -> second #. 24-hour format, fixed width.";
"$h, $m, $s same x/c have not-fixed format. 00:03:24 vs. 0:3:24";
"$O/$o -> numeric hour in 12-hour format.";
"$D -> long day name. $d -> short day name.";
"$N -> long month name. $n -> short month name.";
"$Y -> long year # (e.g. '1991'). $y -> short year # (e.g. '91')";
"$Z -> the time zone (added in by r'm later)";
"$P/$p -> AM/PM, or am/pm.";
"$T -> date number. $t -> date number with no extra whitespace etc.";
"$1 -> Month in fixed-width numeric format (01-12) (added by dpk)";
"$2 -> Month in nonfixed numeric format (1-12)";
"$3 -> Date in fixed-width format, 0-fill";
"$$ -> $.";
"";
"This verb stolen from Ozymandias's #4835:time_subst.";
res = "";
thestr = args[1];
if (length(args) > 1)
thetime = tonum(args[2]);
else
thetime = time();
endif
if ((typeof(thestr) != STR) || (typeof(thetime) != NUM))
player:tell("Bad arguments to time_subst.");
return;
endif
itslength = length(thestr);
if (!itslength)
return "";
endif
done = 0;
cctime = ctime(thetime);
while (dollar = index(thestr, "$"))
res = res + thestr[1..dollar - 1];
if (dollar == length(thestr))
return res;
endif
thechar = thestr[dollar + 1];
thestr[1..dollar + 1] = "";
if (thechar == "$")
res = res + "$";
elseif (!strcmp(thechar, "h"))
res = res + $string_utils:trim(tostr(tonum(cctime[12..13])));
elseif (thechar == "H")
res = res + cctime[12..13];
elseif (!strcmp(thechar, "m"))
res = res + $string_utils:trim(tostr(tonum(cctime[15..16])));
elseif (thechar == "M")
res = res + cctime[15..16];
elseif (!strcmp(thechar, "s"))
res = res + $string_utils:trim(tostr(tonum(cctime[18..19])));
elseif (thechar == "S")
res = res + cctime[18..19];
elseif (!strcmp(thechar, "D"))
res = res + $time_utils:day(thetime);
elseif (thechar == "d")
res = res + cctime[1..3];
elseif (!strcmp(thechar, "N"))
res = res + $time_utils:month(thetime);
elseif (thechar == "n")
res = res + cctime[5..7];
elseif (!strcmp(thechar, "T"))
res = res + cctime[9..10];
elseif (thechar == "t")
res = res + $string_utils:trim(cctime[9..10]);
elseif (thechar == "O")
res = res + tostr(((tonum(cctime[12..13]) + 11) % 12) + 1);
elseif (!strcmp(thechar, "p"))
res = res + ((tonum(cctime[12..13]) >= 12) ? "pm" | "am");
elseif (thechar == "P")
res = res + ((tonum(cctime[12..13]) >= 12) ? "PM" | "AM");
elseif (!strcmp(thechar, "y"))
res = res + cctime[23..24];
elseif (thechar == "Y")
res = res + cctime[21..24];
elseif (thechar == "Z")
res = res + cctime[26..28];
elseif (thechar == "1")
res = res + $string_utils:right(tostr($string_utils:explode(cctime)[2] in
this.monthabbrs), 2, "0");
elseif (thechar == "2")
res = res + tostr($string_utils:explode(cctime)[2] in this.monthabbrs);
elseif (thechar == "3")
res = res + $string_utils:subst(cctime[9..10], {{" ", "0"}});
endif
endwhile
return res + thestr;
.
mmddyy ddmmyy:
"Copied from Archer (#52775):mmddyy Tue Apr 6 17:04:26 1993 PDT";
"Given a time() or ctime()-style date and an optional separator, this returns the
MM/DD/YY or DD/MM/YY form of the date (depending on the verb called.) The default
seperator is '/'";
if (typeof(args[1]) == NUM)
time = ctime(args[1]);
elseif (typeof(args[1]) == STR)
time = args[1];
else
return E_TYPE;
endif
date = $string_utils:explode(time);
day = tonum(date[3]);
month = date[2] in $time_utils.monthabbrs;
year = date[5];
daystr = (day < 10) ? "0" + tostr(day) | tostr(day);
monthstr = (month < 10) ? "0" + tostr(month) | tostr(month);
yearstr = tostr(year)[3..4];
divstr = (length(args) == 1) ? "/" | args[2];
if (verb == "mmddyy")
return tostr(monthstr, divstr, daystr, divstr, yearstr);
else
return tostr(daystr, divstr, monthstr, divstr, yearstr);
endif
.
parse_english_time_interval:
"$time_utils:parse_english_time_interval(n1,u1,n2,u2,...)";
"or $time_utils:parse_english_time_interval(\"n1 u1[,] [and] n2[,] u2 [and] ...\")";
"There must be an even number of arguments, all of which must be strings,";
" or there must be just one argument which is the entire string to be parsed.";
"The n's are are numeric strings, and the u's are unit names.";
"The known units are in $time_utils.time_units,";
" which must be kept sorted with bigger times at the head.";
"Returns the time represented by those words.";
"For example,";
" $time_utils:parse_english_time_interval(\"30\",\"secs\",\"2\",\"minutes\",\"31\",\"seconds\")
=> 181";
if ((length(args) == 1) && index(args[1], " "))
return $time_utils:parse_english_time_interval(@$string_utils:words(args[1]));
endif
a = $list_utils:setremove_all(args, "and");
nargs = length(a);
if (nargs % 2)
return E_ARGS;
endif
nsec = 0;
n = 0;
for i in [1..nargs]
if ((i % 2) == 1)
if ($string_utils:is_numeric(a[i]))
n = tonum(a[i]);
elseif (a[i] in {"a", "an"})
n = 1;
elseif (a[i] in {"no"})
n = 0;
else
return E_INVARG;
endif
else
unit = a[i];
if (unit[length(unit)] == ",")
unit = unit[1..length(unit) - 1];
endif
ok = 0;
for entry in ($time_utils.time_units)
if ((!ok) && (unit in entry[2..length(entry)]))
nsec = nsec + (entry[1] * n);
ok = 1;
endif
endfor
if (!ok)
return E_INVARG;
endif
endif
endfor
return nsec;
.
seconds_until_date:
"Copied from Ballroom Complex (#29992):from_date by Keelah! (#30246) Tue Jul 13 19:42:32
1993 PDT";
":seconds_until_date(month,day,time,which)";
"month is a string or the numeric representation of the month, day is a number, time
is a string in the following format, hh:mm:ss.";
"which==-1 => use most recent such month.";
"which==+1 => use first upcoming such month.";
"which==0 => use closest such month.";
"This will return the number of seconds until the month, day and time given to it.";
"Written by Keelah, on July 5, 1993.";
month = args[1];
day = args[2];
which = args[4];
time = args[3];
converted = 0;
converted = converted + $time_utils:from_month(month, which, day);
current = this:seconds_until_time("12:00:00");
get_seconds = this:seconds_until_time(time);
if (get_seconds < 0)
get_seconds = (get_seconds + 39600) - current;
else
get_seconds = (get_seconds + 39600) - current;
endif
converted = (converted + get_seconds) - time();
return converted;
.
seconds_until_time: "Copied from Ballroom Complex (#29992):seconds_until by Keelah! (#30246) Tue Jul 13 19:42:37 1993 PDT"; ":seconds_until_time(hh:mm:ss)"; "Given the string hh:mm:ss, this returns the number of seconds until that hh:mm:ss. If the hh:mm:ss is before the current time(), the number returned is a negative, else the number is a positive."; "Written by Keelah, on July 4, 1993."; current = $time_utils:to_seconds(ctime()[12..19]); time = $time_utils:to_seconds(args[1]); return tonum(time) - tonum(current); . PROPERTY DATA:       monthlens       timezones       stsd       ctcd       ct       corr       dayabbrs       days       months       monthabbrs       zones       time_units       tz_names |