-- TimeConvert.Mesa Edited by Johnsson on 29-Jul-80 9:25:55 -- Copyright Xerox Corporation 1979, 1980 DIRECTORY InlineDefs USING [BcplLongNumber, DIVMOD, LDIVMOD, LongNumber], StringDefs USING [AppendChar, AppendString], Time USING [], TimeDefs USING [ BaseYear, currentParameters, currentTime, DaysInFourYears, DefaultTime, PackedTime, StartWeekDay, UnpackedTime, WestEast]; TimeConvert: PROGRAM IMPORTS InlineDefs, StringDefs EXPORTS TimeDefs, Time SHARES TimeDefs = BEGIN OPEN TimeDefs; UP: TYPE = POINTER TO UnpackedTime; Number: TYPE = InlineDefs.LongNumber; DivideTime: PROCEDURE [num: Number, den: CARDINAL] RETURNS [quotient: PackedTime, remainder: CARDINAL] = BEGIN OPEN InlineDefs; q: Number; t: CARDINAL; [q.highbits, t] _ LDIVMOD[num.highbits, 0, den]; [q.lowbits, remainder] _ LDIVMOD[num.lowbits, t, den]; RETURN[quotient: q.lc, remainder: remainder] END; CurrentDayTime, Current: PUBLIC PROCEDURE RETURNS [PackedTime] = BEGIN t: InlineDefs.BcplLongNumber _ currentTime^; RETURN[LOOPHOLE[Number[num[highbits: t.highbits, lowbits: t.lowbits]]]] END; TP: TYPE = RECORD [beginDST, endDST: CARDINAL, zone, zoneminutes: INTEGER]; TimeParameters: PROCEDURE RETURNS [p: TP] = BEGIN OPEN p; direction: WestEast; [beginDST: beginDST, endDST: endDST, zone: zone, zoneminutes: zoneminutes, direction: direction] _ currentParameters^; IF direction # west THEN BEGIN zone _ -zone; zoneminutes _ -zoneminutes END; RETURN END; MonthTable: ARRAY [0..12] OF CARDINAL = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; Unpack: PUBLIC PROCEDURE [p: PackedTime _ 0] RETURNS [unpacked: UnpackedTime] = UnpackDT; UnpackDT: PUBLIC PROCEDURE [p: PackedTime _ DefaultTime] RETURNS [unp: UnpackedTime] = BEGIN u: UP = @unp; day4, day, yr4: CARDINAL; month: CARDINAL _ 1; t: Number; parms: TP; parms _ TimeParameters[]; IF p = DefaultTime THEN p _ CurrentDayTime[]; [p, u.second] _ DivideTime[[lc[p]], 60]; p _ p - parms.zoneminutes; -- ignore underflow [p, u.minute] _ DivideTime[[lc[p]], 60]; u.zone _ parms.zone; u.dst _ FALSE; p _ p - parms.zone; -- ignore underflow DO -- have to repeat if DST [t.lc, u.hour] _ DivideTime[[lc[p]], 24]; u.weekday _ (t.lowbits + StartWeekDay) MOD 7; [yr4, day4] _ InlineDefs.DIVMOD[t.lowbits, DaysInFourYears]; day4 _ (IF day4 >= 2*365 + 31 + 28 THEN 3 ELSE (day4 + (365 - 31 - 28))/365) + day4; [day4, day] _ InlineDefs.DIVMOD[day4, 366]; u.year _ BaseYear + yr4*4 + day4; WHILE day >= MonthTable[month] DO month _ month + 1 ENDLOOP; u.month _ month _ month - 1; day _ day + 1; u.day _ day - MonthTable[month]; IF u.dst OR ~CheckDateGE[u, day, parms.beginDST, 2] OR CheckDateGE[ u, day, parms.endDST, 1] THEN EXIT; p _ p + 1; u.dst _ TRUE; ENDLOOP; RETURN END; InvalidTime, Invalid: PUBLIC ERROR = CODE; Pack: PUBLIC PROCEDURE [UnpackedTime, BOOLEAN] RETURNS [time: PackedTime] = PackDT; PackDT: PUBLIC PROCEDURE [unp: UnpackedTime, computeDST: BOOLEAN _ TRUE] RETURNS [time: PackedTime] = BEGIN u: UP = @unp; year, month, day, day1, hour, minute, second: CARDINAL; zone: INTEGER; dst: BOOLEAN; yr3: [0..3]; t: Number; tp: TP _ TimeParameters[]; [year: year, month: month, day: day, hour: hour, minute: minute, second: second, zone: zone, dst: dst] _ u^; IF (year _ year - BaseYear) >= 136 OR month >= 12 OR day ~IN [1..31] OR hour >= 24 OR minute >= 60 OR second >= 60 THEN ERROR InvalidTime; yr3 _ year MOD 4; IF day > LOOPHOLE[MonthTable[month + 1] - MonthTable[month], CARDINAL] OR (month = 1 AND day = 29 AND yr3 # 3) THEN ERROR InvalidTime; -- compute days this year in day1 day1 _ MonthTable[month] + day; IF yr3 # 3 THEN BEGIN tp.beginDST _ tp.beginDST - 1; tp.endDST _ tp.endDST - 1; IF month >= 2 THEN day1 _ day1 - 1; END; t _ Number[ num[highbits: 0, lowbits: (year/4)*DaysInFourYears + yr3*365 + day1 - 1]]; u.weekday _ (t.lowbits + TimeDefs.StartWeekDay) MOD 7; IF computeDST THEN BEGIN OPEN tp; IF CheckDateGE[u, day1, beginDST, 2] AND ~CheckDateGE[u, day1, endDST, 2] THEN zone _ zone - 1 END ELSE BEGIN tp.zone _ zone; tp.zoneminutes _ 0; IF dst THEN tp.zone _ tp.zone - 1; END; RETURN[((t.lc*24 + hour + tp.zone)*60 + minute + tp.zoneminutes)*60 + second] END; Append: PUBLIC PROCEDURE [STRING, UnpackedTime, BOOLEAN] = AppendDayTime; AppendDayTime: PUBLIC PROCEDURE [ s: STRING, unp: UnpackedTime, zone: BOOLEAN _ FALSE] = BEGIN z: INTEGER; KnownZones: TYPE = [4..10]; zones: PACKED ARRAY KnownZones OF CHARACTER _ ['A, 'E, 'C, 'M, 'P, 'Y, 'H]; u: UP = @unp; p: CARDINAL _ s.length; m: CARDINAL; w2d: PROCEDURE [v: CARDINAL] = BEGIN d1, d2: CARDINAL; [d1, d2] _ InlineDefs.DIVMOD[v, 10]; IF d1 # 0 THEN s[p] _ '0 + d1; s[p + 1] _ '0 + d2; p _ p + 3; END; StringDefs.AppendString[s, " 0-xxx-00 0:00:00"L]; w2d[u.day]; m _ u.month*3; THROUGH [0..2] DO s[p] _ ("JanFebMarAprMayJunJulAugSepOctNovDec"L)[m]; p _ p + 1; m _ m + 1; ENDLOOP; p _ p + 1; w2d[u.year MOD 100]; w2d[u.hour]; w2d[u.minute]; w2d[u.second]; IF zone AND (z _ unp.zone) IN KnownZones THEN BEGIN OPEN StringDefs; c: CHARACTER _ IF unp.dst THEN 'D ELSE 'S; AppendChar[s, ' ]; AppendChar[s, zones[z]]; AppendChar[s, c]; AppendChar[s, 'T]; END; RETURN END; CheckDateGE: PROCEDURE [u: UP, days, dstDay, dstHour: INTEGER] RETURNS [BOOLEAN] = BEGIN weekday: INTEGER _ u.weekday; RETURN[ IF days < dstDay - 6 THEN FALSE ELSE IF days > dstDay THEN TRUE ELSE IF weekday = 6 THEN u.hour >= dstHour ELSE days - weekday > dstDay - 6] END; END..