Strasmore Research
Learn Matt ConnorBy Matt Connor · Updated 2026-08-26 · data as of August 26, 2026 · refreshed weekly

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.

QueryMarket status computed at this page's refresh: weekday check, holiday check, and the ET clock
date_checkedweekdaytime_checked_ettodays_calendarmarket_statusnext_regular_sessiondays_to_next_session
2026-08-26Wednesday09:00normal weekdayPREMARKET2026-08-260
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_session
Run this yourself

As 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.

QueryEvery upcoming NYSE closure and early close on the calendar feed, with a countdown
closure_datefalls_onholidayday_statuscloses_at_etdays_away
2026-09-07MonLabor Dayclosed12
2026-11-26ThuThanksgivingclosed92
2026-11-27FriThanksgivingearly-close13:0093
2026-12-24ThuChristmasearly-close13:00120
2026-12-25FriChristmasclosed121
2027-01-01FriNew Years Dayclosed128
2027-01-18MonMartin Luther King, Jr. Dayclosed145
2027-02-15MonWashington's Birthdayclosed173
2027-03-26FriGood Fridayclosed212
2027-05-31MonMemorial Dayclosed278
2027-06-18FriJuneteenthclosed296
2027-07-05MonIndependence Dayclosed313
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 16
Run this yourself

The 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.

QueryThis calendar year's closures: already passed (counted from the tape) plus still ahead (from the calendar)
categoryalready_passedstill_aheadtotalcalendar_year
full closure73102026
early close (1:00 pm)2242026
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 ord
Run this yourself

2026 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.

QueryThe most recent session on the tape: bar count, same-day SPY options prints, and the last half-day observed
most_recent_sessionweekdayregular_minute_barsspy_option_prints_thousandslast_early_closeearly_close_bars
2026-08-25Tuesday20410742026-08-25204
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_bars
Run this yourself

The 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.

QueryUnscheduled closures on the tape: zero regular-session bars on an ordinary weekday
closure_datefalls_onnamespy_regular_session_bars
2012-10-29MonHurricane Sandy — day 10
2012-10-30TueHurricane Sandy — day 20
2012-10-31WedReopening after Sandy390
2018-12-05WedMourning — George H. W. Bush0
2025-01-09ThuMourning — Jimmy Carter0
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.1
Run this yourself

Hurricane 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:

QuerySPY across recent weekends and holiday weekends: Friday's close vs. the reopening print
last_session_beforereopening_sessiondays_darkclose_before_breakreopening_printgap_pct
Fri 2026-06-12Mon 2026-06-153741.63751.851.38
Thu 2026-06-18Mon 2026-06-224746.56747.70.15
Fri 2026-06-26Mon 2026-06-293729.09736.521.02
Thu 2026-07-02Mon 2026-07-064744.8748.740.53
Fri 2026-07-10Mon 2026-07-133754.9752.47-0.32
Fri 2026-07-17Mon 2026-07-203743.2747.060.52
Fri 2026-07-24Mon 2026-07-273738.85744.910.82
Fri 2026-07-31Mon 2026-08-033746.81749.440.35
Fri 2026-08-07Mon 2026-08-103773.2772.6-0.08
Fri 2026-08-14Mon 2026-08-173776.3776.18-0.02
Fri 2026-08-21Mon 2026-08-243766.95763.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 d
Run this yourself

The 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:

QueryWeekdays in the trailing year when stocks traded but no Treasury yield printed
session_dateweekday
2025-10-13Monday
2025-11-11Tuesday
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 d
Run this yourself

In 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.