Decoding unix time

Now that I can read unix time with the newly made
unix module
I also need a way to make it accessible for humans. The unix time is a rather simple time. It is the amount of
seconds elapsed as of January 1, 1970 (an event referred to as 'the epoch'). Until 3600 that number had some
meaning to humans but the current datenumber is completely meaningless. See also
https://www.epochconverter.com/

What is the time today? Unix says 1582062091 or, in human speak, January 18,300, 1970. C has an asctime function
but I haven't got a clue how to access it yet. So in the meantime I made an epoch translator that turns 30 bits of
date into a human readable date.

The algorithm

The number may be huge but it is also simple:

- days = epoch DIV (24 * 3600)
- time = epoch MOD (24 * 3600)
- hour = time DIV 3600
- minute = (time MOD 3600) DIV 60
- seconds = time MOD 60

WHILE days > (365 + Leap (year)) DO days := days - 365 - Leap (year); INC (year) END;The leap year rules are rather complicated: If a year is divisible by 4 it is a leap year, unless it is a century, unless unless it is a quadruple century (divisible by 400). Now that could be a very interesting formula (as used by most C sources) but let's just take a look at the important dates.

The epoch was in 1970. The first century break was the year 2000. But since 2000 is a multiple of 400, it IS a simple leap year. The next one is 2100. This would not be a leap year. But the chances of any one of us getting so old are zero. Just ignore that date. So the only rule for us is 'divisible by 4'. Period.

Getting from days to months is not too complex with some cheating. First create an array with for each months the days between January 1 and that month. Then compare the day count with the elements in that array. Done.

The epoch program

Below is the source of the program. It has a silly name, just ignore it.

MODULE marchd; (* Create March Dates where start of year = March 1 and end of year is March 365 (or 366) *) IMPORT In, Out; CONST Daysecs = 24 * 3600; VAR year, month, day, days, minute, hour, seconds, secs2d, i : INTEGER; ytod : ARRAY 14 OF INTEGER; (* Year to day *) Done : BOOLEAN; PROCEDURE Leap (yr : INTEGER) : INTEGER; BEGIN IF year MOD 4 = 0 THEN RETURN 1 END; RETURN 0 END Leap; PROCEDURE Init; BEGIN ytod [1] := 0; ytod [2] := 31; ytod [3] := 60; ytod [4] := 91; ytod [5] := 121; ytod [6] := 152; ytod [7] := 182; ytod [8] := 213; ytod [9] := 244; ytod [10] := 274; ytod [11] := 305; ytod [12] := 335 END Init; BEGIN Init; year := 1970; In.Int (seconds); days := seconds DIV Daysecs; secs2d := seconds MOD Daysecs; hour := secs2d DIV 3600; minute := (secs2d MOD 3600) DIV 60; WHILE days > (365 + Leap (year)) DO days := days - 365 - Leap (year); INC (year) END; Done := FALSE; i := 12; IF (Leap (year) = 1) & (days > 59) THEN INC (days) END; WHILE ~Done DO IF days > ytod [i] THEN month := i; day := days - ytod [i]; Done := TRUE ELSE DEC (i) END END; Out.String ("Date is "); Out.Int (year, 5); Out.Int (month, 4); Out.Int (day, 4); Out.Int (hour, 4); Out.Int (minute, 4); Out.Ln END marchd.I guess this program is not too difficult to comprehend. The only special line is

IF (Leap (year) = 1) & (days > 59) THEN INC (days) END;When we are in a leapyear AND beyond 28 February, THEN add one day to the daycounter so the rest of the routine needs no adjustment.

Page created 18 Feb 2020,