Time Inquiry

Developer(s): George Chambers
Date: 198x
Type: Program
Platform(s): TS 2068
Tags: Home

Time Inquiry is a world time-zone lookup program that lets users find the corresponding local time for any city or country when given a known time at another location. It loads a companion machine code file (“time.C1”) into memory above address 32550 and uses a Z80 machine code routine (POKEd in from DATA statements at line 9030) to perform a binary search or sequential scan through a packed city/time-zone database stored in high RAM. City entries are encoded as a numeric time-zone code prefix concatenated with the city name and terminated by an asterisk (ASCII 42). The program supports adding new cities to the database via menu option 2 and can save both the BASIC program and the updated code/data file back to tape. Input validation routines check for alphabetic city names and numeric hour values in the range 0–24, rejecting fractional hours other than half-hours (converted to display as “.30”).


Program Structure

The program is organized around a central menu at line 350 with four options dispatched via GO TO VAL x$*2000 (line 460), routing to:

  • 2000 – Time inquiry (main feature)
  • 4000 (via 4060) – Add cities/countries to the database
  • 6020 – Information/help text
  • 8000/9900 – Save to tape

Initialization (lines 1080) loads the machine code data file, POKEs the Z80 routine from DATA, sets up display attributes, and draws decorative border rectangles using PLOT/DRAW. The subroutine at 90009010 RESTOREs to line 9030 and POKEs 68 bytes of machine code into addresses 3255232619.

Variable Conventions

Several variables are pre-initialized at line 20 using idiomatic ZX Spectrum BASIC to avoid repeating numeric literals and to save memory:

VariableValueMeaning
oo0 (NOT PI)Zero / false
oa1 (PI/PI)One / true
ob2Two (max consecutive spaces)
oj10Column/row offset
ol12Noon pivot value
w350Menu line number
v3000Screen-clear scroll subroutine line
l32658Base address of city database in RAM

Using NOT PI for 0 and PI/PI for 1 is a well-known memory-saving idiom on this platform, avoiding storage of the numeric literal in the program line.

Machine Code Usage

Lines 90009034 POKE a 68-byte Z80 routine into RAM starting at address 32552. The routine is invoked at line 2530 via LET b= USR 32552. Before the call, lines 24602500 set up a search string in RAM at 32513, and patch the machine code at addresses 3260432607 with the database pointer p (split into low and high bytes). After the call, lines 25402590 read the result address from PEEK 32617/32618 and walk the found record to extract the numeric code (up to 5 characters, digits only) into b$ and the city name into d$, stopping when a * terminator (ASCII 42) is found.

The companion file “time.C1” is loaded at line 10 as a CODE block starting at 32656, which stores the city database. The current end-of-database pointer p is reconstructed at line 15 from a two-byte little-endian value PEEKed from addresses 32656/32657.

Database Format

Each city record in the CODE block is formatted as a numeric time-zone offset (e.g., 7) immediately followed by the city name (e.g., NEW YORK), terminated by an asterisk (*, ASCII 42). The time-zone number represents the local hour when Greenwich Mean Time is 12:00 noon, functioning as an absolute UTC offset expressed on a 24-hour clock. New records are appended by the menu-option-2 path (lines 40604200), with p maintained as a running pointer and persisted back into addresses 32656/32657.

Time Calculation

The core arithmetic (lines 21702330) computes the time difference as:

  1. Extract origin city offset a = VAL a$ and destination offset b = VAL b$ from the database.
  2. Compute displacement t = b - a + f where f is the user-entered known hour.
  3. Wrap t into the 1–24 range, then classify as A.M., P.M., NOON, or MIDNIGHT using ol (12) as pivot.

Line 2326 handles half-hour time zones: if t - INT t <> 0, it sets display suffix r$ to "0 " and adds 0.3 to the integer part of t to produce a display like 7.30 instead of 7.5. This is a practical workaround for displaying fractional hours since the platform’s PRINT would otherwise show 7.5.

Input Validation

Two validation subroutines are used:

  • 100180: Validates a city/country name. Allows uppercase letters A–Z (ASCII 65–90), spaces, commas, and periods. Rejects strings with more than one consecutive space (q counts spaces; if q=2, branches to 320). Invalid input triggers an error message at line 325.
  • 240310: Validates a numeric hour. Allows digits and one decimal point; rejects values outside 0–24 or non-integer values (line 302). The slash character (/, ASCII 47) is explicitly excluded despite being in the digit range check.

Screen Management

The subroutine at line 3000 scrolls the screen by printing 32 spaces (e$, dimensioned at line 80) from row 21 up to row oj (10) in a FOR loop with STEP -1, effectively clearing lines without a full CLS. The variable v=3000 is used throughout as GO SUB v for this purpose.

Notable Anomalies

  • Line 2165 tests IF LEN A$=0 (uppercase A$) but sets A$="0"; however, the origin city data was stored in lowercase a$ at line 2020. On this platform uppercase and lowercase variable names are distinct, so this guard may not function as intended if the origin city lookup populated a$ rather than A$.
  • Line 2210 modifies f (subtracts 12) after it has already been used to compute t, which could affect the display label consistency in edge cases but does not alter the already-computed result.
  • Lines 31003140 appear to be a diagnostic/debugging utility left in the listing: they scan RAM from address 37380 onward and print raw memory contents. Line 3130 is commented out with REM.
  • Line 4000 is referenced by GO TO 4000 at line 4140 but does not appear in the listing; the add-city entry point visible is 4060. This is a non-existent line reference.
  • The INKEY$ loop at line 23702380 has a subtle logic issue: line 2370 waits for a non-empty keypress, but line 2380 then re-reads INKEY$, which may already be empty by the time it executes, causing “N” to never be detected reliably. A stored variable for the keypress would be more robust.
  • Line 9910 does GO TO ol, i.e., GO TO 12, a non-existent line — standard technique to halt after saving.

Image Gallery

Source Code

    1 REM     TIME INQUIRY          
    2 REM    George Chambers
    3 REM    14 Richome Court
    4 REM  Toronto,Ont. M1K 2Y1   
   10 CLEAR VAL "32550":LOAD "time.C1"CODE 
   15 LET p= PEEK VAL "32656"+ VAL "256"* PEEK VAL "32657"
   20 LET oo= NOT PI:LET oa= PI/ PI:LET ob=2:LET oj= VAL "10":LET ol= VAL "12":LET w= VAL "350":LET v= VAL "3000":LET l= VAL "32658"
   30 BORDER VAL "5":INK oo:PAPER VAL "5":CLS 
   40 GO SUB VAL "9000"
   50 PRINT AT VAL "3",oj; PAPER VAL "6";"TIME INQUIRY"; PAPER VAL "5";,, TAB VAL "7"; PAPER VAL "6";"By George Chambers"
   60 INK oa:PLOT oo, VAL "108":DRAW oo, VAL "62":DRAW VAL "255",oo:DRAW oo,-62:DRAW -255,oo
   70 INK ob:PLOT VAL "8", VAL "114":DRAW oo, VAL "50":DRAW VAL "238",oo:DRAW oo,-50:DRAW -238,oo:INK oo
   80 DIM e$(32)
   90 GO TO w
  100 LET q=oo
  110 FOR n=oa TO LEN x$
  120 IF x$(n) <>" " THEN LET q=oo
  130 IF x$(n)=" " THEN GO TO VAL "150"
  135 IF x$(n)= CHR$ VAL "46" OR x$(n)= CHR$ VAL "44" THEN GO TO VAL "150"
  140 IF x$(n)< CHR$ VAL "65" OR x$(n)> CHR$ VAL "90" THEN GO TO VAL "320"
  150 IF x$(n)=" " THEN LET q=q+oa
  160 IF q=ob THEN GO TO VAL "320"
  170 NEXT n
  180 RETURN 
  240 LET q=oo
  250 FOR a=oa TO LEN x$
  260 IF x$(a)< CHR$ VAL "46" OR x$(a)> CHR$ VAL "57" OR x$= CHR$ VAL "47" THEN GO TO VAL "325"
  270 IF x$(a)= CHR$ VAL "46" THEN LET q=q+oa
  280 IF q=ob THEN GO TO VAL "325"
  290 NEXT a
  300 IF VAL x$> VAL "24" OR VAL x$<oo THEN GO TO VAL "325"
  301 LET x= VAL x$
  302 IF x <> INT x THEN GO TO VAL "320"
  310 RETURN 
  320 PRINT ,, TAB VAL "10";x$
  325 PRINT AT VAL "18",oa; FLASH oa;"YOU HAVE ENTERED INVALID DATA"; FLASH oo
  330 PRINT ,,"Please press any key to restart"
  340 IF INKEY$="" THEN GO TO VAL "340"
  350 GO SUB v:PRINT AT oj,oo;"This  program  will  provide theproper time displacement for anycountry  or city in the world"
  380 PRINT ''"1) Time Inquiry"
  390 PRINT '"2) To Add Cities/Countries"
  400 PRINT '"3) Information"
  410 PRINT '"4) To save To Disk"
  420 PRINT #1; INK oa;"   PRESS A KEY:(1 TO 4)"; INK oo
  430 LET x$= INKEY$
  440 IF x$<"1" OR x$>"4" THEN GO TO VAL "430"
  460 GO TO VAL x$* VAL "2000"
 2000 GO SUB v:PRINT AT oj,oo;"First enter the "; INK ob;"name of the city"; INK oo;"or country.";
 2010 GO SUB VAL "2400"
 2020 LET a$=b$
 2030 LET c$=d$
 2040 PRINT INK oa;"** ";c$;" **"; INK oo
 2050 PRINT ,,"Now enter the "; INK oa;"known hour"; INK oo;"  at ",; INK oa;c$; INK oo;" (as a figure","between 1 and 24)";
 2060 POKE VAL "23658", VAL "8":INPUT x$
 2070 IF x$="" THEN GO TO VAL "2060"
 2080 PRINT INK ob;"   ** ";x$;" **"; INK oo
 2090 GO SUB VAL "240"
 2100 LET f$=x$
 2120 LET h$="A.M."
 2130 IF VAL f$>ol THEN LET h$="P.M."
 2135 IF VAL f$=ol THEN LET h$="NOON"
 2137 IF f$="24" THEN LET h$="MIDNIGHT"
 2140 LET f= VAL f$
 2150 PRINT ,,"Next, Enter the "; INK oa;"name of the cityor country"; INK oo;"  where  you  wish thecorresponding time check."
 2160 GO SUB VAL "2400"
 2165 IF LEN A$=0 THEN LET A$="0"
 2170 LET a= VAL a$
 2180 LET b= VAL b$
 2190 LET t=b-a
 2200 LET t=t+f
 2210 IF f>ol THEN LET f=f-ol
 2220 LET j$="A.M."
 2230 IF t> VAL "24" THEN LET t=t- VAL "24"
 2240 IF t<oo THEN LET j$="P.M.":LET t=t+ol
 2260 IF t>ol THEN LET j$="P.M.":LET t=t-ol
 2280 IF t=ol AND j$="A.M." THEN LET j$="NOON"
 2290 IF t=ol AND j$="P.M." THEN LET j$="MIDNIGHT"
 2305 LET r$=".00 "
 2307 GO SUB v
 2310 PRINT AT oj,oo;"WHEN IT IS "; INK ob;f;".00 ";h$; INK oo;" AT"
 2320 PRINT ' INK ob;c$; INK oo;" THE TIME AT"
 2326 IF t- INT t <>oo THEN LET r$="0 ":LET t= INT t+.3
 2330 PRINT ' INK ob;d$; INK oo;" WILL BE "; INK ob;t;r$;j$; INK oo
 2340 PRINT ''"DO YOU WANT ANOTHER TIME CHECK?"
 2350 PRINT ,, TAB oj;"ENTER Y/N"
 2370 IF INKEY$="" THEN GO TO VAL "2370"
 2380 IF INKEY$="N" THEN CLS :GO TO VAL "8010"
 2390 GO TO w
 2400 POKE VAL "23658", VAL "8":INPUT x$
 2410 IF x$="" THEN GO TO VAL "2400"
 2420 GO SUB VAL "100"
 2430 LET d$=x$
 2440 LET x$=x$+"\::"
 2450 FOR x=oa TO LEN x$
 2460 POKE VAL "32513"+x, CODE x$(x)
 2470 NEXT x
 2480 POKE VAL "32606",p- VAL "256"* INT (p/256)
 2490 POKE VAL "32607", INT (p/256)
 2500 POKE VAL "32604", VAL "146":POKE VAL "32605", VAL "127"
 2530 LET b= USR VAL "32552"
 2540 LET x= PEEK VAL "32617"+ VAL "256"* PEEK VAL "32618"
 2542 IF x=l THEN GO TO VAL "5000"
 2543 LET b$=""
 2545 LET d$=""
 2550 FOR y=x TO x+ VAL "16"
 2555 IF y-x>4 THEN GO TO VAL "2570"
 2560 IF PEEK y> VAL "44" AND PEEK y< VAL "58" AND PEEK y <> VAL "45" AND PEEK y <> VAL "47" THEN LET b$=b$+ CHR$ PEEK y
 2570 IF PEEK y> VAL "64" AND PEEK y< VAL "91" THEN LET d$=d$+ CHR$ PEEK y
 2575 IF PEEK y= VAL "32" OR PEEK y= VAL "44" OR PEEK y= VAL "46" THEN LET d$=d$+ CHR$ PEEK y
 2580 IF PEEK (y+oa)= VAL "42" THEN RETURN 
 2590 NEXT y
 2690 RETURN 
 3000 FOR N=21 TO oj STEP -oa:PRINT AT N,oo;e$:NEXT N:RETURN 
 3100 REM   \{17}\{4}To scan names list\{17}\{5}
 3110 FOR n=37380 TO VAL "65000"
 3120 PRINT n, CHR$ PEEK n
 3130 REM IF PEEK (n)=42 THEN PRINT :PRINT (n+1);" ";
 3140 NEXT n:STOP 
 4060 GO SUB v:PRINT AT oj,oo;" Enter the code number and name",,,"     of the city or country"
 4070 PRINT '"       (See Instructions)"
 4080 INPUT x$
 4090 LET a$="*"+x$
 4100 PRINT AT VAL "14", VAL "8";e$' TAB oj; INK ob;x$; INK oo
 4110 PRINT AT 18,oo;"Press  N/L  to log this listing or  C  to correct it"
 4120 INPUT x$
 4130 GO SUB v
 4140 IF x$="C" THEN GO TO VAL "4000"
 4150 FOR x=oa TO LEN a$
 4160 POKE l+p, CODE a$(x)
 4170 LET p=p+oa
 4180 NEXT x
 4190 POKE l+p, VAL "42"
 4195 POKE VAL "32657", INT (p/ VAL "256"):POKE VAL "32656",p-(PEEK VAL "32657"* VAL "256")
 4200 GO TO w
 5020 GO SUB v:PRINT AT oj,oo;"    The name you requested",,,"          ";d$;"  "
 5025 PRINT ,,"    is not in our records"
 5030 PRINT ,,"Please select another  name."
 5040 PRINT ,,"  If you wish, it is possible toenter additional  locations intothis program via Menu item No.2.    Check the instructions."
 5060 PRINT AT VAL "18",oo;"Press any key to return to Menu"
 5070 IF INKEY$="" THEN GO TO VAL "5070"
 5080 GO TO w
 6020 CLS :PRINT AT oo,oo'"If the requested locality is notstored, you will be advised."
 6030 PRINT '"You may add  localities  to  thedata base, if you wish."
 6040 PRINT '"An entry consists of the name ofthe city, plus a numerical  codeprefix denoting it's time zone."''"      (Example) 7NEW YORK"
 6050 PRINT '"The code prefix must  correspondto the time (as a 24-hour clock)in that locality,when the Green-wich Mean Time is 12 noon." 
 6060 PRINT '"Note: This program does not copewith Daylight Saving Time."
 6300 PRINT INK oa'"Press any key to return to Menu"; INK oo
 6310 IF INKEY$="" THEN GO TO VAL "6310"
 6320 CLS :GO TO VAL "50"
 8000 GO TO VAL "9900"
 8010 GO SUB v:PRINT AT oj, VAL "8";" TEMPUS FUGITS "
 8020 PRINT ,, TAB VAL "6";" MY,HOW TIME FLIES "
 8030 PAUSE oo:STOP 
 9000 RESTORE VAL "9030"
 9010 FOR n= VAL "32552" TO VAL "32619":READ a:POKE n,a:NEXT n:RETURN 
 9030 DATA 42,92,127,237,75,94,127,17,2,127,26,237,177,226,96
 9031 DATA 127,19,26,254,143,202,71,127,237,161,202,56,127,195,47
 9032 DATA 127,34,92,127,43,126,254,42,202,84,127,195,74,127,34
 9033 DATA 105,127,237,67,94,127,201,44,142,228,3,33,146,127,1
 9034 DATA 1,0,195,84,127,34,142,0,0
 9890 STOP 
 9900 SAVE "time.B1" LINE 1:SAVE "time.C1"CODE VAL "32656",p
 9910 GO TO ol

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.