> For the complete documentation index, see [llms.txt](https://stonkmarket.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://stonkmarket.gitbook.io/docs/smart-contracts/market-hours-oracle.md).

# MarketHoursOracle

A shared oracle contract that determines whether the NYSE market is currently open. All tokens on a chain — and that chain's [StonkHook](/docs/smart-contracts/stonk-hook.md) — reference a single oracle, saving \~500K gas per deployment.

Each deployment has its own. On Base the v1 oracle was reused unchanged in v2, so the schedule and holiday calendar carried straight over; Robinhood Chain had none, so its deploy stood up a second, independent one. The two are unrelated contracts: a holiday added to one does not appear on the other.

## Overview

| Property     | Value                           |
| ------------ | ------------------------------- |
| Contract     | `MarketHoursOracle.sol`         |
| Inherits     | `Ownable`, `IMarketHoursOracle` |
| Dependencies | `BokkyPooBahsDateTimeLibrary`   |
| Market Open  | 9:30 AM ET                      |
| Market Close | 4:00 PM ET                      |

| Network                | Address                                                                                                                                  |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Base mainnet (8453)    | [`0x6521aCb39535A7397863efefc08bC2Cf9C5f68b4`](https://basescan.org/address/0x6521aCb39535A7397863efefc08bC2Cf9C5f68b4)                  |
| Robinhood Chain (4663) | [`0xD454Ce3959F3f68Bfbd45AB6bD2beE3B2E7dd7AE`](https://robinhoodchain.blockscout.com/address/0xD454Ce3959F3f68Bfbd45AB6bD2beE3B2E7dd7AE) |

## How It Works

The oracle performs pure math calculations on Unix timestamps to determine market state. No external data feeds or oracles are required.

### Check Order

1. **Is it a holiday?** → Check the `fixedHolidays` mapping for `YYYYMMDD` key
2. **Is it a weekend?** → Calculate day of week from timestamp
3. **Is it within market hours?** → Convert UTC to Eastern Time, check 9:30-16:00

### DST Handling

The oracle automatically determines whether Daylight Saving Time is in effect:

| Period        | Offset | Market Open (UTC) | Market Close (UTC) |
| ------------- | ------ | ----------------- | ------------------ |
| EDT (Mar-Nov) | UTC-4  | 13:30             | 20:00              |
| EST (Nov-Mar) | UTC-5  | 14:30             | 21:00              |

DST transitions follow US rules:

* **Spring forward:** 2nd Sunday in March
* **Fall back:** 1st Sunday in November

## Holiday Management

Holidays are **not** hardcoded. The oracle starts empty and the owner loads dates, which are stored as `YYYYMMDD` integer keys in a mapping (e.g. `20260101` for Jan 1, 2026). Every function takes date components, not a pre-built key.

### Functions

| Function                                                                    | Access | Description                        |
| --------------------------------------------------------------------------- | ------ | ---------------------------------- |
| `addHoliday(year, month, day, name)`                                        | Owner  | Add a single holiday               |
| `removeHoliday(year, month, day)`                                           | Owner  | Remove a holiday                   |
| `updateHoliday(oldYear, oldMonth, oldDay, newYear, newMonth, newDay, name)` | Owner  | Move a holiday to a different date |
| `batchAddHolidays(years[], months[], days[], names[])`                      | Owner  | Add multiple holidays in one call  |

There is no batch-remove function. `batchAddHolidays` reverts with `ArrayLengthMismatch` if the four arrays are not the same length.

Holiday changes take effect immediately for **every** token that references the oracle, including tokens deployed long before the change.

### Holidays Currently Loaded

Both oracles — Base and Robinhood Chain — currently carry the same twenty dates: the full 2026 and 2027 NYSE calendars.

| 2026       |                             | 2027       |                             |
| ---------- | --------------------------- | ---------- | --------------------------- |
| 2026-01-01 | New Year's Day              | 2027-01-01 | New Year's Day              |
| 2026-01-19 | Martin Luther King Jr. Day  | 2027-01-18 | Martin Luther King Jr. Day  |
| 2026-02-16 | Washington's Birthday       | 2027-02-15 | Washington's Birthday       |
| 2026-04-03 | Good Friday                 | 2027-03-26 | Good Friday                 |
| 2026-05-25 | Memorial Day                | 2027-05-31 | Memorial Day                |
| 2026-06-19 | Juneteenth                  | 2027-06-18 | Juneteenth (observed)       |
| 2026-07-03 | Independence Day (observed) | 2027-07-05 | Independence Day (observed) |
| 2026-09-07 | Labor Day                   | 2027-09-06 | Labor Day                   |
| 2026-11-26 | Thanksgiving Day            | 2027-11-25 | Thanksgiving Day            |
| 2026-12-25 | Christmas Day               | 2027-12-24 | Christmas (observed)        |

Later years must be loaded by the owner, on each chain separately, before they arrive. An unloaded year fails **open** — the market trades through the holiday rather than halting — so this is a live-configuration matter, not something the contract can infer. Call `getHolidays()` on the oracle for the chain you care about to read its live list.

## Key Functions

### View

| Function                                  | Returns                                                                                                        |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `isMarketOpen()`                          | `true` if the market is currently open                                                                         |
| `getMarketState()`                        | Current `MarketState` enum value                                                                               |
| `getCurrentHoliday()`                     | `"Market Holiday"` if today is a holiday, otherwise `"Not a Holiday"`                                          |
| `getNextMarketOpen(year, month, day)`     | Next market open — today at 9:30 AM ET if that is still ahead on a trading day, otherwise the next trading day |
| `getNextTradingDayOpen(year, month, day)` | Next open, always skipping to a later calendar day                                                             |
| `getEasternTime()`                        | `block.timestamp` shifted into Eastern Time                                                                    |
| `isDST()`                                 | Whether DST is in effect right now (no timestamp argument)                                                     |
| `timestampToDate(timestamp)`              | `(year, month, day)` for a timestamp                                                                           |
| `fixedHolidays(dateKey)`                  | Whether a `YYYYMMDD` key is registered as a holiday                                                            |
| `getHolidays()`                           | Array of all registered `YYYYMMDD` keys                                                                        |
| `getHolidayCount()`                       | Number of registered holidays                                                                                  |

The holiday, weekend, and trading-hours checks themselves are `internal` — read them through `getMarketState()`, `isMarketOpen()`, or `fixedHolidays(dateKey)`.

## Events

| Event            | Description            |
| ---------------- | ---------------------- |
| `HolidayAdded`   | New holiday registered |
| `HolidayRemoved` | Holiday removed        |
| `HolidayUpdated` | Holiday date changed   |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://stonkmarket.gitbook.io/docs/smart-contracts/market-hours-oracle.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
