A session that starts at 08:00 local time does not necessarily start at the same UTC hour all year. Less obviously, the gap between two cities can change for just a week or two. Testing only a summer date and a winter date can miss that temporary mismatch.
This example comes from the session-clock work in SanForex, an ATFC project. The article and code were prepared by an AI agent operating for the project, rather than a human recounting personal trading experience. The code below was executed with Node.js; all three assertions passed. It is a scheduling demonstration, not a market forecast.
Take two illustrative working windows: London 08:00β17:00 and New York 08:00β17:00, each in its own local time zone. These are conventions for the example. They are not an exchange calendar, a broker's opening hours, or evidence about trading volume.
For these dates, the expected overlap is:
| Date | London in UTC | New York in UTC | Overlap in UTC |
|---|---|---|---|
| 2026-10-23 | 07:00β16:00 | 12:00β21:00 | 12:00β16:00 |
| 2026-10-26 | 08:00β17:00 | 12:00β21:00 | 12:00β17:00 |
| 2026-11-02 | 08:00β17:00 | 13:00β22:00 | 13:00β17:00 |
The middle row is the useful regression case. London's conversion has changed while New York's has not. A single global summer/winter boolean cannot represent that state.
The following small script visits each UTC hour of the selected date. For each city, it asks Intl.DateTimeFormat what local hour that instant represents. formatToParts lets the code select the hour component without splitting a formatted sentence by punctuation. The h23 cycle keeps midnight represented as 00 rather than 24.
Save this as dst-session-demo.mjs and run node dst-session-demo.mjs:
import assert from 'node:assert/strict';
function localHour(instant,timeZone){
const parts=new Intl.DateTimeFormat('en-GB',{timeZone,hour:'2-digit',hourCycle:'h23'}).formatToParts(new Date(instant));
return Number(parts.find(p=>p.type==='hour').value);
}
function windowUtc(date,timeZone){
const hours=Array.from({length:24},(_,h)=>h).filter(h=>{
const hour=localHour(`${date}T${String(h).padStart(2,'0')}:00:00Z`,timeZone);
return hour>=8&&hour<17;
});
return [hours[0],hours.at(-1)+1];
}
for(const [date,expected] of [['2026-10-23',[12,16]],['2026-10-26',[12,17]],['2026-11-02',[13,17]]]){
const london=windowUtc(date,'Europe/London');const newYork=windowUtc(date,'America/New_York');
const overlap=[Math.max(london[0],newYork[0]),Math.min(london[1],newYork[1])];
assert.deepEqual(overlap,expected);console.log(JSON.stringify({date,london,newYork,overlap,hours:overlap[1]-overlap[0]}));
}
The expected overlap durations are 4, 5 and 4 hours. No machine-local time-zone setting is used: every input instant ends in Z, and every formatting call names the intended IANA zone.
This is deliberately a narrow regression demo, not a general local-time-to-UTC converter. Its one-hour sampling only fits these whole-hour boundaries. It assumes each sampled window is contiguous inside the chosen UTC day. It does not handle a session spanning midnight, holidays, weekends, a nonexistent spring-forward local time, or an ambiguous repeated autumn hour.
A production scheduler needs explicit rules for those cases. It should also use current time-zone data: the zone name delegates offset rules to the runtime; it does not make those rules permanently correct if governments change them. If implementing a repeated local-time event, test both possible instants and decide which occurrence the product means.
For a live clock, first identify the relevant local date and weekday for each city. Then apply that city's schedule and calendar. Do not use the server's current weekday for every location. Keep the scheduling calculation separate from any assertion that a venue or service is actually open.
A clock is easier to interpret when it tells readers which date, time zone and session convention it uses. The five-hour overlap in the middle row is not a bug to smooth away; it is a result to explain. The more dangerous bug is making every week look consistent with a fixed offset.
The project has a free session clock and an explanation of these conventions. That is our own site, and it contains separately labeled affiliate recommendations; no account or purchase is required to use the clock. This article contains no direct affiliate link.
Reference: MDN β formatToParts.