'===========================================================================
' Subject: CLOCK SET                          Date: 11-01-94 (00:00)       
'  Author: Douglas Lusher                     Code: QB, QBasic, PDS        
'  Origin: FidoNet QUIK_BAS Echo            Packet: DATETIME.ABC
'===========================================================================
'Well, here we are at daylight saving time again. Thought I
'would repost this bit of code to set the time and date in
'a computer by calling the NIST (National Institute of
'Standards and Technology) and obtaining the correct values
'from their atomic clock. Just a note for those of you who
'may have gotten this code from when I have posted it in
'the past: this is an updated version, there were a couple
'of subtle bugs in the previously posted versions.

 DEFINT A-Z
 CONST False = 0, True = NOT False
 CONST Modem = 1

 TimeOut$ = "*** Time limit exceeded, program aborted"
 Abort$ = "*** Program aborted from keyboard"

 PhoneNumber$ = "1-303-494-4774"
 'this is the phone number for the National Institute for Standards
 'and Technology in Colorado. It's the number I use for setting
 'my computer's clock, so the rest of the program is written to use
 'it. Listed below are some other numbers that you can call by
 'modem for the same purpose, but I don't know anything about the
 'service and info they provide.

 'PhoneNumber$ = "1-202-653-0351"
 'the United States Naval Observatory in Anapolis, Maryland

 'PhoneNumber$ = "07-2217033"         ' Brisbane, Australia
 'PhoneNumber$ = "03-6001641"         ' Melbourne, Australia

 ComSpec$ = "COM1:1200,N,8,1,BIN,CS0,DS0"
 'Change this ComSpec$ if your modem is on a different serial port.
 '1200 baud and 300 baud are the only speeds available at NIST

 ON ERROR GOTO HandleError
 WIDTH 80
 PRINT
 PRINT "CLOCKSET.BAS"
 PRINT "A program to set the clock/calendar of an IBM compatible"
 PRINT "computer after obtaining the correct date and time via modem."
 PRINT "Written by Douglas H. Lusher, 11-01-1994"
 PRINT
 PRINT "Time Zone? <E>astern, <C>entral, <M>ountain, <P>acific: ";
 DO
   LOCATE , , 1: Ky$ = INPUT$(1): LOCATE , , 0
   IF Ky$ = CHR$(27) THEN PRINT : PRINT Abort$: END
   Ky$ = UCASE$(Ky$)
   TZ% = INSTR("ECMP", Ky$)
   IF TZ% THEN PRINT Ky$: TZ% = TZ% + 4: EXIT DO
   BEEP
 LOOP
 'If you require other time zones, the above code will have
 'to be altered. For Alaska, TZ% must be set equal to 9.
 'For Hawaii, set TZ% equal to 11.

 PRINT "Daylight Savings Time? <Y>es, <N>o: ";
 DO
   LOCATE , , 1: Ky$ = INPUT$(1): LOCATE , , 0
   IF Ky$ = CHR$(27) THEN PRINT : PRINT Abort$: END
   Ky$ = UCASE$(Ky$)
   IF Ky$ = "Y" OR Ky$ = "N" THEN PRINT Ky$: EXIT DO
   BEEP
 LOOP
 IF Ky$ = "Y" THEN TZ% = TZ% - 1

 Abort% = False
 OPEN ComSpec$ FOR RANDOM AS #Modem
 PRINT #Modem, "ATZ"
 Start! = TIMER
 DO
   IF LineReceived(ModemInput$) THEN
     IF INSTR(ModemInput$, "OK") THEN EXIT DO
   ELSEIF INKEY$ = CHR$(27) THEN
     PRINT : PRINT Abort$: Abort% = True: EXIT DO
   ELSEIF TimeSince!(Start!) > 20 THEN
     PRINT : PRINT TimeOut$: Abort% = True: EXIT DO
   END IF
 LOOP

 IF Abort% THEN GOTO ProgramEnd

 SLEEP (3)
 PRINT #Modem, "ATDT"; PhoneNumber$
 Start! = TIMER
 DO
   IF LineReceived(ModemInput$) THEN
     IF INSTR(ModemInput$, "CONNECT") THEN
       EXIT DO
     ELSEIF INSTR(ModemInput$, "BUSY") THEN
       Abort% = True: EXIT DO
     ELSEIF INSTR(ModemInput$, "NO CARRIER") THEN
       Abort% = True: EXIT DO
     ELSEIF INSTR(ModemInput$, "ERROR") THEN
       Abort% = True: EXIT DO
     END IF
   ELSEIF INKEY$ = CHR$(27) THEN
     PRINT : PRINT Abort$: Abort% = True: EXIT DO
   ELSEIF TimeSince!(Start!) > 30 THEN
     PRINT : PRINT TimeOut$: Abort% = True: EXIT DO
   END IF
 LOOP

 IF Abort% THEN GOTO ProgramEnd

 Start! = TIMER
 LineCount% = 0
 DO
   IF LineReceived(ModemInput$) THEN
     'discard the first few lines to allow the connection
     '  to stabilize
     LineCount% = LineCount% + 1
     IF LineCount% > 10 THEN
       GOSUB SetClock
       IF ClockSet% THEN EXIT DO
     ELSEIF INSTR(ModemInput$, "NO CARRIER") THEN
       EXIT DO
     ELSEIF INSTR(ModemInput$, "ERROR") THEN
       EXIT DO
     END IF
   ELSEIF INKEY$ = CHR$(27) THEN
     PRINT : PRINT Abort$: EXIT DO
   ELSEIF TimeSince!(Start!) > 30 THEN
     PRINT : PRINT TimeOut$: EXIT DO
   END IF
 LOOP

 ProgramEnd:
 PRINT #Modem, "+++";
 Start! = TIMER
 DO UNTIL TimeSince!(Start!) > 2: LOOP
 PRINT #Modem, "ATH0"
 Start! = TIMER
 DO
   IF LineReceived(ModemInput$) THEN
     IF INSTR(ModemInput$, "OK") THEN EXIT DO
   ELSEIF TimeSince!(Start!) > 20 THEN
     EXIT DO
   END IF
 LOOP
 CLOSE #Modem
 END

 SetClock:
 'lines containing the date and time info are
 '50 characters long and end with a "*" or "#"
 IF LEN(ModemInput$) <> 50 THEN
   ClockSet% = False: RETURN
 END IF
 IF MID$(ModemInput$, 50) <> "*" AND MID$(ModemInput$, 50) <> "#" THEN
   ClockSet% = False: RETURN
 END IF
 'get the date info from the line
 D$ = MID$(ModemInput$, 10, 5) + "-19" + MID$(ModemInput$, 7, 2)
 IF VAL(MID$(ModemInput$, 7, 2)) < 94 THEN MID$(D$, 7, 2) = "20"
 'get the time info
 T$ = MID$(ModemInput$, 16, 8)
 'alter the time for the desired time zone
 Hour% = VAL(T$) - TZ%
 IF Hour% < 0 THEN
   'some adjustments will be necessary
   Hour% = Hour% + 24
   Day% = VAL(MID$(D$, 4, 2)) - 1
   IF Day% = 0 THEN
     Month% = VAL(MID$(D$, 1, 2)) - 1
     SELECT CASE Month%
       CASE 0
         Day% = 31
         Month% = 12
         Year% = VAL(MID$(D$, 7, 4)) - 1
         MID$(D$, 7, 4) = RIGHT$(STR$(Year%), 4)
       CASE 1, 3, 5, 7, 8, 10
         Day% = 31
       CASE 4, 6, 9, 11
         Day% = 30
       CASE 2
         Day% = 28
         Year% = VAL(MID$(D$, 7, 4))
         IF LeapYear(Year%) THEN Day% = 29
     END SELECT
     MID$(D$, 1, 2) = RIGHT$(STR$(Month% + 100), 2)
   END IF
   MID$(D$, 4, 2) = RIGHT$(STR$(Day% + 100), 2)
 END IF
 MID$(T$, 1, 2) = RIGHT$(STR$(Hour% + 100), 2)
 PRINT STRING$(58, "*")
 PRINT "  Current settings: Date: "; DATE$, "Time: "; TIME$
 DATE$ = D$: TIME$ = T$
 PRINT "      Corrected to: Date: "; DATE$, "Time: "; TIME$
 PRINT STRING$(58, "*"): PRINT
 ClockSet% = True
 RETURN

 HandleError:
 ErrCode% = ERR
 IF ErrCode% = 57 THEN
   Err57% = Err57% + 1
   IF Err57% <= 5 THEN
     RESUME
   ELSE
     PRINT "Program terminated; too many I/O errors."
     RESUME ProgramEnd
   END IF
 ELSE
   PRINT "ERROR:"; ErrCode%; "- Program terminated."
   RESUME ProgramEnd
 END IF

 FUNCTION LeapYear% (Year%) STATIC
 'returns True (-1) if the specified year is a leap year
   LY% = (Year% MOD 4 = 0) AND (Year% MOD 100 <> 0)
   LY% = LY% OR (Year% MOD 400 = 0)
   LeapYear% = LY%
 END FUNCTION

 FUNCTION LineReceived (Received$) STATIC
   CRLF$ = CHR$(13) + CHR$(10)
   LineReceived = False
   IF LOC(Modem) THEN
     NewChars$ = INPUT$(LOC(Modem), #Modem)
     PRINT NewChars$;
     Buffer$ = Buffer$ + NewChars$
     LineEnd% = INSTR(Buffer$, CRLF$)
     IF LineEnd% THEN
       Received$ = LEFT$(Buffer$, LineEnd% - 1)
       Buffer$ = MID$(Buffer$, LineEnd% + 2)
       LineReceived = True
     END IF
   END IF
 END FUNCTION

 FUNCTION TimeSince! (Mark!)
   TimeNow! = TIMER
   TimeSince! = (TimeNow! - ((TimeNow! < Mark!) * 86400)) - Mark!
 END FUNCTION
