Chronology sources
Scholars disagree about 上古 (pre-Qin) dating. The disagreement is real scholarship, not data error, so this library does not settle it for you — it lets you pick.
import chhiskit
chhiskit.get_age_from_cultural_period("夏", level="epoch") # → (-2070.0, ...)
chhiskit.get_age_from_cultural_period("夏", level="epoch", source="shl") # → (-1989.0, ...)
chhiskit.get_age_from_cultural_period("夏", level="epoch", source="wgd") # → (-2100.0, ...)
chhiskit.set_default_source("shl") # or set a preference once
Available sources
source |
Reference | Year | Covers |
|---|---|---|---|
"shl" |
上海图书馆开放数据平台 | 2024 | Everything — 朝代 / 年号 / 帝王. The base table. |
"xsz" |
夏商周断代工程 | 2000 | 夏 / 商 / 周 / 东周 only |
"wgd" |
万国鼎《中国历史纪年表》(中华书局) | 1956 | 国号 / 朝代-level spans only (74 entries) |
"default" |
alias | — | Whatever set_default_source was last given; initially "xsz" |
Call chhiskit.list_sources() to get this table at runtime.
How sources compose
Sources are overlays, not replacements. 上图 is the only source with full coverage, so it is always the base; a selected source overrides the spans it knows about and everything else falls back to 上图.
This matters because coverage differs wildly. 断代工程 pronounces on four polities; 万国鼎's parseable index covers 74; neither says anything about 年号:
chhiskit.get_age_from_cultural_period("康熙", source="wgd")
# → (1662.0, 1722.0) ← 上图 data; 万国鼎's index carries no 年号 spans
# SourceFallbackWarning: source='wgd' has no entry for '康熙'; falling back to 上图 base data
That warning fires whenever a source you asked for by name had nothing to say.
The answer is still correct — it just isn't from the source you named, and
saying so silently would misrepresent where the numbers came from. It is not
raised for the default source (whose fallback is by design) or for "shl"
(which is the base).
Overlays only apply to dynasty-level rows. A source saying 「清 1636~1911」 is
making a claim about the polity, not about each of its 年号 — so it never
rewrites 康熙. One consequence: level="dynasty" unions a polity's rows, so
where 上图 has an era row starting earlier than the overlay (清's 天命 1616 vs
万国鼎's 1636 国号改称), the union still reports the earlier year.
Where they disagree
上图 (shl) |
万国鼎 (wgd) |
断代工程 (xsz) |
|
|---|---|---|---|
| 夏 | -1989 ~ -1559 | 約-2100 ~ -1600 | -2070 ~ -1600 |
| 商 | -1559 ~ -1123 | 約-1600 ~ -1028 | -1600 ~ -1046 |
| 周 | -1123 ~ -256 | -1027 ~ -256 | -1046 ~ -256 |
| 西周 | -1046 ~ -771 | -1027 ~ -771 | -1046 ~ -771 |
| 东周 | -770 ~ -221 | -770 ~ -256 | -770 ~ -256 |
| 春秋 | -770 ~ -477 | -770 ~ -481 | (not covered) |
| 战国 | -476 ~ -221 | -480 ~ -222 | (not covered) |
A full three-way comparison, covering the differences outside 上古 as well, is
kept in the repository at
data/dynasties/chronology_crosscheck.md.
Why xsz is the default
Two reasons, both about 上图 rather than about who is right:
- It closes a silent hole.
新石器ends at-2070— already the 断代工程 figure — but 上图 starts 夏 at-1989, so-2069..-1990matched nothing. - 上图 is internally split. Its 周 begins
-1123on the older dating while its own 西周 begins-1046on 断代工程's. One table, two chronologies.
Anchoring the ancient rows makes one table tell one story. Note what this claim
is not: 断代工程's 夏 -2070 is not universally accepted (its precision is
widely disputed outside China). It is canonical for this dataset, not
correct in any final sense — which is exactly why the source stays selectable.
source="shl" returns the 上图 record unmodified, and is pinned by tests to keep
returning exactly what this library published before sources existed.
东周: an honest exception
xsz.csv carries 东周 -770 ~ -256, but its note says plainly that this is
not a 断代工程 finding. 断代工程's new results concern the pre-841 BCE era;
东周 rests on traditional dating that was never in doubt.
It is included because 万国鼎 and traditional chronology agree on -256 (周赧王 卒 / 秦灭东周) against 上图's -221, which appears to conflate 东周 with 战国. Attributing it to 断代工程 would have been fabricated provenance — worse than a wrong year.
春秋 and 战国 are deliberately not overlaid: 断代工程 doesn't cover them, and 春秋's end year is itself a three-way dispute (前481 获麟 / 前476 / 前453). Their differences are reported, not resolved.
Knowing where an answer came from
SourceFallbackWarning is the answer to "did this number actually come from
the source I asked for?" — it fires exactly when it did not. To treat a fallback
as an error rather than a warning:
import warnings
from chhiskit import SourceFallbackWarning
with warnings.catch_warnings():
warnings.simplefilter("error", SourceFallbackWarning)
chhiskit.get_age_from_cultural_period("夏", level="epoch", source="wgd") # fine
chhiskit.get_age_from_cultural_period("康熙", source="wgd") # raises
This is useful when a result must be attributable to one specific reference — an analysis that cites 断代工程, say, should not silently mix in 上图 spans.