Picture the first ten minutes of a trading desk's morning. Someone has an order to place in London and another in New York. Before anything else, three questions: is each exchange actually open today, does either one close early, and if we buy today, on which day does the money really change hands?
Most of the time the answers are boring. The trouble is the days they aren't. A holiday in one country but not the other. Christmas Eve, when New York closes at one in the afternoon. A trade on a Friday that can't settle until a holiday Monday has passed. Get one of those wrong and a payment arrives a day late, or a trade fails and someone spends the afternoon on the phone explaining why.
MarketClock is my answer to those three questions. It covers the 30 stock exchanges and financial markets in the open-source holidays library, from the NYSE and Nasdaq to London, Tokyo, Hong Kong and Frankfurt. It tells you whether a market is open right now, with a countdown to the close. It works out settlement dates across several markets at once. And it checks its own data against the calendars the exchanges publish themselves. I built all of it in October 2026, across 24 pull requests.
This is how it fits together, the parts that fought back, and the one rule that shaped everything.
The rule: no answer without a source
The holidays library is excellent at one thing: knowing which days a market is closed. It's maintained by a large community and updated several times a year. I decided early that MarketClock would never keep its own copy of those dates. The library is the single source, and the app only asks it.
Everything else a trader needs, the library doesn't have. Trading hours. Early-close times. How many days a trade takes to settle in each country. Those had to come from somewhere else, and that's where most projects quietly start guessing.
So I wrote one rule into the project's instructions before writing any code: every fact that doesn't come from the library is stored with the link to the page it came from. A settlement cycle has a regulator's announcement behind it. A trading hour has the exchange's own page. If I couldn't open that page and read the fact myself, the fact didn't go in.
That rule cost me. Several exchange websites refuse automated visitors. A couple were down for maintenance the whole time I was building. One industry briefing I wanted to cite had moved, and its old link led nowhere. Each time, the honest move was the same: leave the market without that piece of data and say so on the page. A market with no confirmed hours shows "hours not on file" instead of a guess dressed up as an answer.
It also paid back. The settlement calculator can show you, under its answer, exactly which rule it used and a link to read it yourself.

One place that knows what day it is
The second decision was where the date logic lives.
It lives in one small package of plain Python, with no web framework and no database in it. The API calls it, the calendar feeds call it, the status badges call it. None of them do date maths of their own. It has full branch coverage, which means a test exercises every path through it, and the build refuses any change that lowers that.
The reason is trust. If the market page worked out "trading day" one way and the settlement tool another, sooner or later they would disagree, and the person looking at both would stop believing either.
Inside that package, I leaned on the library rather than around it. When I needed "the next trading day", the library already had a function for it, tested against far more calendars than I'll ever check by hand. Every time I was tempted to write my own loop, I used theirs.
The question that sounds simple: when does it settle?
When you buy a share, you don't own it the moment you click. The trade is agreed today, but the money and the shares actually swap a little later. In the United States that's one business day later, written T+1. In London today it's two, T+2.
Business days, though, are where it gets interesting. A day only counts if the market is open. And if your trade involves two markets, a day only counts if both are open.
Take an order placed on 23 December 2026 that touches both New York and London, on a two-day cycle. Christmas Eve counts: both markets are open, if only for the morning. Christmas Day doesn't. The 26th and 27th are a weekend. Monday the 28th, New York is open, but London is closed for Boxing Day, which moves to Monday because the 26th falls on a Saturday. So the second shared business day is Tuesday the 29th. Most people would have guessed the 28th.

There was one more twist. Settlement cycles change. The United States moved from T+2 to T+1 on 28 May 2024, and the UK plans to make the same move in October 2027. A tool that stores one number per country gets every older trade wrong, and back offices look at old trades all the time.
So each cycle is stored with the date it took effect. Ask about a trade from 2020 and MarketClock uses T+2. Ask about one from last week and it uses T+1. Leave the cycle out entirely and it picks the rule in force on that trade date and tells you where it found it.
Is it open right now?
This sounds like the easiest question, and it was the one I rewrote the most.
"Now" is different in every market. When it's Friday night in New York, it's already Saturday morning in Tokyo. So MarketClock reads each exchange's date in its own time zone before asking anything else. Then it checks the day: weekend, holiday, half day or normal. Then the clock: before the open, during the session, after an early close.
The result is a small badge on every market page: "Open, closes in 2h 10m", or "Closed (holiday), opens Monday 09:30". The markets list shows the same thing for all 30 exchanges at once.
The part I'm proudest of is the case where it says less. For markets whose trading hours I couldn't confirm, the badge still knows a weekend from a working day, because that comes from the library. It just won't claim the market is open at 3 p.m. if it doesn't know when the session ends.
Also readOne Seat, Two Buyers: Race Conditions, IDOR and Keys in a Cinema Booking System
The Last Mango Problem: Race Conditions in a Real Marketplace
Checking the library against the exchanges
If the whole app trusts one library, the obvious question is: how do we know the library is right?
So I built a data-quality page. I took the calendars the exchanges publish themselves, entered every closed day and early close with the date I read them, and compared them day by day with the library. Only whole years go in, because a half-published year would show false gaps.
The first three were the New York Stock Exchange for 2026 to 2028, Nasdaq for 2026 and the London Stock Exchange for 2027 and 2028. Sixty-six official days in all. Every one matched.
I'll admit that was slightly disappointing. I had half hoped to find a mistake and send the fix back to the library, which is how open source is supposed to work. But a clean result is still a result, and now there's a page that proves it, with the sources linked.

Small things people actually use
Not everyone wants a website. Some people want the closures in the calendar they already live in, so every market has a calendar feed you can subscribe to in Google Calendar, Apple Calendar or Outlook. It always covers this year and next, so a subscription never quietly runs out.
There's a page per market per year, like "NYSE holidays 2027", and a yearly page that lists every exchange's closures side by side. There's a calculator for adding or counting business days. There's a small card other websites can embed to show whether a market is open. And there's a watchlist, kept only in your own browser, that can remind you, while the site is open in a tab, the day before a market you follow closes. Nothing about you is ever stored on a server, because there are no accounts to store it in.

What I got wrong
My 3D globe froze the page. The home page has a rotating globe of exchange cities, and it looked lovely on my laptop. Then I ran a performance audit, which simulates a slower phone without a graphics chip. The globe was being drawn by the processor instead, and it blocked the page for over a minute. The fix was to draw a simple dotted sphere first and only load the real globe on large screens with a proper graphics chip, after the page has finished loading.
A fade-in made the page look slow. The big headlines slid in with a fade. Browsers don't count invisible text when they measure how fast a page appears, so the fade made the site look seconds slower than it was. The headlines now flip into place without fading.
My rate limit could be fooled. To stop anyone hammering the API, each visitor gets a number of requests per minute. My first version identified visitors by the first address in a header that the visitor can write themselves. Changing that header would have given anyone a fresh allowance. It now reads the last address, the one my own server adds.
I trusted a "helpful" library default. The validation library happily accepted a long number like 1782950400 as a date, because it's a valid timestamp for midnight. Nobody types that by accident, but an API that accepts it is an API that will surprise someone. Dates must now be written as year, month and day, and nothing else.
By the numbers
- 30 exchanges and markets, each with its own weekend
- 66 official holiday dates checked against the library, all matching
- 210 automated tests: 172 on the backend, 38 on the frontend
- 100% branch coverage on the date logic
- 24 pull requests, every one checked by CI and CodeQL before it merged
What's next
The code is ready. MarketClock goes live in February 2027. After that, the work is mostly outside the code: more exchange calendars for the data-quality page as their websites become readable, trading hours for the markets that still say "not on file", and the first real trader telling me what I missed.
If I started again, I would write the rule about sources on day one, exactly as I did, and I would test on a slow phone from the first week instead of the last.
The source is on GitHub, and I wrote about settlement itself, for people who have never placed a trade, in The day the money moves.
Up next
Keep reading.
01HolidayOps: Building a Working Days API for 250 Countries
How I built HolidayOps on my own: a Django and React platform that tells payroll, HR and logistics teams whether any date is a working day in any country, with company calendars, iCal feeds, signed webhooks and a public site that needs no JavaScript.
9 minThe Engineering Logs
02BookMyMovie: Building a Cinema Ticketing Platform
How I built BookMyMovie on my own, a Laravel, React and MySQL cinema booking platform with live seat maps, trailers, QR e-tickets that work offline, online payments and an Urdu interface: stack, architecture, data model, design, SEO, security, what broke and what I would change.
17 minThe Engineering Logs
03GleanGrid: Building a Pre-Order Marketplace for Farmers Markets
How I designed and built GleanGrid on my own, a Laravel and React marketplace where Hyderabad's farmers publish weekly stock and customers reserve it, pay online or at the stall, and collect it: architecture, data model, payments, security and UX.
15 minThe Engineering Logs
04Zovita+: Building an Online Pharmacy That Adapts to Each Shopper
How I rebuilt Zovita+, an online pharmacy with 1,186 real medicines, a 3D symptom body map, personal offers, drug-interaction warnings, refill reminders, pharmacist-reviewed prescriptions, Urdu, and card or cash payments, on Laravel, React and MySQL: stack, data model, checkout locking, payments, admin, security, SEO, testing, what broke and what I'd change.
22 minThe Engineering Logs
05The Day the Money Moves
When you buy a share, you don't own it the moment you click. A plain-language story of trade settlement, T+1 and T+2, why holidays in two countries can push a payment back a day, and what building MarketClock taught me about dates that have a history.
4 minThe Engineering Logs
06The Discount That Knew You Were Hesitating: Rule-Based Personalisation in an Online Pharmacy
How Zovita+ turns browsing into personal discounts without a machine-learning model: one visitor key for guests and customers, interaction counters, six offer rules, one pricing function for the bag and the charge, offers locked and redeemed once at checkout, guest-to-account merging, A/B tests, and the edge cases that shaped it.
10 minThe Engineering Logs
