If you pull filings from SEC's submissions API (data.sec.gov/submissions/CIK##########.json), each one comes with an acceptanceDateTime like 2026-07-14T14:30:38.000Z. The Z says UTC. For a large share of companies that is not true, and which companies depends on the file you read, not on the filing.
That matters whenever the time of day matters: whether results came out before the open or after the close, which trading day an insider purchase belongs to, or an event study's day 0.
What I measured
On 2026-10-11 I took 25 companies' submissions files: the 12 newest filings in each, plus 6 from December to February to cover standard time. That is 450 filings across 34 form types, 98 filing agents and three years.
For each one I compared acceptanceDateTime with the "Accepted" time printed on the filing's index page (.../{accession}-index.htm). That page is in US Eastern time and matches the filing's own SGML header.
What I found
Every file was either right for all its filings, or off by exactly one Eastern offset for all of them: +4 hours for filings accepted in daylight time, +5 hours in standard time. No other offset appeared, whatever the form, filing agent or time of day.
| Right | Off by one Eastern offset |
|---|---|
| MSFT, GOOGL, XOM, PFE, KO, TSLA, NFLX, INTC, GE, F, O, SPY | AAPL, NVDA, AMZN, META, JPM, BAC, WMT, BRK, TSM, GME, PLTR, MRNA, Vanguard |
So JPMorgan's results 8-K, accepted at 06:30 Eastern (10:30 UTC), shows up as 14:30Z: after the open instead of before it.
The same filing reads differently in two files. A Form 4 sits in both the company's file and the insider's own file. Apple's director Form 4s from 26 February:
| Accession | Apple's file | Director's file | Index page (Eastern) |
|---|---|---|---|
| 0001059235-26-000004 | 2026-02-27T04:34:19Z | 2026-02-26T23:34:19Z | 2026-02-26 18:34:19 |
| 0001216519-26-000004 | 2026-02-27T04:33:49Z | 2026-02-26T23:33:49Z | 2026-02-26 18:33:49 |
The director's files are right; Apple's file is five hours late (February is standard time). You can check it yourself with the standard library:
import json, re, urllib.request
UA = {"User-Agent": "Your Name you@example.com"} # SEC asks for a contact
get = lambda u: urllib.request.urlopen(urllib.request.Request(u, headers=UA)).read().decode()
acc = "0001059235-26-000004"
for cik in (320193, 1059235): # Apple's file, then the director's
r = json.loads(get(f"https://data.sec.gov/submissions/CIK{cik:010d}.json"))["filings"]["recent"]
print(cik, r["acceptanceDateTime"][r["accessionNumber"].index(acc)])
html = get(f"https://www.sec.gov/Archives/edgar/data/320193/{acc.replace('-', '')}/{acc}-index.htm")
print("index:", re.search(r'Accepted</div>\s*<div class="info">([^<]+)', html).group(1))
These are the values on 11 October. The files change, which is the next point.
The split follows each file's newest filing. Every file whose newest filing was accepted on or before 2 October was right. Every file whose newest filing was accepted on or after 5 October was off, including its filings from February. My guess is that files rebuilt since early October are written with the extra offset. I can't see rebuild times (the API sends no Last-Modified header), so that is a hypothesis, not a finding.
I wasn't the first to notice. An edgartools issue (dgunning/edgartools#1501) reported Apple four hours late on 8 October, and on 7 October some files that gave Eastern time labelled as UTC. I added the data above there.
What to do about it
Read the time from the index page or the SGML header when it matters. That costs one request per filing.
Because a file is uniform, one request per file is enough. Measure the file's error on one filing, then correct the rest:
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
ET = ZoneInfo("America/New_York")
def file_shift(api_iso, accepted_et):
"""A submissions file's error in Eastern offsets (-1, 0 or 1), from one filing's index-page time."""
api = datetime.fromisoformat(api_iso.replace("Z", "+00:00"))
true = datetime.strptime(accepted_et, "%Y-%m-%d %H:%M:%S").replace(tzinfo=ET)
k = (api - true) / -true.utcoffset() # the offset is 4 h (EDT) or 5 h (EST)
if k not in (-1, 0, 1):
raise ValueError(f"unexpected shift {k}")
return int(k)
def corrected(api_iso, k):
"""The true acceptance time of any filing in a file whose shift is k."""
api = datetime.fromisoformat(api_iso.replace("Z", "+00:00"))
if k == 0:
return api
for h in (4, 5):
t = api - k * timedelta(hours=h)
if -t.astimezone(ET).utcoffset() == timedelta(hours=h):
return t
k = file_shift("2026-02-27T04:34:19.000Z", "2026-02-26 18:34:19") # Apple's file: 1
corrected("2026-07-14T14:30:38.000Z", k) # a 06:30 ET filing: 10:30:38 UTC
Calibrate on two filings from different seasons, and read every filing from its own index page if they disagree. Recalibrate whenever you re-download the file, because a rebuild can change it.
Where it bit me
canli-mcp's earnings_calendar already read times from the index pages. Its event_study did not: it took acceptanceDateTime to decide whether a filing came before or after the 16:00 close.
With today's files the damage is small. Only afternoon filings move to the next day: 1 of 31 JPMorgan 8-Ks since 2025, and none of 55 NVIDIA insider sales. A file that gives Eastern time labelled UTC would be worse: every results release after the close would land on its own day. event_study now calibrates each file this way, with two extra requests, and says in its result which it did.
Try it
canli-mcp is a free, MIT-licensed MCP server for finance: 306 tools behind three, reading SEC filings, insider trades, 13F and 13D/G holdings, options, FOMC and macro data straight from the sources, with no API key for almost everything.
npx -y canli-mcp
# Claude Code
claude mcp add canli -- npx -y canli-mcp
The code is on GitHub:
-
arhancanli/canlicapital: every MCP server, including the fix (
acceptanceTimesinmcp-markets/src/sources.mjs), the benchmarks and the site. - arhancanli/alphac: the strategy research engine.
If you have seen other EDGAR fields that don't mean what they say, I'd like to hear about them.
Top comments (0)