Abstract. This program transforms time from one representation to another.
The source representation is the number of seconds elapsed since January 1, 1970,
00:00:00. The target representation is a vector of (year, month, day, hour, minute, second)
all normalized in the sense introduced below. This program is written as a demo program of elucidative programming in connection to the paper An Elucidative Programming Environment for Scheme intended for the Nordic Workshop on Programmming Language Research, NWPER'2000 in Lillehammer, Norway, June 2000. A similar demo program is available for Java. The paper is available in a zipped postscript format and as pdf. |
1.1 Time systems and functions 1.2 The plan of attack |
1.1 Time systems and functions |
(time-decode 948450887) = (2000 1 21 10 34 47)See details about time-decode in the next section. Please be aware of the problems of time zones and daylight saving time, cf. section 3.1.
1.2 The plan of attack |
Scheme is weak with respect to static typing so let us here give the signature of the function:
time-decode: integer -> (year x month x day x hour x minute x second)The type year represents an integer greater than or equal to 1970, month is the interval [1..12], day is [1..31], hour is [0..23], and both minute and second belong to [0..59]. The vector on the right hand side will be represented as a list in our program.
As a matter of terminology, the integer at the left hand side of the signature will be called the second counter. We say that an integer value is T-normalized if it is contained in the interval of type T. Thus, for instance, the integer 25 is not hour-normalized, but 1 is (leaving us with 24 hours which can be changed to one extra day).
In the one extreme we can imagine the conversions to be done via a (presumably complicated) formula which realizes an efficient calculation of the result, using arithmetic operators. In the other extreme we can imagine a simple solution based on successive counting and subtracting of well-defined time intervals such as years (with and without leap days), months (in four variations), days, and hours from the second counter. This would be a less efficient solution, but if reliability and trust are emphasized, this will provide for a transparent and easy to follow solution.
In the solution presented in section 2 we will allow "counting", but for some simple sub-problems we use solutions based on "calculation" with formulas involving simple arithmetic operators.
2 The solution In this section we describe the solutions in a number of natural subsection. First we find the year. The last information we extract is the month. |
2.1 Dealing with years 2.2 Dealing with days, hours, minutes, and seconds 2.3 Dealing with months 2.4 Putting it all together |
2.1 Dealing with years |
Now the function years-and-seconds solves the problem. The underlying counting is an iterative process, which we in Scheme handle by a tail-recursive function. This function is called cycle-years. The "cycling" starts from base-year. (cycle-years n y r) maintains the invariant
n + r = Cwhere C is the start value of r. n is increased and r is decreased by the the number of seconds in the actual year y. y is increased by one for each iteration. When the rest r becomes less than the seconds in the actual year, we return y and the rest seconds (as a list of two elements).
The function cycle-years depends on the constants seconds-in-a-leap-year and seconds-in-a-normal-year which are easily pre-calculated using a pocket calculator.
2.2 Dealing with days, hours, minutes, and seconds |
It is easy to find the unnormalized number of days, and the normalized hours, minutes, and seconds from r. This is done by quotient and modulo calculations. The function how-many-days-hours-minutes-seconds does that. We first find the (non day-normalized) number of days by dividing r by seconds-in-a-day (). The remainder, called n-rest-1 () is used to find the hour-normalized number of hours by division of n-rest-1 by seconds-in-an-hour (). Again the remainder, n-rest-2 () is found, and this quantum is used to find the minute-normalized number of minutes (). Finally the number of seconds are found in the last modulo calculation (). We use a sequential name-biding form let* to find the results in a sequential fashion. Still we are entirely within the functional paradigm, of course. The function returns the list of days, hours, minutes, and seconds.
2.3 Dealing with months |
The function day-and-month solves the problem. Like in section 2.1 we go for a counting solution. This is done by the tail-recursive helping function day-and-month-help. A call of
(day-and-month-help n m y c)involves that in year y and month m we are taking
(days-in-month m y)days from c and adding a month to m. The function days-in-month relies on a table of month lengths (for a normal year) called month-length-normal-year. The iteration goes on as long as the rest days, c, is less than the number of days in the actual month m (in the year y).
In the function day-and-month we pass the expression (+ 1 day-count) to the formal day counter parameter c in day-and-month-help. The reason is that one day into January brings us to some point in time at January 2, not January 1. Thus, because c will be the day of the month, c can never be 0. In the tail-recursive call, we know that c > (days-in-month m y), thus ensuring this property recursively.
2.4 Putting it all together |
3 Post Scriptum In this section we will make a final remark to the time conversion program. |
3.1 Final remarks |
3.1 Final remarks |
The easiest counter measure is to add or subtract an hour (3600 seconds) in time-decode just after the parameter n (the second counter) has been passed as parameter.
This concludes the time conversion example.
It would be possible - and natural - to continue the example with the reverse transformation, by calculation of the weekday, and by transformation of time intervals. Most of these can be found in the LAML library called Time, cf. the LAML libraries.