Is the Stock Market Open Today?
Is the US stock market open today? A computed open/closed status, today's calendar, every upcoming holiday, and what happens to orders placed while it's closed.
The US stock market is open Monday through Friday, 9:30 am to 4:00 pm Eastern, except on scheduled holidays and a few 1:00 pm early closes, so "is the stock market open today?" reduces to three checks: is it a weekday, is it on the holiday calendar, and where does the clock sit in the session. This page runs all three against live exchange records on every refresh, and the "data as of" stamp above is its freshness receipt. For the session-by-session clock see stock market hours; for the full calendar, market holidays and early closes.
Is the stock market open right now?
The panel below computes the answer at the moment this page's data was last refreshed. It checks the weekday, looks today's date up in the exchange holiday feed, and places the Eastern-time clock inside or outside the official windows: premarket from 4:00 am, the regular session from 9:30 am, after-hours from the close until 8:00 pm.
| date_checked | weekday | time_checked_et | todays_calendar | market_status | next_regular_session | days_to_next_session |
|---|---|---|---|---|---|---|
| 2026-08-26 | Wednesday | 09:00 | normal weekday | PREMARKET | 2026-08-26 | 0 |
The exact SQL behind every number
WITH
toTimeZone(now(), 'America/New_York') AS now_et,
toDate(now_et) AS today_et,
toHour(now_et) * 60 + toMinute(now_et) AS min_now,
(SELECT countDistinct(date) FROM global_markets.stocks_market_holidays
WHERE date = toDate(toTimeZone(now(), 'America/New_York')) AND status = 'closed') AS today_full_holiday,
(SELECT countDistinct(date) FROM global_markets.stocks_market_holidays
WHERE date = toDate(toTimeZone(now(), 'America/New_York')) AND status = 'early-close') AS today_early,
(SELECT any(name) FROM global_markets.stocks_market_holidays
WHERE date = toDate(toTimeZone(now(), 'America/New_York'))) AS today_holiday_name,
if(today_early = 1, 780, 960) AS close_min,
if(today_early = 1, 1020, 1200) AS after_hours_end,
(SELECT min(d) FROM (SELECT toDate(toTimeZone(now(), 'America/New_York')) + arrayJoin(range(1, 11)) AS d)
WHERE toDayOfWeek(d) <= 5
AND d NOT IN (SELECT date FROM global_markets.stocks_market_holidays WHERE status = 'closed')) AS next_sess_after_today,
toDayOfWeek(today_et) <= 5 AND today_full_holiday = 0 AS today_is_session
SELECT
toString(today_et) AS date_checked,
formatDateTime(today_et, '%W') AS weekday,
formatDateTime(now_et, '%H:%i') AS time_checked_et,
multiIf(toDayOfWeek(today_et) >= 6, 'weekend',
today_full_holiday = 1, concat('holiday — ', today_holiday_name),
today_early = 1, concat('early close (1:00 pm) — ', today_holiday_name),
'normal weekday') AS todays_calendar,
multiIf(NOT today_is_session, 'CLOSED',
min_now < 240, 'CLOSED (overnight)',
min_now < 570, 'PREMARKET',
min_now < close_min, 'OPEN',
min_now < after_hours_end, 'AFTER-HOURS',
'CLOSED (overnight)') AS market_status,
toString(if(today_is_session AND min_now < close_min, today_et, next_sess_after_today)) AS next_regular_session,
dateDiff('day', today_et, if(today_is_session AND min_now < close_min, today_et, next_sess_after_today)) AS days_to_next_sessionAs of 09:00 ET on Wednesday, 2026-08-26, the computed status read PREMARKET, with today's calendar entry "normal weekday". The next regular-session open on the schedule, today itself whenever the status reads PREMARKET or OPEN, is 2026-08-26. That date already skips weekends and every full-closure holiday, and it is never more than a few days out, even across a long holiday weekend. Reading this later than the stamp? The same three checks take seconds by hand: weekday, the holiday table below, the ET clock.
The next scheduled closure, and everything after it
The forward calendar comes straight from the exchange feed. One nuance worth knowing: the table includes today whenever today is itself a holiday or an early close, the query asks for every closure from today forward, not strictly after it, so on a holiday morning the first row and the status panel above agree with each other.
| closure_date | falls_on | holiday | day_status | closes_at_et | days_away |
|---|---|---|---|---|---|
| 2026-09-07 | Mon | Labor Day | closed | 12 | |
| 2026-11-26 | Thu | Thanksgiving | closed | 92 | |
| 2026-11-27 | Fri | Thanksgiving | early-close | 13:00 | 93 |
| 2026-12-24 | Thu | Christmas | early-close | 13:00 | 120 |
| 2026-12-25 | Fri | Christmas | closed | 121 | |
| 2027-01-01 | Fri | New Years Day | closed | 128 | |
| 2027-01-18 | Mon | Martin Luther King, Jr. Day | closed | 145 | |
| 2027-02-15 | Mon | Washington's Birthday | closed | 173 | |
| 2027-03-26 | Fri | Good Friday | closed | 212 | |
| 2027-05-31 | Mon | Memorial Day | closed | 278 | |
| 2027-06-18 | Fri | Juneteenth | closed | 296 | |
| 2027-07-05 | Mon | Independence Day | closed | 313 |
The exact SQL behind every number
SELECT toString(date) AS closure_date,
formatDateTime(date, '%a') AS falls_on,
any(name) AS holiday,
any(status) AS day_status,
any(if(status = 'early-close', formatDateTime(toTimeZone(close, 'America/New_York'), '%H:%i'), '')) AS closes_at_et,
dateDiff('day', today(), date) AS days_away
FROM global_markets.stocks_market_holidays
WHERE exchange = 'NYSE' AND date >= today()
GROUP BY date
ORDER BY date
LIMIT 16The next scheduled interruption is Labor Day on 2026-09-07 (closed), 12 days from the refresh stamp. Any weekday not in this table is a normal 9:30–4:00 session. Early-close days end regular trading at 1:00 pm Eastern and cluster around Thanksgiving, Christmas Eve, and the Fourth of July; the closing auction still runs on those days, it simply prints three hours early.
How many days is the market closed each year?
"About nine or ten holidays a year" is the stock answer, this page can count instead of estimate. The exchange feed only carries closures still ahead, so the ones already passed are recovered from the tape: a weekday on which SPY printed zero regular-session minute bars was a full closure, and one that printed roughly half a session (about 210 bars instead of 390) was an early close.
| category | already_passed | still_ahead | total | calendar_year |
|---|---|---|---|---|
| full closure | 7 | 3 | 10 | 2026 |
| early close (1:00 pm) | 2 | 2 | 4 | 2026 |
The exact SQL behind every number
WITH day_bars AS (
SELECT cal.day AS day, ifNull(t.bars, 0) AS bars
FROM (SELECT makeDate(toYear(today()), 1, 1) + arrayJoin(range(370)) AS day) AS cal
LEFT JOIN (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, count() AS bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(makeDate(toYear(today()), 1, 1), 'America/New_York')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
) AS t ON t.d = cal.day
WHERE toDayOfWeek(cal.day) BETWEEN 1 AND 5
AND cal.day <= today() - 4
),
past AS (
SELECT countIf(bars = 0) AS past_full, countIf(bars BETWEEN 120 AND 330) AS past_early
FROM day_bars
),
ahead AS (
SELECT countDistinctIf(date, status = 'closed') AS ahead_full,
countDistinctIf(date, status = 'early-close') AS ahead_early
FROM global_markets.stocks_market_holidays
WHERE date > today() - 4 AND toYear(date) = toYear(today())
)
SELECT category, already_passed, still_ahead, already_passed + still_ahead AS total, toString(toYear(today())) AS calendar_year
FROM (
SELECT 'full closure' AS category, past.past_full AS already_passed, ahead.ahead_full AS still_ahead, 1 AS ord FROM past, ahead
UNION ALL
SELECT 'early close (1:00 pm)' AS category, past.past_early AS already_passed, ahead.ahead_early AS still_ahead, 2 AS ord FROM past, ahead
)
ORDER BY ord2026 carries 10 full closures, 7 already behind, 3 still ahead, plus 4 scheduled 1:00 pm early closes, 2 of them still to come. (A closure inside the last few days can sit briefly in neither count while the tape's ingest lag clears; the split self-corrects on the next refresh.) Weekends do the rest of the closing: subtract the roughly 104 weekend days and these holidays from 365, and a year leaves about 250 trading sessions.
The tape's receipt: the most recent session
A calendar says what should happen; the tape says what did. The panel below pulls the most recent session actually observed on our SPY minute-bar tape, its bar count, the number of SPY option trades printed the same day, and the most recent half-day anywhere on the trailing tape.
| most_recent_session | weekday | regular_minute_bars | spy_option_prints_thousands | last_early_close | early_close_bars |
|---|---|---|---|---|---|
| 2026-08-25 | Tuesday | 204 | 1074 | 2026-08-25 | 204 |
The exact SQL behind every number
WITH rth AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, count() AS bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= today() - 450
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
),
last_sess AS (
SELECT max(d) AS last_d
FROM rth
WHERE bars >= 120 AND d < toDate(toTimeZone(now(), 'America/New_York'))
),
opt AS (
SELECT round(count() / 1e3, 0) AS spy_option_prints_thousands
FROM global_markets.options_trades
WHERE ticker >= 'O:SPY2' AND ticker < 'O:SPY3'
AND sip_timestamp >= toDateTime((SELECT last_d FROM last_sess), 'America/New_York')
AND sip_timestamp < toDateTime((SELECT last_d FROM last_sess) + 1, 'America/New_York')
),
last_early AS (
SELECT toString(max(d)) AS last_early_close_date,
argMax(bars, d) AS its_bars
FROM rth WHERE bars BETWEEN 120 AND 330
)
SELECT toString((SELECT last_d FROM last_sess)) AS most_recent_session,
formatDateTime((SELECT last_d FROM last_sess), '%W') AS weekday,
(SELECT bars FROM rth WHERE d = (SELECT last_d FROM last_sess)) AS regular_minute_bars,
(SELECT spy_option_prints_thousands FROM opt) AS spy_option_prints_thousands,
(SELECT last_early_close_date FROM last_early) AS last_early_close,
(SELECT its_bars FROM last_early) AS early_close_barsThe most recent session on our tape is 2026-08-25 (Tuesday), which printed 204 regular-session minute bars, a full day runs about 390, an early close about 210. The same session carried roughly 1074 thousand individual SPY option trades: the options market keeps the equity calendar, holidays and half-days included, and expirations that land on a closed Friday move up a day. The most recent early close on the tape was 2026-08-25, at 204 minute bars, the measured shape of a 1:00 pm half-day. One front-edge note: this warehouse ingests with a one-to-two-day lag, so "most recent session" here can trail the actual latest session by a day or two.
When the market closes without warning
Scheduled closures live on the calendar; unscheduled ones never do. They are rare, a handful per decade, and the tape keeps their receipts: a weekday that should have printed 390 bars and printed none.
| closure_date | falls_on | name | spy_regular_session_bars |
|---|---|---|---|
| 2012-10-29 | Mon | Hurricane Sandy — day 1 | 0 |
| 2012-10-30 | Tue | Hurricane Sandy — day 2 | 0 |
| 2012-10-31 | Wed | Reopening after Sandy | 390 |
| 2018-12-05 | Wed | Mourning — George H. W. Bush | 0 |
| 2025-01-09 | Thu | Mourning — Jimmy Carter | 0 |
The exact SQL behind every number
WITH events AS (
SELECT arrayJoin([
(toDate('2012-10-29'), 'Hurricane Sandy — day 1'),
(toDate('2012-10-30'), 'Hurricane Sandy — day 2'),
(toDate('2012-10-31'), 'Reopening after Sandy'),
(toDate('2018-12-05'), 'Mourning — George H. W. Bush'),
(toDate('2025-01-09'), 'Mourning — Jimmy Carter')
]) AS e
),
tape AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d, count() AS bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND ((window_start >= '2012-10-29 00:00:00' AND window_start < '2012-11-01 12:00:00')
OR (window_start >= '2018-12-05 00:00:00' AND window_start < '2018-12-06 12:00:00')
OR (window_start >= '2025-01-09 00:00:00' AND window_start < '2025-01-10 12:00:00'))
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
)
SELECT toString(e.1) AS closure_date,
formatDateTime(e.1, '%a') AS falls_on,
e.2 AS name,
toUInt32(ifNull(t.bars, 0)) AS spy_regular_session_bars
FROM events
LEFT JOIN tape AS t ON t.d = events.e.1
ORDER BY e.1Hurricane Sandy kept both major exchanges dark on 2012-10-29 and 2012-10-30, the first multi-day weather closure since 1888, and the reopening session on 2012-10-31 printed a full 390 bars. National days of mourning closed the market on 2018-12-05 (President George H. W. Bush) and 2025-01-09 (President Jimmy Carter). The longest unscheduled closure of the modern era, September 11 through 14, 2001, four straight sessions, predates our minute data, which begins in 2003. Each closure above shows on the tape as 0 regular-session bars: nothing traded.
What happens to an order placed while the market is closed?
Nothing executes while the market is closed. An order submitted on a Saturday, a holiday, or at 2:00 am simply queues at your broker until the next session, and a queued market order transacts at whatever price the opening auction discovers, days after you clicked. The gap between one session's close and the next session's first print is the exposure you accept, and it is measurable:
| last_session_before | reopening_session | days_dark | close_before_break | reopening_print | gap_pct |
|---|---|---|---|---|---|
| Fri 2026-06-12 | Mon 2026-06-15 | 3 | 741.63 | 751.85 | 1.38 |
| Thu 2026-06-18 | Mon 2026-06-22 | 4 | 746.56 | 747.7 | 0.15 |
| Fri 2026-06-26 | Mon 2026-06-29 | 3 | 729.09 | 736.52 | 1.02 |
| Thu 2026-07-02 | Mon 2026-07-06 | 4 | 744.8 | 748.74 | 0.53 |
| Fri 2026-07-10 | Mon 2026-07-13 | 3 | 754.9 | 752.47 | -0.32 |
| Fri 2026-07-17 | Mon 2026-07-20 | 3 | 743.2 | 747.06 | 0.52 |
| Fri 2026-07-24 | Mon 2026-07-27 | 3 | 738.85 | 744.91 | 0.82 |
| Fri 2026-07-31 | Mon 2026-08-03 | 3 | 746.81 | 749.44 | 0.35 |
| Fri 2026-08-07 | Mon 2026-08-10 | 3 | 773.2 | 772.6 | -0.08 |
| Fri 2026-08-14 | Mon 2026-08-17 | 3 | 776.3 | 776.18 | -0.02 |
| Fri 2026-08-21 | Mon 2026-08-24 | 3 | 766.95 | 763.28 | -0.48 |
The exact SQL behind every number
WITH daily AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d,
round(argMin(toFloat64(open), window_start), 2) AS open_px,
round(argMax(toFloat64(close), window_start), 2) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= today() - 75
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
),
paired AS (
SELECT d,
open_px,
lagInFrame(d) OVER (ORDER BY d) AS prev_d,
lagInFrame(close_px) OVER (ORDER BY d) AS prev_close
FROM daily
)
SELECT concat(formatDateTime(prev_d, '%a '), toString(prev_d)) AS last_session_before,
concat(formatDateTime(d, '%a '), toString(d)) AS reopening_session,
dateDiff('day', prev_d, d) AS days_dark,
toString(prev_close) AS close_before_break,
toString(open_px) AS reopening_print,
round((open_px - prev_close) / prev_close * 100, 2) AS gap_pct
FROM paired
WHERE prev_close > 0 AND dateDiff('day', prev_d, d) >= 3
ORDER BY dThe table covers the last 11 weekends and long weekends, the days_dark column marks the four-day holiday breaks. The most recent one ran from Fri 2026-08-21 to Mon 2026-08-24 (3 calendar days dark): SPY's regular-session close before the break was $766.95, the reopening print $763.28, a -0.48% gap a queued market order would have accepted sight unseen. A limit order caps the price instead, at the cost of possibly not filling; why stocks gap overnight covers the mechanics behind these moves.
Time zones, the bond market, and the rest of the world
Three mismatches generate most of the remaining "is it open" confusion. Time zones: official hours are Eastern, 9:30 am ET is 6:30 am Pacific and 2:30 pm London most of the year, and the market's dates are ET dates, so a reader in Asia can have their "today" straddle two US sessions. The bond market: Treasuries trade on the SIFMA calendar, not the NYSE's, it observes every stock-market holiday plus two more, and its early closes are 2:00 pm recommendations that come around more often than the stock market's 1:00 pm half-days. The full-day divergence is visible in the data:
| session_date | weekday |
|---|---|
| 2025-10-13 | Monday |
| 2025-11-11 | Tuesday |
The exact SQL behind every number
WITH stock_days AS (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS d
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= today() - 370
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY d
HAVING count() >= 100
)
SELECT toString(d) AS session_date,
formatDateTime(d, '%W') AS weekday
FROM stock_days
WHERE d <= (SELECT max(date) FROM global_markets.treasury_yields)
AND d NOT IN (SELECT date FROM global_markets.treasury_yields WHERE date >= today() - 370)
ORDER BY dIn the trailing year there were exactly 2 weekdays where the stock market held a full session and no Treasury yield printed, 2025-10-13 and 2025-11-11, one in October and one in November: Columbus Day and Veterans Day, the two federal holidays equities work straight through. The rest of the world: overseas exchanges keep their own calendars, and index futures trade nearly around the clock, which is how a headline can say "stocks are falling" at 3:00 am ET while every US stock exchange is dark. Extended hours around each US session run 4:00 am to 9:30 am and 4:00 pm to 8:00 pm ET, thinner and wider-spread; the mechanics live in the extended-hours guide.
FAQ
Is the stock market open right now?
As of this page's last data refresh, 09:00 ET on 2026-08-26, the computed status was PREMARKET. Past the stamp, the rule takes seconds: weekdays 9:30 am to 4:00 pm ET, minus the dates in the holiday table above.
Is the stock market open tomorrow?
Tomorrow is a normal session unless it is a Saturday, a Sunday, or a date in the closure table above. The soonest regular session on the calendar as of this page's refresh, today included, when the market is open, is 2026-08-26.
Is the stock market open on Christmas Eve?
When December 24 falls on a weekday, US stock exchanges typically hold a shortened session that closes at 1:00 pm ET; when it falls on a weekend there is no session at all. Christmas Day is always a full closure, this year's exact dates are in the calendar table above.
Is the stock market open on Black Friday?
Yes. The Friday after Thanksgiving is a scheduled half-day: regular trading ends at 1:00 pm ET instead of 4:00 pm, roughly 210 minute bars on the tape instead of 390.
Is the bond market open today?
Usually when stocks are, but not always. The Treasury market follows the SIFMA calendar: every stock-market holiday plus Columbus Day and Veterans Day, with more frequent (and earlier, 2:00 pm) early closes. The trailing-year tape shows 2 weekdays where stocks traded and Treasury yields did not print.
Every panel above is a stored, versioned query with its exact SQL underneath, expand any panel to audit it. To check any date, session, or gap yourself, ask in plain English on the Strasmore terminal.