From at least mid-September until at least October 22, 2026, acceptanceDateTime in SEC's submissions JSON (data.sec.gov/submissions/CIK##########.json) was wrong for a large share of filers, even though every value ends in Z. On October 28 every file I checked read true UTC. If your backtest cached that field before this week, the cache still holds the wrong values.
Three states, one per file
The value was in one of three states, and the whole file shared it:
- True UTC. Microsoft, Tesla (until October) and Alphabet looked like this.
-
One Eastern offset late, +4 h in summer and +5 h in winter. Apple's 10-Q
0000320193-26-000020was accepted at 06:01:02 ET on 2026-07-31, before the open. On October 21 the API returned14:01:02Z, which is 10:01 ET, half an hour into the session. -
Eastern wall time labelled
Z. Arena Pharmaceuticals' earnings 8-K of 2016-05-09 was accepted at 16:18:17 ET, after the close. The API returned16:18:17Z, which reads as 12:18 ET, mid-session. The stock opened 5.1% higher the next day.
Which state a file was in followed SEC's last rebuild of that file, not the company. On October 11 arhancanli compared 450 filings from 25 companies with their index pages: 12 files were right, and 13 were one offset late, including Apple, Nvidia, Amazon, Meta and JPMorgan. shahar-arbor found the third state in files for MMAT, SVB, Heliogen and Bed Bath & Beyond. The full thread is edgartools #1501.
My own numbers come from a post-earnings-drift audit I ran in September. 43 of 228 timed filings were Eastern time labelled Z, all from issuers no longer in company_tickers.json. Read as UTC, 26 filings accepted after the entry day's close would have looked intraday.
Why a few hours matter
An earnings backtest makes one decision per event: was the release before the open, during the session, or after the close? That decides whether the reaction is in today's open, today's close or tomorrow's open. Four or five hours is enough to move a release across 09:30 or 16:00, and nothing raises an error. In my PEAD backtest, timing alone moved net alpha per trade from 1.21% to about 0.25% (write-up).
What changed this week
On October 28 at 12:52 UTC I re-read all 228 filings from my audit. All 228 now read true UTC, the 43 included, and none of the 185 that were right in September had moved the other way.
At 12:55 UTC I checked the 13 files reported as one offset late, plus Microsoft, Tesla and Alphabet: three filings each (the newest, the newest before October 23, and one from February, so both sides of DST). 48 of 48 read true UTC. Apple's 10-Q now says 10:01:02Z, which is right. The last time anyone in the thread saw a late file was October 22.
I can't tell whether this is a fix or one more rebuild. SEC sends no Last-Modified or ETag for these files, so a change can't be dated from outside.
Check what you stored
Re-fetching won't tell you what your cache holds. Compare each cached value with the filing's -index-headers.html, which gives the acceptance time in Eastern time and doesn't change:
import re, urllib.request
from datetime import datetime
from zoneinfo import ZoneInfo
UA = {"User-Agent": "Your Name you@example.com"} # SEC requires a real contact
ET, UTC = ZoneInfo("America/New_York"), ZoneInfo("UTC")
def accepted_utc(cik: int, accession: str) -> datetime:
url = (f"https://www.sec.gov/Archives/edgar/data/{cik}/"
f"{accession.replace('-', '')}/{accession}-index-headers.html")
html = urllib.request.urlopen(urllib.request.Request(url, headers=UA)).read().decode("latin1")
stamp = re.search(r"ACCEPTANCE-DATETIME>\s*(\d{14})", html).group(1)
return datetime.strptime(stamp, "%Y%m%d%H%M%S").replace(tzinfo=ET).astimezone(UTC)
def convention(cached: str, truth: datetime) -> str:
value = datetime.strptime(cached[:19], "%Y-%m-%dT%H:%M:%S").replace(tzinfo=UTC)
hours = (value - truth).total_seconds() / 3600
offset = -truth.astimezone(ET).utcoffset().total_seconds() / 3600
if abs(hours) < 0.01:
return "utc"
if abs(hours - offset) < 0.01:
return "one offset late"
if abs(hours + offset) < 0.01:
return "Eastern wall time labelled Z"
return f"other ({hours:+.2f} h)"
truth = accepted_utc(320193, "0000320193-26-000020")
print(truth) # 2026-07-31 10:01:02+00:00
print(convention("2026-07-31T14:01:02.000Z", truth)) # one offset late
That is one small request per filing. At SEC's limit of 10 requests a second, 10,000 filings take under 20 minutes. Cache the result, since the index page doesn't change.
For new work, read the time from the index headers and keep the JSON value next to it. edgartools plans the same for 6.1 (filing.accepted_at). For earnings 8-Ks, earnings-session (MIT, pip install earnings-session) does this and records which convention the JSON used for each filing. Disclosure: I maintain it.
If your cache turns up a pattern different from these three, I'd like to see it.
Top comments (0)