############################################################################
#
# File: datefns.icn
#
# Subject: Procedure for dates
#
# Author: Charles Hethcoat
#
# Date: August 14, 1995
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# datefns.icn - a collection of date functions
#
# Adaptor: Charles L Hethcoat III
# June 12, 1995
# Taken from various sources as attributed below.
#
# All date and calendar functions use the "date_rec" structure defined
# below.
#
# Note: I adapted the procedures "julian" and "unjulian" sometime in 1994
# from "Numerical Recipes in C." Some time later I discovered them
# (under slightly different names) in Version 9 of the Icon Library
# (Ralph Griswold, author). I am including mine for what they are worth.
# That'll teach me to wait!
#
############################################################################
record date_rec(year, month, day, yearday, monthname, dayname)
global monthlist # Maps month numbers into month names
global monthtbl # Maps month names into numbers 1-12
global dow # Maps 1-7 into Sunday-Saturday
global cum_days # Cum. day counts for month end, leap & non-leap yrs.
# initdate - call to initialize the global data before using other fns.
# See "The C Programming Language," by Kernighan and Richie (Wylie,
# 1978)
procedure initdate()
monthlist :=
["January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"]
monthtbl := table()
monthtbl["January"] := 1
monthtbl["February"] := 2
monthtbl["March"] := 3
monthtbl["April"] := 4
monthtbl["May"] := 5
monthtbl["June"] := 6
monthtbl["July"] := 7
monthtbl["August"] := 8
monthtbl["September"] := 9
monthtbl["October"] := 10
monthtbl["November"] := 11
monthtbl["December"] := 12
dow :=
["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday"]
cum_days := [
[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
]
return
end
# today - obtain computationally-useful values for today's date
procedure today()
local junk, datestruct
datestruct := date_rec()
&dateline ? { # &dateline is in a fixed format:
junk := tab(upto(&letters))
datestruct.dayname := tab(many(&letters))
junk := tab(upto(&letters))
datestruct.monthname := tab(many(&letters))
junk := tab(upto(&digits))
datestruct.day := tab(many(&digits))
junk := tab(upto(&digits))
datestruct.year := tab(many(&digits))
}
datestruct.month := monthtbl[datestruct.monthname]
datestruct.yearday := doy(datestruct.year, datestruct.month, datestruct.day)
return datestruct
end
# The next two routines have been adapted from "Numerical Recipes in C,"
# by Press, Flannery, Teukolsky, and Vetterling (Cambridge, 1988). The
# following quote is from page 10:
# Astronomers number each 24-hour period, starting and ending at noon,
# with a unique integer, the Julian Day Number. Julian Day Zero was
# a very long time ago; a convenient reference point is that Julian
# Day 2440000 began at noon of May 23, 1968. If you know the Julian
# Day Number that began at noon of a given calendar date, then the day
# of the week of that date is obtained by adding 1 and taking the result
# modulo base 7; a zero answer corresponds to Sunday, 1 to Monday, ...,
# 6 to Saturday.
# The C code presented in that book heavily uses the automatic conversion
# of real (floating point) numbers to integers by truncation. Since Icon
# doesn't do this, explicit type conversions are required.
# julian - convert a date_rec to a Julian day number
procedure julian(date)
local jul
local ja, jy, jm, z1, z2
if date.year = 0 then
fail
if date.year < 0 then
date.year +:= 1
if date.month > 2 then {
jy := date.year
jm := date.month + 1
} else {
jy := date.year - 1
jm := date.month + 13
}
z1 := real(integer(365.25*jy))
z2 := real(integer(30.6001*jm))
jul := integer(z1 + z2 + date.day + 1720995)
if date.day + 31*(date.month + 12*date.year) >= 588829 then {
ja := integer(0.01*jy)
jul +:= 2 - ja + integer(0.25*ja)
}
return jul
end
# unjulian - produce a date from the Julian day number
procedure unjulian(julianday)
local ja, jalpha, jb, jc, jd, je # integers all
local datestruct
datestruct := date_rec()
if julianday >= 2299161 then {
jalpha := integer((real(julianday - 1867216) - 0.25)/36524.25)
ja := julianday + 1 + jalpha - integer(0.25*jalpha)
} else
ja := julianday
jb := ja + 1524
jc := integer(6680.0 + (real(jb - 2439870) - 122.1)/365.25)
jd := 365*jc + integer(0.25*jc)
je := integer((jb - jd)/30.6001)
datestruct.day := jb - jd - integer(30.6001*je)
datestruct.month := je - 1
if datestruct.month > 12 then
datestruct.month -:= 12
datestruct.year := jc - 4715
if datestruct.month > 2 then
datestruct.year -:= 1
if datestruct.year <= 0 then
datestruct.year -:= 1
# Get the day number in the year:
datestruct.yearday := doy(datestruct.year, datestruct.month, datestruct.day)
# Get the name of the month:
datestruct.monthname := monthlist[datestruct.month]
# Calculate the day of the week:
datestruct.dayname := dow[(julianday + 1) % 7 + 1]
return datestruct
end
# doy - return day-of-year from (year, month, day)
# Adapted from K&R
procedure doy(year, month, day)
local leap, y, m, d
y := integer(year)
m := integer(month)
d := integer(day)
leap :=
if (y % 4 = 0 & y % 100 ~= 0) | y % 400 = 0 then
2 # leap year
else
1 # non-leap year
return cum_days[leap][m] + d
end
# wrdate - write out a basic date string with a leadin string
procedure wrdate(leadin, date)
write(leadin, " ", date.year, " ", date.monthname, " ", date.day)
end
This page produced by UniDoc on 2021/04/15 @ 23:59:44.