The world's time zones
It is noon in London when it is nine at night in Tokyo, and the difference changes twice a year in many places, on dates each country chooses. The Time Zone library carries the tz database, the list of every zone's rules that phones and computers everywhere use, so a program can know the time anywhere. Each zone has a name, a region and its biggest city: Europe/Paris, America/New_York. TimeZones lists them:
put TimeZones() into tZones
put the number of lines of tZones > 300
put "Europe/Paris" is among the lines of tZones
put "Asia/Kolkata" is among the lines of tZones
put "Mars/Olympus_Mons" is among the lines of tZones
true true true false
Use these names, not abbreviations like EST or CET: an abbreviation can mean different zones in different countries, and does not say whether summer time applies.
Offsets from UTC
Every zone's clock is a number of hours ahead of or behind UTC, the world's reference time, which is the time in London in winter. the seconds counts in UTC, the same at that moment everywhere. FromUniversalTime takes a moment in UTC seconds and a zone, and gives that zone's clock as seconds, so the difference is the zone's offset:
put 1768478400 into tMoment -- 12:00 UTC on 15 January 2026
repeat for each item tZone in "Europe/London,America/New_York,Asia/Tokyo,Asia/Kolkata,Asia/Kathmandu,Australia/Sydney"
put tZone && (FromUniversalTime(tMoment, tZone) - tMoment) / 3600
end repeat
Europe/London 0 America/New_York -5 Asia/Tokyo 9 Asia/Kolkata 5.5 Asia/Kathmandu 5.75 Australia/Sydney 11
An offset is not always whole hours: India is five and a half hours ahead, Nepal five and three quarters. Sydney is eleven ahead in January because it is summer there.
Summer time
Many zones put their clocks forward an hour in summer, and each does it on its own dates; the south's summer is the north's winter. The same zone at two moments half a year apart:
function offsetHours pZone, pMoment
return (FromUniversalTime(pMoment, pZone) - pMoment) / 3600
end offsetHours
put 1768478400 into tJanuary -- 12:00 UTC on 15 January 2026
put 1784116800 into tJuly -- 12:00 UTC on 15 July 2026
repeat for each item tZone in "Europe/London,America/New_York,Australia/Sydney,Asia/Tokyo"
put tZone && offsetHours(tZone, tJanuary) && offsetHours(tZone, tJuly)
end repeat
Europe/London 0 1 America/New_York -5 -4 Australia/Sydney 11 10 Asia/Tokyo 9 9
London and New York go forward in July, Sydney goes back, and Japan has no summer time at all. The library knows the rules for past years too, as they were, so old dates come out right.
A zone's clock
The seconds FromUniversalTime gives are a clock reading: read as if they were UTC, they show that zone's time. A day is 86400 seconds and an hour 3600, so mod and div take the hours and minutes out, and comparing whole days says whether the zone is already in the next day, or still in the day before:
function clockOf pSeconds
return format("%02d:%02d", (pSeconds mod 86400) div 3600, (pSeconds mod 3600) div 60)
end clockOf
function dayOf pLocal, pMoment
put (pLocal div 86400) - (pMoment div 86400) into tDays
if tDays > 0 then return "the next day"
if tDays < 0 then return "the day before"
return "the same day"
end dayOf
put 1768478400 into tMoment -- 12:00 UTC on 15 January 2026
put "UTC" && clockOf(tMoment)
repeat for each item tZone in "America/Los_Angeles,Asia/Tokyo,Pacific/Auckland"
put FromUniversalTime(tMoment, tZone) into tLocal
put tZone && clockOf(tLocal) && dayOf(tLocal, tMoment)
end repeat
UTC 12:00 America/Los_Angeles 04:00 the same day Asia/Tokyo 21:00 the same day Pacific/Auckland 01:00 the next day
With the seconds in place of the fixed moment, it is a world clock, a different answer every minute:
function clockOf pSeconds
return format("%02d:%02d", (pSeconds mod 86400) div 3600, (pSeconds mod 3600) div 60)
end clockOf
put the seconds into tNow
repeat for each item tZone in "Europe/London,America/New_York,Asia/Tokyo"
put tZone && clockOf(FromUniversalTime(tNow, tZone))
end repeat
Europe/London 14:05 America/New_York 09:05 Asia/Tokyo 23:05
A meeting across zones
ToUniversalTime goes the other way: from a zone's clock reading, as seconds, to the moment in UTC. A clock reading as seconds is the day's midnight, counted as if in UTC, plus the hours and minutes. A call set for nine in the morning in New York on 15 June 2026, from Paris and Tokyo:
function clockOf pSeconds
return format("%02d:%02d", (pSeconds mod 86400) div 3600, (pSeconds mod 3600) div 60)
end clockOf
put 1781481600 into tDay -- midnight at the start of 15 June 2026, as UTC seconds
put tDay + 9 * 3600 into tNine -- 9:00 on that day, on a clock
put ToUniversalTime(tNine, "America/New_York") into tMoment
put "UTC" && clockOf(tMoment)
put "Paris" && clockOf(FromUniversalTime(tMoment, "Europe/Paris"))
put "Tokyo" && clockOf(FromUniversalTime(tMoment, "Asia/Tokyo"))
UTC 13:00 Paris 15:00 Tokyo 22:00
Store moments in UTC seconds, as the seconds gives them, and turn them into a zone's clock only to show them. Then a list of events from people in many zones sorts into the right order, and summer time never makes one an hour out.
Try it yourself
Write a function isWorkingHours that takes a zone and a moment in UTC seconds, and returns true when that zone's clock is from 9:00 up to but not including 17:00, so a program can say whom it is a good time to call.
Show a solution
function isWorkingHours pZone, pMoment
local tHour
put (FromUniversalTime(pMoment, pZone) mod 86400) div 3600 into tHour
return tHour >= 9 and tHour < 17
end isWorkingHours
put 1768478400 into tMoment -- 12:00 UTC on 15 January 2026
repeat for each item tZone in "Europe/Berlin,America/Chicago,Asia/Singapore"
put tZone && isWorkingHours(tZone, tMoment)
end repeat
Europe/Berlin true America/Chicago false Asia/Singapore false
Words in this lesson
Each one finds every lesson that uses it. The Dictionary has the whole story of each, with its syntax and more examples.