9 Forth Words for Date and Time 9 9 Mitch Bradley 9 Many computers have some facility, either hardware or software, for keeping track of the date and time of day. The F83 Users Group meeting at the 1984 FIG National Convention discussed a set of Forth words for getting the date and time from the system. Specified Words NOW ( -- seconds minutes hours) Returns the current time as seconds [0-59], minutes [0-59], and hours [0-23]. The time is for the local time zone. TODAY ( -- day month year ) Returns the day [1-31], the month [1-12], and the year. For example, as I am writing this (December 2, 1984), TODAY returns 2 12 1984. IS-TODAY ( day month year -- ) Sets the system's idea of the current time" IS-NOW ( seconds minutes hours -- ) Sets the system's idea of the current time. The arguments are the same as returned by NOW. Discussion These words are intended to be a standardized interface to whatever timekeeping functions are provided by the system. Note that these words specify nothing at all about the format in which dates and times are printed. The display format for dates and times is best left to the application program, since different applications are likely to have different requirements. The specified words represent a uniform way to ask the system for the required information. Note also that in all cases, the "most-significant" item of information appears on the top of the stack, consistent with other Forth words which use multiple stack items. Some systems do not provide any timekeeping function at all. In this case, dummy versions of the words "NOW" and "TODAY" may be provided. I recommend that the dummy "NOW" return the "0 0 12", which is noon. The dummy TODAY should return whatever date March 20, 1986 - 2 - was previously entered by the user. One reasonable implementa- tion could keep variables DAY, MONTH, and YEAR, which would be initialized to 0. If the dummy TODAY were accessed, and the variables were 0, then the system could ask the user to set the date. The inclusion of dummy versions of these words provides a uniform applications interface for utilities that want to know the date or time. The IS-NOW and IS-TODAY words are intended as low-level interfaces, and not as nice user-level interfaces. However, even as they stand, they are not too terrible, since, for instance "1 12 1984 IS-TODAY" is a relatively painless way of setting the Date to December 1, 1984. Similarly, "0 49 17 IS-NOW" is not all that bad a way of specifying 5:49 PM. The order of the operands is easy to remember because of the rule that the most-significant part is always on top of the stack. Nicer user-level interfaces might allow the information to be entered in words, but the specified words provide the basic functionality. Suggested Words The following words are suggested as part of a complete word set for dealing with dates and times. They will be needed if Forth is ever used in a nationwide or worldwide network of com- puters. DST? ( -- f ) Returns true if Daylight Savings Time is in effect locally, false if not. On many systems, it is hard to automatically determine this. A simple compromise is to make this word a constant, and to change the value of the constant when the time changes. TIME-ZONE ( -- minutes-west-of-GMT ) Returns the difference "GMT - local time" in minutes. For instance, Pacific Standard Time is 8 hours west of GMT, so TIME-ZONE returns 480. Why minutes instead of hours? Well, some places aren't on hour boundaries, for instance, Afghan- istan is 4 1/2 hours east of GMT, so TIME-ZONE would return -270. Printing Words These words are provided as an example of how to use the date and time words. For fear of starting an endless argument, I do not suggest the printing words as any sort of a standard whatso- ever. Use them if you wish, toss them if you don't. .TIME-ZONE ( -- ) Prints a string representing the current time zone (e.g. - PST). .DATE ( day month year -- ) Prints the date represented by the numbers on the stack. March 20, 1986 - 3 - .TIME ( msec secs mins hours -- ) Prints the time represented by the numbers on the stack. .TODAY ( -- ) Prints todays date. .NOW ( -- ) Prints the current time. Implementations Two versions are given. The first one is for a system which provides no timekeeping mechanism. This implementation simply returns the last date that the user has entered. The second implementation is for MS-DOS. Thanks to Ralph Phraner for pro- viding the code for the MS-DOS implementation. Both versions are written in the Forth 83 dialect. Dummy Implementation for a System with No Clock March 20, 1986 - 4 - VARIABLE SECOND VARIABLE MINUTE VARIABLE HOUR VARIABLE DAY VARIABLE MONTH VARIABLE YEAR : SET-NOW ( seconds minutes hours -- ) HOUR ! MINUTE ! SECOND ! ; : SET-TODAY ( day month year -- ) YEAR ! MONTH ! DAY ! ; 0 0 12 SET-NOW 0 0 0 SET-TODAY : GET-NUMBER ( -- n ) PAD 10 EXPECT 0. PAD 1- CONVERT DROP ; : BETWEEN ( n min max -- f ) ( True if min <= n <= max ) >R OVER > SWAP R> > OR NOT ; : PROMPT-SET-TODAY ( -- ) ." Please set the date." CR ( No check is made for a day too big for the month, ) ( such as February 31 ) BEGIN ." Day? [1-31] " GET-NUMBER DUP 1 31 BETWEEN NOT WHILE CR ." The day must between 1 and 31." DROP REPEAT BEGIN ." Month? [1-12] " GET-NUMBER DUP 1 12 BETWEEN NOT WHILE CR ." The month must between 1 and 12." DROP REPEAT BEGIN ." Year? " GET-NUMBER DUP 1983 <= WHILE CR ." Try a year > 1983." DROP REPEAT SET-TODAY ; : NOW ( -- seconds minutes hours ) SECOND @ MINUTE @ HOUR @ ; : TODAY ( -- day month year ) YEAR @ 0= IF PROMPT-SET-TODAY THEN DAY @ MONTH @ YEAR @ ; March 20, 1986 - 5 - Implementation for MS-DOS F83 (Thanks to Ralph Phraner) ONLY FORTH ALSO HIDDEN DEFINITIONS HEX CODE (GETDAY) ( -- year month.day ) 2A # AH MOV 21 INT CX PUSH DX PUSH NEXT END-CODE CODE (GETNOW) ( -- hours.minutes seconds.centiseconds ) 2C # AH MOV 21 INT CX PUSH DX PUSH NEXT END-CODE CODE (SETDAY) ( year month.day -- ) DX POP CX POP 2B # AH MOV 21 INT NEXT END-CODE CODE (SETNOW) ( hours.minutes seconds.centiseconds -- ) DX POP CX POP 2D # AH MOV 21 INT NEXT END-CODE ONLY FORTH HIDDEN ALSO FORTH DEFINITIONS : WBSPLIT ( 16b -- lobyte hibyte ) DUP FF AND SWAP FLIP FF AND ( FLIP swaps the bytes within a word ) ; : TODAY ( -- month day year ) (GETDAY) WBSPLIT ROT ; : NOW ( -- seconds minutes hours ) (GETNOW) FF AND SWAP WBSPLIT ; A Simple Implementation of the Suggested Words March 20, 1986 - 6 - FALSE CONSTANT DST? 480 CONSTANT TIME-ZONE ( Pacific Standard Time ) : .TIME-ZONE ( -- ) ." PST" ; An Implementation of the Printing Words : ," ( --STRING ) ASCII " WORD DUP C@ ( str len ) HERE SWAP 1+ ( str here len+1) DUP ALLOT CMOVE ; HERE ," December" HERE ," November" HERE ," October" HERE ," September" HERE ," August" HERE ," July" HERE ," June" HERE ," May" HERE ," April" HERE ," March" HERE ," February" HERE ," January" CREATE MONTHS , , , , , , , , , , , , : .MONTH ( index -- ) 1- 2* MONTHS + @ COUNT TYPE ; : .DATE ( day month year -- ) BASE @ >R DECIMAL SWAP .MONTH SPACE SWAP 2 .R ." , " . R> BASE ! ; : 2.R ( n -- ) Print 2 digits with 0-padding 0 <# # # #> TYPE ; : .TIME ( secs mins hours -- ) BASE @ >R DECIMAL 2 .R ." :" 2.R ." :" 2.R SPACE .TIME-ZONE R> BASE ! ; : .NOW ( -- ) NOW .TIME ; : .TODAY ( -- ) TODAY .DATE ; March 20, 1986