[{"data":1,"prerenderedAt":2001},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel":1966,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel":1975,"children:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel":1980,"related:\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel":1981},{"id":4,"title":5,"body":6,"dateModified":1932,"datePublished":1932,"description":1933,"extension":1934,"faq":1935,"keyword":1944,"kind":1945,"meta":1946,"navigation":172,"path":1955,"seo":1956,"slug":1959,"stem":1960,"topics":1961,"type":1964,"__hash__":1965},"docs\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel\u002Findex.md","Fix \"OverflowError: date value out of range\" When Reading Excel",{"type":7,"value":8,"toc":1920},"minimark",[9,39,44,75,105,109,387,390,435,449,686,690,693,769,789,793,796,1162,1171,1352,1356,1363,1442,1445,1564,1590,1594,1601,1767,1774,1778,1831,1835,1855,1859,1865,1871,1877,1883,1887,1916],[10,11,12,13,17,18,20,21,24,25,28,29,32,33,38],"p",{},"Excel stores a date as a number — the count of days since 30 December 1899 — and marks the cell as a date only through its number format. Python libraries convert any number in a date-formatted cell into a ",[14,15,16],"code",{},"datetime",". That works until a cell holds a number that cannot be a date: Python's ",[14,19,16],{}," stops at 31 December 9999, Excel's calendar at serial 2,958,465, and a number like 99,999,999 is far beyond both. Depending on the library and version, the result is ",[14,22,23],{},"OverflowError: date value out of range",", a warning that the cell \"will be treated as an error\", a silent ",[14,26,27],{},"NaT"," in pandas, or an ",[14,30,31],{},"OutOfBoundsDatetime"," later in the pipeline. This page shows where each one comes from, how to see the original numbers, and how to convert them correctly. It belongs to ",[34,35,37],"a",{"href":36},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002F","Troubleshooting Common Python Excel Errors",".",[40,41,43],"h2",{"id":42},"prerequisites","Prerequisites",[45,46,51],"pre",{"className":47,"code":48,"language":49,"meta":50,"style":50},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl python-calamine\n","bash","",[14,52,53],{"__ignoreMap":50},[54,55,58,62,66,69,72],"span",{"class":56,"line":57},"line",1,[54,59,61],{"class":60},"sMTad","pip",[54,63,65],{"class":64},"srMev"," install",[54,67,68],{"class":64}," pandas",[54,70,71],{"class":64}," openpyxl",[54,73,74],{"class":64}," python-calamine\n",[10,76,77,80,81,84,85,88,89,92,93,96,97,100,101,104],{},[14,78,79],{},"contracts.xlsx"," has an ",[14,82,83],{},"Expiry"," column formatted as ",[14,86,87],{},"dd mmm yyyy",". Two rows are ordinary dates. The others are the kinds of values that turn up in real exports: ",[14,90,91],{},"2958465"," (31 December 9999, used as \"never expires\"), ",[14,94,95],{},"99999999"," (another \"never\" convention), ",[14,98,99],{},"20261231"," (a yyyymmdd date typed as a number, then formatted as a date), and ",[14,102,103],{},"-5"," (a negative number in a date column).",[40,106,108],{"id":107},"step-1-see-the-symptom-your-stack-produces","Step 1 — See the symptom your stack produces",[45,110,114],{"className":111,"code":112,"language":113,"meta":50,"style":50},"language-python shiki shiki-themes github-light github-dark-high-contrast","import warnings\nimport pandas as pd\nfrom openpyxl import load_workbook\nfrom openpyxl.utils.datetime import from_excel\n\nwith warnings.catch_warnings(record=True) as caught:\n    warnings.simplefilter(\"always\")\n    ws = load_workbook(\"contracts.xlsx\")[\"Contracts\"]\n    print([c.value for c in ws[\"B\"]][1:])\nprint(caught[0].message if caught else \"no warning\")\n\ntry:\n    from_excel(99999999)\nexcept OverflowError as exc:\n    print(\"from_excel:\", type(exc).__name__, exc)\n\nprint(pd.read_excel(\"contracts.xlsx\")[\"Expiry\"].tolist())\n","python",[14,115,116,126,140,154,167,174,202,214,237,270,299,304,313,323,338,364,369],{"__ignoreMap":50},[54,117,118,122],{"class":56,"line":57},[54,119,121],{"class":120},"s-kum","import",[54,123,125],{"class":124},"skGVy"," warnings\n",[54,127,129,131,134,137],{"class":56,"line":128},2,[54,130,121],{"class":120},[54,132,133],{"class":124}," pandas ",[54,135,136],{"class":120},"as",[54,138,139],{"class":124}," pd\n",[54,141,143,146,149,151],{"class":56,"line":142},3,[54,144,145],{"class":120},"from",[54,147,148],{"class":124}," openpyxl ",[54,150,121],{"class":120},[54,152,153],{"class":124}," load_workbook\n",[54,155,157,159,162,164],{"class":56,"line":156},4,[54,158,145],{"class":120},[54,160,161],{"class":124}," openpyxl.utils.datetime ",[54,163,121],{"class":120},[54,165,166],{"class":124}," from_excel\n",[54,168,170],{"class":56,"line":169},5,[54,171,173],{"emptyLinePlaceholder":172},true,"\n",[54,175,177,180,183,187,190,194,197,199],{"class":56,"line":176},6,[54,178,179],{"class":120},"with",[54,181,182],{"class":124}," warnings.catch_warnings(",[54,184,186],{"class":185},"sa561","record",[54,188,189],{"class":120},"=",[54,191,193],{"class":192},"sP0c6","True",[54,195,196],{"class":124},") ",[54,198,136],{"class":120},[54,200,201],{"class":124}," caught:\n",[54,203,205,208,211],{"class":56,"line":204},7,[54,206,207],{"class":124},"    warnings.simplefilter(",[54,209,210],{"class":64},"\"always\"",[54,212,213],{"class":124},")\n",[54,215,217,220,222,225,228,231,234],{"class":56,"line":216},8,[54,218,219],{"class":124},"    ws ",[54,221,189],{"class":120},[54,223,224],{"class":124}," load_workbook(",[54,226,227],{"class":64},"\"contracts.xlsx\"",[54,229,230],{"class":124},")[",[54,232,233],{"class":64},"\"Contracts\"",[54,235,236],{"class":124},"]\n",[54,238,240,243,246,249,252,255,258,261,264,267],{"class":56,"line":239},9,[54,241,242],{"class":192},"    print",[54,244,245],{"class":124},"([c.value ",[54,247,248],{"class":120},"for",[54,250,251],{"class":124}," c ",[54,253,254],{"class":120},"in",[54,256,257],{"class":124}," ws[",[54,259,260],{"class":64},"\"B\"",[54,262,263],{"class":124},"]][",[54,265,266],{"class":192},"1",[54,268,269],{"class":124},":])\n",[54,271,273,276,279,282,285,288,291,294,297],{"class":56,"line":272},10,[54,274,275],{"class":192},"print",[54,277,278],{"class":124},"(caught[",[54,280,281],{"class":192},"0",[54,283,284],{"class":124},"].message ",[54,286,287],{"class":120},"if",[54,289,290],{"class":124}," caught ",[54,292,293],{"class":120},"else",[54,295,296],{"class":64}," \"no warning\"",[54,298,213],{"class":124},[54,300,302],{"class":56,"line":301},11,[54,303,173],{"emptyLinePlaceholder":172},[54,305,307,310],{"class":56,"line":306},12,[54,308,309],{"class":120},"try",[54,311,312],{"class":124},":\n",[54,314,316,319,321],{"class":56,"line":315},13,[54,317,318],{"class":124},"    from_excel(",[54,320,95],{"class":192},[54,322,213],{"class":124},[54,324,326,329,332,335],{"class":56,"line":325},14,[54,327,328],{"class":120},"except",[54,330,331],{"class":192}," OverflowError",[54,333,334],{"class":120}," as",[54,336,337],{"class":124}," exc:\n",[54,339,341,343,346,349,352,355,358,361],{"class":56,"line":340},15,[54,342,242],{"class":192},[54,344,345],{"class":124},"(",[54,347,348],{"class":64},"\"from_excel:\"",[54,350,351],{"class":124},", ",[54,353,354],{"class":192},"type",[54,356,357],{"class":124},"(exc).",[54,359,360],{"class":192},"__name__",[54,362,363],{"class":124},", exc)\n",[54,365,367],{"class":56,"line":366},16,[54,368,173],{"emptyLinePlaceholder":172},[54,370,372,374,377,379,381,384],{"class":56,"line":371},17,[54,373,275],{"class":192},[54,375,376],{"class":124},"(pd.read_excel(",[54,378,227],{"class":64},[54,380,230],{"class":124},[54,382,383],{"class":64},"\"Expiry\"",[54,385,386],{"class":124},"].tolist())\n",[10,388,389],{},"Three behaviours from the same file:",[391,392,393,412,426],"ul",{},[394,395,396,400,401,404,405,408,409,411],"li",{},[397,398,399],"strong",{},"openpyxl 3.1"," converts the in-range serials and replaces the impossible ones with the string ",[14,402,403],{},"'#VALUE!'",", emitting ",[14,406,407],{},"UserWarning: Cell B4 is marked as a date but the serial value 99999999 is outside the limits for dates. The cell will be treated as an error."," Older openpyxl releases raised ",[14,410,23],{}," at this point and stopped reading altogether.",[394,413,414,419,420,422,423,38],{},[397,415,416],{},[14,417,418],{},"openpyxl.utils.datetime.from_excel",", which scripts call to convert serials themselves, still raises ",[14,421,23],{}," for the same number — as does any hand-written ",[14,424,425],{},"datetime(1899, 12, 30) + timedelta(days=n)",[394,427,428,431,432,434],{},[397,429,430],{},"pandas with the openpyxl engine"," turns the error cells into ",[14,433,27],{},". The read succeeds, the warning scrolls past, and contract C-103's expiry has quietly disappeared.",[10,436,437,438,440,441,443,444,446,447,38],{},"The ",[14,439,103],{}," is converted to 25 December 1899 — a valid ",[14,442,16],{},", but certainly not a contract expiry — and ",[14,445,99],{}," is far beyond 9999 and also becomes ",[14,448,27],{},[450,451,459,460,459,464,459,468,459,475,459,484,459,488,459,495,459,499,459,503,459,507,459,511,459,513,459,517,459,519,459,522,459,525,459,529,459,531,459,535,459,537,459,540,459,543,459,547,459,549,459,552,459,554,459,556,459,559,459,563,459,565,459,568,459,573,459,576,459,579,459,583,459,585,459,588,459,590,459,592,459,595,459,599,459,601,459,604,459,608,459,611,459,615,459,619,459,622,459,626,459,629,459,633,459,636,459,639,459,642,459,645,459,648,459,652,459,658,459,661,459,667,459,672,459,680],"svg",{"viewBox":452,"role":453,"ariaLabelledBy":454,"xmlns":457,"style":458},"126 0 527 248","img",[455,456],"ovf-symptom-t","ovf-symptom-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:527px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[461,462,463],"title",{"id":455},"The same date column through openpyxl and pandas",[465,466,467],"desc",{"id":456},"The Excel column holds serials 46266, 2958465, 99999999, 20261231 and -5, all formatted as dates. openpyxl returns real dates for the first two,",[469,470],"rect",{"x":471,"y":281,"width":472,"height":473,"fill":474},"126","527","248","#ffffff",[469,476],{"x":477,"y":478,"width":479,"height":480,"rx":281,"fill":481,"stroke":482,"style":483},"142.6","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[469,485],{"x":486,"y":478,"width":487,"height":480,"rx":281,"fill":481,"stroke":482,"style":483},"174.6","73.5",[489,490,494],"text",{"x":491,"y":492,"style":493},"211.3","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[469,496],{"x":497,"y":478,"width":498,"height":480,"rx":281,"fill":481,"stroke":482,"style":483},"248.1","93.5",[489,500,502],{"x":501,"y":492,"style":493},"294.8","B",[469,504],{"x":477,"y":505,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"64.0","28.0",[489,508,266],{"x":509,"y":510,"style":493},"158.6","83.0",[469,512],{"x":486,"y":505,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,514,516],{"x":491,"y":510,"style":515},"font-size:11px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Contract",[469,518],{"x":497,"y":505,"width":498,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,520,521],{"x":501,"y":510,"style":515},"Expiry serial",[469,523],{"x":477,"y":524,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"92.0",[489,526,528],{"x":509,"y":527,"style":493},"111.0","2",[469,530],{"x":486,"y":524,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,532,534],{"x":491,"y":527,"style":533},"font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","C-101",[469,536],{"x":497,"y":524,"width":498,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,538,539],{"x":501,"y":527,"style":533},"46266",[469,541],{"x":477,"y":542,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"120.0",[489,544,546],{"x":509,"y":545,"style":493},"139.0","3",[469,548],{"x":486,"y":542,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,550,551],{"x":491,"y":545,"style":533},"C-102",[469,553],{"x":497,"y":542,"width":498,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,555,91],{"x":501,"y":545,"style":533},[469,557],{"x":477,"y":558,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"148.0",[489,560,562],{"x":509,"y":561,"style":493},"167.0","4",[469,564],{"x":486,"y":558,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,566,567],{"x":491,"y":561,"style":533},"C-103",[469,569],{"x":497,"y":558,"width":498,"height":506,"rx":281,"fill":570,"stroke":571,"style":572},"#fce9e9","var(--danger,#dc2626)","stroke-width:1.5px",[489,574,95],{"x":501,"y":561,"style":575},"font-size:11px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle",[469,577],{"x":477,"y":578,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"176.0",[489,580,582],{"x":509,"y":581,"style":493},"195.0","5",[469,584],{"x":486,"y":578,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,586,587],{"x":491,"y":581,"style":533},"C-104",[469,589],{"x":497,"y":578,"width":498,"height":506,"rx":281,"fill":570,"stroke":571,"style":572},[489,591,99],{"x":501,"y":581,"style":575},[469,593],{"x":477,"y":594,"width":479,"height":506,"rx":281,"fill":481,"stroke":482,"style":483},"204.0",[489,596,598],{"x":509,"y":597,"style":493},"223.0","6",[469,600],{"x":486,"y":594,"width":487,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},[489,602,603],{"x":491,"y":597,"style":533},"C-105",[469,605],{"x":497,"y":594,"width":498,"height":506,"rx":281,"fill":606,"stroke":607,"style":572},"#fdefd8","var(--gold,#b4740a)",[489,609,103],{"x":501,"y":597,"style":610},"font-size:11px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[469,612],{"x":613,"y":478,"width":614,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},"524.7","92.7",[489,616,83],{"x":617,"y":618,"style":515},"571.1","59.0",[469,620],{"x":613,"y":621,"width":614,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},"68.0",[489,623,625],{"x":617,"y":624,"style":533},"87.0","2026-09-01",[469,627],{"x":613,"y":628,"width":614,"height":506,"rx":281,"fill":474,"stroke":482,"style":483},"96.0",[489,630,632],{"x":617,"y":631,"style":533},"115.0","9999-12-31",[469,634],{"x":613,"y":635,"width":614,"height":506,"rx":281,"fill":570,"stroke":571,"style":572},"124.0",[489,637,27],{"x":617,"y":638,"style":575},"143.0",[469,640],{"x":613,"y":641,"width":614,"height":506,"rx":281,"fill":570,"stroke":571,"style":572},"152.0",[489,643,27],{"x":617,"y":644,"style":575},"171.0",[469,646],{"x":613,"y":647,"width":614,"height":506,"rx":281,"fill":606,"stroke":607,"style":572},"180.0",[489,649,651],{"x":617,"y":650,"style":610},"199.0","1899-12-25",[489,653,657],{"x":654,"y":655,"style":656},"242.1","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","stored serial",[489,659,660],{"x":617,"y":655,"style":656},"what pandas returns",[56,662],{"x1":663,"y1":635,"x2":664,"y2":635,"stroke":665,"style":666},"351.6","510.7","var(--brand,#5b5cf0)","stroke-width:2px",[668,669],"polygon",{"points":670,"fill":671},"514.7,124.0 505.7,129.0 505.7,119.0","#5b5cf0",[469,673],{"x":674,"y":675,"width":676,"height":677,"rx":678,"fill":474,"stroke":482,"style":679},"375.9","91.0","114.5","22.0","11","stroke-width:1.2px",[489,681,685],{"x":682,"y":683,"style":684},"433.2","106.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","pd.read_excel",[40,687,689],{"id":688},"step-2-get-the-raw-numbers-back","Step 2 — Get the raw numbers back",[10,691,692],{},"To decide what a bad value means, you need the number that was stored, which openpyxl has already discarded. The calamine engine keeps it: for a date-formatted cell outside the date range, it returns the number itself:",[45,694,696],{"className":111,"code":695,"language":113,"meta":50,"style":50},"raw = pd.read_excel(\"contracts.xlsx\", engine=\"calamine\")\nprint(raw.assign(kind=raw[\"Expiry\"].map(lambda v: type(v).__name__)).to_string(index=False))\n",[14,697,698,722],{"__ignoreMap":50},[54,699,700,703,705,708,710,712,715,717,720],{"class":56,"line":57},[54,701,702],{"class":124},"raw ",[54,704,189],{"class":120},[54,706,707],{"class":124}," pd.read_excel(",[54,709,227],{"class":64},[54,711,351],{"class":124},[54,713,714],{"class":185},"engine",[54,716,189],{"class":120},[54,718,719],{"class":64},"\"calamine\"",[54,721,213],{"class":124},[54,723,724,726,729,732,734,737,739,742,745,748,750,753,755,758,761,763,766],{"class":56,"line":128},[54,725,275],{"class":192},[54,727,728],{"class":124},"(raw.assign(",[54,730,731],{"class":185},"kind",[54,733,189],{"class":120},[54,735,736],{"class":124},"raw[",[54,738,383],{"class":64},[54,740,741],{"class":124},"].map(",[54,743,744],{"class":120},"lambda",[54,746,747],{"class":124}," v: ",[54,749,354],{"class":192},[54,751,752],{"class":124},"(v).",[54,754,360],{"class":192},[54,756,757],{"class":124},")).to_string(",[54,759,760],{"class":185},"index",[54,762,189],{"class":120},[54,764,765],{"class":192},"False",[54,767,768],{"class":124},"))\n",[10,770,771,772,774,775,777,778,780,781,784,785,38],{},"Out-of-range cells come back as plain integers — ",[14,773,95],{}," and ",[14,776,99],{}," — next to the converted dates, and the ",[14,779,103],{}," appears as a ",[14,782,783],{},"time"," value, because calamine interprets a small negative serial as a time of day. A column mixing types like this is exactly what you want while diagnosing: every impossible value is visible. If calamine is not available, read the cell values straight from the sheet XML as shown in ",[34,786,788],{"href":787},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Finspect-the-xml-inside-an-xlsx-file-with-python\u002F","Inspect the XML Inside an .xlsx File with Python",[40,790,792],{"id":791},"step-3-decide-what-each-value-means-then-convert","Step 3 — Decide what each value means, then convert",[10,794,795],{},"The fix is a mapping from raw serial to intended date, written down rather than guessed:",[45,797,799],{"className":111,"code":798,"language":113,"meta":50,"style":50},"import datetime as dt\n\nEXCEL_EPOCH = dt.datetime(1899, 12, 30)\nNEVER = pd.Timestamp(\"2262-04-11\")      # stand-in for \"no expiry\" inside pandas' safe range\n\ndef to_expiry(value):\n    if isinstance(value, dt.datetime):\n        return NEVER if value.year == 9999 else pd.Timestamp(value)\n    if isinstance(value, (int, float)):\n        n = int(value)\n        if n in (2958465, 99999999):\n            return NEVER\n        if 19000101 \u003C= n \u003C= 21001231:                       # yyyymmdd typed as a number\n            return pd.to_datetime(str(n), format=\"%Y%m%d\")\n        if 1 \u003C= n \u003C= 2958465:\n            return pd.Timestamp(EXCEL_EPOCH + dt.timedelta(days=n))\n    return pd.NaT                                          # negative serials, times, text\n\nraw[\"Expiry clean\"] = raw[\"Expiry\"].map(to_expiry)\nraw[\"Never expires\"] = raw[\"Expiry clean\"] == NEVER\nprint(raw[[\"Contract\", \"Expiry clean\", \"Never expires\"]].to_string(index=False))\n",[14,800,801,813,817,843,863,867,879,890,916,936,949,971,979,1003,1033,1051,1073,1084,1089,1110,1132],{"__ignoreMap":50},[54,802,803,805,808,810],{"class":56,"line":57},[54,804,121],{"class":120},[54,806,807],{"class":124}," datetime ",[54,809,136],{"class":120},[54,811,812],{"class":124}," dt\n",[54,814,815],{"class":56,"line":128},[54,816,173],{"emptyLinePlaceholder":172},[54,818,819,822,825,828,831,833,836,838,841],{"class":56,"line":142},[54,820,821],{"class":192},"EXCEL_EPOCH",[54,823,824],{"class":120}," =",[54,826,827],{"class":124}," dt.datetime(",[54,829,830],{"class":192},"1899",[54,832,351],{"class":124},[54,834,835],{"class":192},"12",[54,837,351],{"class":124},[54,839,840],{"class":192},"30",[54,842,213],{"class":124},[54,844,845,848,850,853,856,859],{"class":56,"line":156},[54,846,847],{"class":192},"NEVER",[54,849,824],{"class":120},[54,851,852],{"class":124}," pd.Timestamp(",[54,854,855],{"class":64},"\"2262-04-11\"",[54,857,858],{"class":124},")      ",[54,860,862],{"class":861},"s-wDw","# stand-in for \"no expiry\" inside pandas' safe range\n",[54,864,865],{"class":56,"line":169},[54,866,173],{"emptyLinePlaceholder":172},[54,868,869,872,876],{"class":56,"line":176},[54,870,871],{"class":120},"def",[54,873,875],{"class":874},"s_Opv"," to_expiry",[54,877,878],{"class":124},"(value):\n",[54,880,881,884,887],{"class":56,"line":204},[54,882,883],{"class":120},"    if",[54,885,886],{"class":192}," isinstance",[54,888,889],{"class":124},"(value, dt.datetime):\n",[54,891,892,895,898,901,904,907,910,913],{"class":56,"line":216},[54,893,894],{"class":120},"        return",[54,896,897],{"class":192}," NEVER",[54,899,900],{"class":120}," if",[54,902,903],{"class":124}," value.year ",[54,905,906],{"class":120},"==",[54,908,909],{"class":192}," 9999",[54,911,912],{"class":120}," else",[54,914,915],{"class":124}," pd.Timestamp(value)\n",[54,917,918,920,922,925,928,930,933],{"class":56,"line":239},[54,919,883],{"class":120},[54,921,886],{"class":192},[54,923,924],{"class":124},"(value, (",[54,926,927],{"class":192},"int",[54,929,351],{"class":124},[54,931,932],{"class":192},"float",[54,934,935],{"class":124},")):\n",[54,937,938,941,943,946],{"class":56,"line":272},[54,939,940],{"class":124},"        n ",[54,942,189],{"class":120},[54,944,945],{"class":192}," int",[54,947,948],{"class":124},"(value)\n",[54,950,951,954,957,959,962,964,966,968],{"class":56,"line":301},[54,952,953],{"class":120},"        if",[54,955,956],{"class":124}," n ",[54,958,254],{"class":120},[54,960,961],{"class":124}," (",[54,963,91],{"class":192},[54,965,351],{"class":124},[54,967,95],{"class":192},[54,969,970],{"class":124},"):\n",[54,972,973,976],{"class":56,"line":306},[54,974,975],{"class":120},"            return",[54,977,978],{"class":192}," NEVER\n",[54,980,981,983,986,989,991,994,997,1000],{"class":56,"line":315},[54,982,953],{"class":120},[54,984,985],{"class":192}," 19000101",[54,987,988],{"class":120}," \u003C=",[54,990,956],{"class":124},[54,992,993],{"class":120},"\u003C=",[54,995,996],{"class":192}," 21001231",[54,998,999],{"class":124},":                       ",[54,1001,1002],{"class":861},"# yyyymmdd typed as a number\n",[54,1004,1005,1007,1010,1013,1016,1019,1021,1024,1028,1031],{"class":56,"line":325},[54,1006,975],{"class":120},[54,1008,1009],{"class":124}," pd.to_datetime(",[54,1011,1012],{"class":192},"str",[54,1014,1015],{"class":124},"(n), ",[54,1017,1018],{"class":185},"format",[54,1020,189],{"class":120},[54,1022,1023],{"class":64},"\"%Y%m",[54,1025,1027],{"class":1026},"sSjpA","%d",[54,1029,1030],{"class":64},"\"",[54,1032,213],{"class":124},[54,1034,1035,1037,1040,1042,1044,1046,1049],{"class":56,"line":340},[54,1036,953],{"class":120},[54,1038,1039],{"class":192}," 1",[54,1041,988],{"class":120},[54,1043,956],{"class":124},[54,1045,993],{"class":120},[54,1047,1048],{"class":192}," 2958465",[54,1050,312],{"class":124},[54,1052,1053,1055,1057,1059,1062,1065,1068,1070],{"class":56,"line":366},[54,1054,975],{"class":120},[54,1056,852],{"class":124},[54,1058,821],{"class":192},[54,1060,1061],{"class":120}," +",[54,1063,1064],{"class":124}," dt.timedelta(",[54,1066,1067],{"class":185},"days",[54,1069,189],{"class":120},[54,1071,1072],{"class":124},"n))\n",[54,1074,1075,1078,1081],{"class":56,"line":371},[54,1076,1077],{"class":120},"    return",[54,1079,1080],{"class":124}," pd.NaT                                          ",[54,1082,1083],{"class":861},"# negative serials, times, text\n",[54,1085,1087],{"class":56,"line":1086},18,[54,1088,173],{"emptyLinePlaceholder":172},[54,1090,1092,1094,1097,1100,1102,1105,1107],{"class":56,"line":1091},19,[54,1093,736],{"class":124},[54,1095,1096],{"class":64},"\"Expiry clean\"",[54,1098,1099],{"class":124},"] ",[54,1101,189],{"class":120},[54,1103,1104],{"class":124}," raw[",[54,1106,383],{"class":64},[54,1108,1109],{"class":124},"].map(to_expiry)\n",[54,1111,1113,1115,1118,1120,1122,1124,1126,1128,1130],{"class":56,"line":1112},20,[54,1114,736],{"class":124},[54,1116,1117],{"class":64},"\"Never expires\"",[54,1119,1099],{"class":124},[54,1121,189],{"class":120},[54,1123,1104],{"class":124},[54,1125,1096],{"class":64},[54,1127,1099],{"class":124},[54,1129,906],{"class":120},[54,1131,978],{"class":192},[54,1133,1135,1137,1140,1143,1145,1147,1149,1151,1154,1156,1158,1160],{"class":56,"line":1134},21,[54,1136,275],{"class":192},[54,1138,1139],{"class":124},"(raw[[",[54,1141,1142],{"class":64},"\"Contract\"",[54,1144,351],{"class":124},[54,1146,1096],{"class":64},[54,1148,351],{"class":124},[54,1150,1117],{"class":64},[54,1152,1153],{"class":124},"]].to_string(",[54,1155,760],{"class":185},[54,1157,189],{"class":120},[54,1159,765],{"class":192},[54,1161,768],{"class":124},[10,1163,1164,1165,1167,1168,1170],{},"The 9999 date and the 99,999,999 sentinel both become \"never expires\", flagged in their own column; ",[14,1166,99],{}," becomes 31 December 2026; real serials convert normally; the negative value becomes ",[14,1169,27],{}," and should be reported back to whoever owns the sheet. Choosing a stand-in for \"never\" inside pandas' range avoids the next error in this family.",[450,1172,459,1178,459,1181,459,1184,459,1188,459,1195,459,1206,459,1211,459,1215,459,1219,459,1222,459,1225,459,1232,459,1237,459,1245,459,1252,459,1256,459,1261,459,1264,459,1267,459,1270,459,1274,459,1277,459,1279,459,1285,459,1289,459,1293,459,1296,459,1299,459,1303,459,1306,459,1309,459,1316,459,1320,459,1323,459,1325,459,1328,459,1332,459,1335,459,1338,459,1345,459,1349],{"viewBox":1173,"role":453,"ariaLabelledBy":1174,"xmlns":457,"style":1177},"4 0 752 290",[1175,1176],"ovf-map-t","ovf-map-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[461,1179,1180],{"id":1175},"Turning a raw serial into an intended date",[465,1182,1183],{"id":1176},"A real datetime or a serial between 1 and 2958465 is a date. The values 2958465 and 99999999 are sentinels for never. Eight-digit numbers between 19000101 and 21001231 are yyyymmdd dates. Negative numbers and anything else are reported as invalid.",[469,1185],{"x":562,"y":281,"width":1186,"height":1187,"fill":474},"752","290",[469,1189],{"x":1190,"y":1191,"width":1192,"height":1193,"rx":835,"fill":1194,"stroke":665,"style":666},"240.0","16.0","280.0","75.5","#f0f4ff",[1196,1197,1199],"g",{"transform":1198},"translate(368.0,29.0) scale(1.000)",[1200,1201],"path",{"d":1202,"fill":1203,"stroke":1204,"style":1205},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[489,1207,1210],{"x":1208,"y":1193,"style":1209},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","What is the raw value?",[56,1212],{"x1":1208,"y1":1213,"x2":1208,"y2":1214,"stroke":665,"style":666},"91.5","111.5",[56,1216],{"x1":1217,"y1":1214,"x2":1218,"y2":1214,"stroke":665,"style":666},"104.0","656.0",[56,1220],{"x1":1217,"y1":1214,"x2":1217,"y2":1221,"stroke":665,"style":666},"157.5",[668,1223],{"points":1224,"fill":671},"104.0,161.5 99.0,152.5 109.0,152.5",[469,1226],{"x":1227,"y":1228,"width":1229,"height":1230,"rx":1231,"fill":474,"stroke":482,"style":679},"56.3","121.5","95.4","21.0","10",[489,1233,1236],{"x":1217,"y":1234,"style":1235},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","1 … 2958465",[469,1238],{"x":1239,"y":1240,"width":1241,"height":1242,"rx":835,"fill":1243,"stroke":1244,"style":666},"20.0","163.5","168.0","110.5","#d9f4f1","var(--teal,#0f9488)",[1196,1246,1248],{"transform":1247},"translate(92.0,176.5) scale(1.000)",[1200,1249],{"d":1250,"fill":1203,"stroke":1251,"style":1205},"M4 5h16v15H4z M4 10h16 M8 3v4 M16 3v4","var(--teal-ink,#0b6157)",[489,1253,1255],{"x":1217,"y":597,"style":1254},"font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Excel serial",[489,1257,1260],{"x":1217,"y":1258,"style":1259},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","epoch 1899-12-30 + n",[489,1262,1067],{"x":1217,"y":1263,"style":1259},"260.0",[56,1265],{"x1":1266,"y1":1214,"x2":1266,"y2":1221,"stroke":665,"style":666},"288.0",[668,1268],{"points":1269,"fill":671},"288.0,161.5 283.0,152.5 293.0,152.5",[469,1271],{"x":1272,"y":1228,"width":1273,"height":1230,"rx":1231,"fill":474,"stroke":482,"style":679},"217.0","141.9",[489,1275,1276],{"x":1266,"y":1234,"style":1235},"2958465, 99999999",[469,1278],{"x":594,"y":1240,"width":1241,"height":1242,"rx":835,"fill":1194,"stroke":665,"style":666},[1196,1280,1282],{"transform":1281},"translate(276.0,185.2) scale(1.000)",[1200,1283],{"d":1284,"fill":1203,"stroke":1204,"style":1205},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2",[489,1286,1288],{"x":1266,"y":1287,"style":1209},"231.8","Sentinel",[489,1290,1292],{"x":1266,"y":1291,"style":1259},"251.2","\"never expires\" flag",[56,1294],{"x1":1295,"y1":1214,"x2":1295,"y2":1221,"stroke":665,"style":666},"472.0",[668,1297],{"points":1298,"fill":671},"472.0,161.5 467.0,152.5 477.0,152.5",[469,1300],{"x":1301,"y":1228,"width":1302,"height":1230,"rx":1231,"fill":474,"stroke":482,"style":679},"398.6","146.7",[489,1304,1305],{"x":1295,"y":1234,"style":1235},"19000101 … 21001231",[469,1307],{"x":1308,"y":1240,"width":1241,"height":1242,"rx":835,"fill":606,"stroke":607,"style":666},"388.0",[1196,1310,1312],{"transform":1311},"translate(460.0,185.2) scale(1.000)",[1200,1313],{"d":1314,"fill":1203,"stroke":1315,"style":1205},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--gold-ink,#7a4e06)",[489,1317,1319],{"x":1295,"y":1287,"style":1318},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","yyyymmdd number",[489,1321,1322],{"x":1295,"y":1291,"style":1259},"format=\"%Y%m%d\"",[56,1324],{"x1":1218,"y1":1214,"x2":1218,"y2":1221,"stroke":665,"style":666},[668,1326],{"points":1327,"fill":671},"656.0,161.5 651.0,152.5 661.0,152.5",[469,1329],{"x":1330,"y":1228,"width":1331,"height":1230,"rx":1231,"fill":474,"stroke":482,"style":679},"600.3","111.4",[489,1333,1334],{"x":1218,"y":1234,"style":1235},"negative \u002F other",[469,1336],{"x":1337,"y":1240,"width":1241,"height":1242,"rx":835,"fill":570,"stroke":571,"style":666},"572.0",[1196,1339,1341],{"transform":1340},"translate(644.0,185.2) scale(1.000)",[1200,1342],{"d":1343,"fill":1203,"stroke":1344,"style":1205},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4","var(--accent-ink,#be185d)",[489,1346,1348],{"x":1218,"y":1287,"style":1347},"font-size:13.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Invalid",[489,1350,1351],{"x":1218,"y":1291,"style":1259},"report to the sheet owner",[40,1353,1355],{"id":1354},"step-4-avoid-outofboundsdatetime-downstream","Step 4 — Avoid OutOfBoundsDatetime downstream",[10,1357,1358,1359,1362],{},"pandas 3 stores datetimes at the resolution that fits, so a column containing 31 December 9999 reads fine as ",[14,1360,1361],{},"datetime64[us]",". The trouble starts when code or a library forces nanosecond precision, whose range ends on 11 April 2262:",[45,1364,1366],{"className":111,"code":1365,"language":113,"meta":50,"style":50},"dates = pd.read_excel(\"contracts.xlsx\", nrows=2)[\"Expiry\"]\nprint(dates.dtype)\ntry:\n    dates.astype(\"datetime64[ns]\")\nexcept Exception as exc:\n    print(type(exc).__name__, exc)\n",[14,1367,1368,1394,1401,1407,1417,1428],{"__ignoreMap":50},[54,1369,1370,1373,1375,1377,1379,1381,1384,1386,1388,1390,1392],{"class":56,"line":57},[54,1371,1372],{"class":124},"dates ",[54,1374,189],{"class":120},[54,1376,707],{"class":124},[54,1378,227],{"class":64},[54,1380,351],{"class":124},[54,1382,1383],{"class":185},"nrows",[54,1385,189],{"class":120},[54,1387,528],{"class":192},[54,1389,230],{"class":124},[54,1391,383],{"class":64},[54,1393,236],{"class":124},[54,1395,1396,1398],{"class":56,"line":128},[54,1397,275],{"class":192},[54,1399,1400],{"class":124},"(dates.dtype)\n",[54,1402,1403,1405],{"class":56,"line":142},[54,1404,309],{"class":120},[54,1406,312],{"class":124},[54,1408,1409,1412,1415],{"class":56,"line":156},[54,1410,1411],{"class":124},"    dates.astype(",[54,1413,1414],{"class":64},"\"datetime64[ns]\"",[54,1416,213],{"class":124},[54,1418,1419,1421,1424,1426],{"class":56,"line":169},[54,1420,328],{"class":120},[54,1422,1423],{"class":192}," Exception",[54,1425,334],{"class":120},[54,1427,337],{"class":124},[54,1429,1430,1432,1434,1436,1438,1440],{"class":56,"line":176},[54,1431,242],{"class":192},[54,1433,345],{"class":124},[54,1435,354],{"class":192},[54,1437,357],{"class":124},[54,1439,360],{"class":192},[54,1441,363],{"class":124},[10,1443,1444],{},"Four different limits are in play, and each error in this family comes from crossing one of them:",[450,1446,459,1451,459,1454,459,1457,459,1460,459,1467,459,1471,459,1477,459,1482,459,1486,459,1490,459,1493,459,1497,459,1501,459,1506,459,1512,459,1516,459,1518,459,1520,459,1523,459,1528,459,1533,459,1536,459,1539,459,1541,459,1543,459,1546,459,1552,459,1557,459,1560,459,1562],{"viewBox":1447,"role":453,"ariaLabelledBy":1448,"xmlns":457,"style":1177},"4 0 752 313",[1449,1450],"ovf-limits-t","ovf-limits-d",[461,1452,1453],{"id":1449},"The date limits a value can cross between Excel and pandas",[465,1455,1456],{"id":1450},"A timeline of limits. Excel serial 1 is 1 January 1900. Nanosecond pandas timestamps end on 11 April 2262. Excel's last date, serial 2958465, and Python's datetime maximum are both 31 December 9999. A value such as 99999999 lies beyond all of them.",[469,1458],{"x":562,"y":281,"width":1186,"height":1459,"fill":474},"313",[56,1461],{"x1":1462,"y1":1463,"x2":1464,"y2":1463,"stroke":1465,"style":1466},"94.0","156.5","666.0","var(--muted,#5b6780)","stroke-width:2.5px",[469,1468],{"x":1239,"y":1191,"width":1469,"height":1470,"rx":835,"fill":481,"stroke":482,"style":666},"172.0","108.5",[1196,1472,1474],{"transform":1473},"translate(94.0,29.0) scale(1.000)",[1200,1475],{"d":1250,"fill":1203,"stroke":1476,"style":1205},"var(--text,#172033)",[489,1478,1481],{"x":683,"y":1479,"style":1480},"74.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Serial 1",[489,1483,1485],{"x":683,"y":1484,"style":533},"93.0","1 Jan 1900, Excel's first",[489,1487,1489],{"x":683,"y":1488,"style":533},"110.0","date",[56,1491],{"x1":683,"y1":1492,"x2":683,"y2":1463,"stroke":1465,"style":572},"124.5",[1494,1495],"circle",{"cx":683,"cy":1463,"r":1496,"fill":1465,"stroke":474,"style":666},"7.0",[469,1498],{"x":1499,"y":1500,"width":1469,"height":1470,"rx":835,"fill":606,"stroke":607,"style":666},"202.7","188.5",[1196,1502,1504],{"transform":1503},"translate(276.7,210.0) scale(1.000)",[1200,1505],{"d":1343,"fill":1203,"stroke":1315,"style":1205},[489,1507,1511],{"x":1508,"y":1509,"style":1510},"288.7","255.5","font-size:12.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","11 Apr 2262",[489,1513,1515],{"x":1508,"y":1514,"style":533},"274.0","end of datetime64[ns]",[56,1517],{"x1":1508,"y1":1463,"x2":1508,"y2":1500,"stroke":1465,"style":572},[1494,1519],{"cx":1508,"cy":1463,"r":1496,"fill":607,"stroke":474,"style":666},[469,1521],{"x":1522,"y":1191,"width":1469,"height":1470,"rx":835,"fill":1194,"stroke":665,"style":666},"385.3",[1196,1524,1526],{"transform":1525},"translate(459.3,29.0) scale(1.000)",[1200,1527],{"d":1284,"fill":1203,"stroke":1204,"style":1205},[489,1529,1532],{"x":1530,"y":1479,"style":1531},"471.3","font-size:12.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Serial 2958465",[489,1534,1535],{"x":1530,"y":1484,"style":533},"31 Dec 9999, Excel and",[489,1537,1538],{"x":1530,"y":1488,"style":533},"Python's last date",[56,1540],{"x1":1530,"y1":1492,"x2":1530,"y2":1463,"stroke":1465,"style":572},[1494,1542],{"cx":1530,"cy":1463,"r":1496,"fill":665,"stroke":474,"style":666},[469,1544],{"x":1545,"y":1500,"width":1469,"height":1470,"rx":835,"fill":570,"stroke":571,"style":666},"568.0",[1196,1547,1549],{"transform":1548},"translate(642.0,210.0) scale(1.000)",[1200,1550],{"d":1551,"fill":1203,"stroke":1344,"style":1205},"M6 6l12 12 M18 6L6 18",[489,1553,1556],{"x":1554,"y":1509,"style":1555},"654.0","font-size:12.5px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Serial 99999999",[489,1558,1559],{"x":1554,"y":1514,"style":533},"no calendar reaches it",[56,1561],{"x1":1554,"y1":1463,"x2":1554,"y2":1500,"stroke":1465,"style":572},[1494,1563],{"cx":1554,"cy":1463,"r":1496,"fill":571,"stroke":474,"style":666},[10,1565,1566,1567,1570,1571,1573,1574,1577,1578,1581,1582,1585,1586,38],{},"Excel itself shows ",[14,1568,1569],{},"########"," in a date-formatted cell whose value is negative or above 2,958,465; Python's ",[14,1572,16],{}," cannot go past 9999 either, which is the ",[14,1575,1576],{},"OverflowError","; and the nanosecond limit in 2262 is a pandas storage choice rather than a calendar limit, which is why it surfaces later and only in some code paths. ",[14,1579,1580],{},"OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 9999-12-31 00:00:00"," appears whenever a 9999 date meets nanosecond storage — older pandas versions, ",[14,1583,1584],{},"astype(\"datetime64[ns]\")",", or libraries that assume it. Mapping sentinel dates to a flag plus a safe stand-in, as in Step 3, removes the problem at the source. The general rules for date columns are in ",[34,1587,1589],{"href":1588},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fparse-excel-dates-into-python-datetimes-with-pandas\u002F","Parse Excel Dates into Python Datetimes with pandas",[40,1591,1593],{"id":1592},"step-5-fix-the-workbook-if-you-own-it","Step 5 — Fix the workbook if you own it",[10,1595,1596,1597,1600],{},"If the file is produced by your own process, stop the bad values at the source. A column of yyyymmdd numbers or IDs should not carry a date format; set it back to ",[14,1598,1599],{},"General"," with openpyxl, and write \"no expiry\" as an empty cell plus a status column rather than a magic date:",[45,1602,1604],{"className":111,"code":1603,"language":113,"meta":50,"style":50},"wb = load_workbook(\"contracts.xlsx\")\nws = wb[\"Contracts\"]\nfixed = 0\nfor (cell,) in ws.iter_rows(min_row=2, min_col=2, max_col=2):\n    if cell.value == \"#VALUE!\" or (hasattr(cell.value, \"year\") and cell.value.year \u003C 1900):\n        cell.number_format = \"General\"\n        fixed += 1\nwb.save(\"contracts_checked.xlsx\")\nprint(\"cells reset to General:\", fixed)\n",[14,1605,1606,1619,1633,1643,1682,1724,1734,1745,1755],{"__ignoreMap":50},[54,1607,1608,1611,1613,1615,1617],{"class":56,"line":57},[54,1609,1610],{"class":124},"wb ",[54,1612,189],{"class":120},[54,1614,224],{"class":124},[54,1616,227],{"class":64},[54,1618,213],{"class":124},[54,1620,1621,1624,1626,1629,1631],{"class":56,"line":128},[54,1622,1623],{"class":124},"ws ",[54,1625,189],{"class":120},[54,1627,1628],{"class":124}," wb[",[54,1630,233],{"class":64},[54,1632,236],{"class":124},[54,1634,1635,1638,1640],{"class":56,"line":142},[54,1636,1637],{"class":124},"fixed ",[54,1639,189],{"class":120},[54,1641,1642],{"class":192}," 0\n",[54,1644,1645,1647,1650,1652,1655,1658,1660,1662,1664,1667,1669,1671,1673,1676,1678,1680],{"class":56,"line":156},[54,1646,248],{"class":120},[54,1648,1649],{"class":124}," (cell,) ",[54,1651,254],{"class":120},[54,1653,1654],{"class":124}," ws.iter_rows(",[54,1656,1657],{"class":185},"min_row",[54,1659,189],{"class":120},[54,1661,528],{"class":192},[54,1663,351],{"class":124},[54,1665,1666],{"class":185},"min_col",[54,1668,189],{"class":120},[54,1670,528],{"class":192},[54,1672,351],{"class":124},[54,1674,1675],{"class":185},"max_col",[54,1677,189],{"class":120},[54,1679,528],{"class":192},[54,1681,970],{"class":124},[54,1683,1684,1686,1689,1691,1694,1697,1699,1702,1705,1708,1710,1713,1716,1719,1722],{"class":56,"line":169},[54,1685,883],{"class":120},[54,1687,1688],{"class":124}," cell.value ",[54,1690,906],{"class":120},[54,1692,1693],{"class":64}," \"#VALUE!\"",[54,1695,1696],{"class":120}," or",[54,1698,961],{"class":124},[54,1700,1701],{"class":192},"hasattr",[54,1703,1704],{"class":124},"(cell.value, ",[54,1706,1707],{"class":64},"\"year\"",[54,1709,196],{"class":124},[54,1711,1712],{"class":120},"and",[54,1714,1715],{"class":124}," cell.value.year ",[54,1717,1718],{"class":120},"\u003C",[54,1720,1721],{"class":192}," 1900",[54,1723,970],{"class":124},[54,1725,1726,1729,1731],{"class":56,"line":176},[54,1727,1728],{"class":124},"        cell.number_format ",[54,1730,189],{"class":120},[54,1732,1733],{"class":64}," \"General\"\n",[54,1735,1736,1739,1742],{"class":56,"line":204},[54,1737,1738],{"class":124},"        fixed ",[54,1740,1741],{"class":120},"+=",[54,1743,1744],{"class":192}," 1\n",[54,1746,1747,1750,1753],{"class":56,"line":216},[54,1748,1749],{"class":124},"wb.save(",[54,1751,1752],{"class":64},"\"contracts_checked.xlsx\"",[54,1754,213],{"class":124},[54,1756,1757,1759,1761,1764],{"class":56,"line":239},[54,1758,275],{"class":192},[54,1760,345],{"class":124},[54,1762,1763],{"class":64},"\"cells reset to General:\"",[54,1765,1766],{"class":124},", fixed)\n",[10,1768,1769,1770,38],{},"The cells openpyxl could not convert lost their original numbers on load, so this pass only marks them for attention — the real fix is in the job that writes the file. Detecting impossible values in incoming files belongs in validation, as in ",[34,1771,1773],{"href":1772},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-excel-columns-before-import-with-pandas\u002F","Validate Excel Columns Before Import with pandas",[40,1775,1777],{"id":1776},"common-pitfalls","Common pitfalls",[391,1779,1780,1792,1809,1815,1821],{},[394,1781,1782,1785,1786,1788,1789,38],{},[397,1783,1784],{},"Ignoring the warning."," openpyxl 3.1 keeps reading and pandas shows ",[14,1787,27],{},"; turn warnings into errors in tests with ",[14,1790,1791],{},"warnings.simplefilter(\"error\")",[394,1793,1794,1797,1798,1801,1802,1804,1805,1808],{},[397,1795,1796],{},"Converting serials by hand."," ",[14,1799,1800],{},"timedelta(days=n)"," raises ",[14,1803,1576],{}," for large ",[14,1806,1807],{},"n","; range-check first.",[394,1810,1811,1814],{},[397,1812,1813],{},"Sentinel dates in pandas."," 9999-12-31 works in pandas 3 but fails wherever nanosecond precision is forced.",[394,1816,1817,1820],{},[397,1818,1819],{},"The 1900 leap-year quirk."," Excel counts a non-existent 29 February 1900, which is why the epoch used for modern serials is 30 December 1899, not 1 January 1900.",[394,1822,1823,1826,1827,38],{},[397,1824,1825],{},"1904-system workbooks."," Some Mac workbooks count from 1904; see ",[34,1828,1830],{"href":1829},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-the-1904-date-system-in-excel-files\u002F","Handle the 1904 Date System in Excel Files",[40,1832,1834],{"id":1833},"conclusion","Conclusion",[10,1836,1837,1838,1841,1842,1844,1845,1848,1849,1851,1852,1854],{},"The error means a date-formatted cell holds a number that cannot be a date. openpyxl 3.1 turns such cells into ",[14,1839,1840],{},"#VALUE!"," with a warning and pandas into ",[14,1843,27],{},"; ",[14,1846,1847],{},"from_excel",", hand-written conversions and older openpyxl raise ",[14,1850,1576],{},"; 9999 dates later trigger ",[14,1853,31],{}," under nanosecond precision. Read the raw serials with the calamine engine, map sentinels, yyyymmdd numbers and real serials explicitly, report the rest, and fix the number format in the workbook that produced them.",[40,1856,1858],{"id":1857},"frequently-asked-questions","Frequently asked questions",[10,1860,1861,1864],{},[397,1862,1863],{},"What causes \"OverflowError: date value out of range\" when reading Excel?","\nA cell with a date number format contains a number outside the range Python can turn into a date, such as 99999999 or a yyyymmdd value like 20261231. Converting it with from_excel, older openpyxl versions, or datetime arithmetic raises OverflowError.",[10,1866,1867,1870],{},[397,1868,1869],{},"Why does openpyxl say a cell is marked as a date but outside the limits for dates?","\nopenpyxl 3.1 found a date-formatted cell whose serial value is beyond Excel's calendar. Instead of raising, it warns and returns the string #VALUE!, which pandas reads as NaT.",[10,1872,1873,1876],{},[397,1874,1875],{},"How do I read the original number from an out-of-range date cell?","\nRead the file with pd.read_excel(path, engine=\"calamine\"). For date-formatted cells outside the valid range, calamine returns the stored number instead of a date.",[10,1878,1879,1882],{},[397,1880,1881],{},"How should I store \"no expiry\" dates from Excel in pandas?","\nMap sentinel values such as 9999-12-31 or 99999999 to a separate boolean flag, and either leave the date empty or use a stand-in inside pandas' safe range, so nanosecond-precision code never meets year 9999.",[40,1884,1886],{"id":1885},"related","Related",[391,1888,1889,1895,1902,1909],{},[394,1890,1891,1892,1894],{},"Up one level: ",[34,1893,37],{"href":36}," — fixes for the errors Excel automation hits most.",[394,1896,1897,1901],{},[34,1898,1900],{"href":1899},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffix-excel-serial-numbers-showing-instead-of-dates\u002F","Fix Excel Serial Numbers Showing Instead of Dates"," — the opposite problem, dates without a date format.",[394,1903,1904,1908],{},[34,1905,1907],{"href":1906},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-text-dates-like-20240131-with-pandas\u002F","Convert Text Dates Like 20240131 with pandas"," — yyyymmdd values as text.",[394,1910,1911,1915],{},[34,1912,1914],{"href":1913},"\u002Fadvanced-data-transformation-and-cleaning\u002Freading-excel-with-polars-and-arrow\u002Fspeed-up-pandas-excel-reads-with-the-calamine-engine\u002F","Speed Up pandas Excel Reads with the Calamine Engine"," — the engine used to recover the raw values.",[1917,1918,1919],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":50,"searchDepth":128,"depth":128,"links":1921},[1922,1923,1924,1925,1926,1927,1928,1929,1930,1931],{"id":42,"depth":128,"text":43},{"id":107,"depth":128,"text":108},{"id":688,"depth":128,"text":689},{"id":791,"depth":128,"text":792},{"id":1354,"depth":128,"text":1355},{"id":1592,"depth":128,"text":1593},{"id":1776,"depth":128,"text":1777},{"id":1833,"depth":128,"text":1834},{"id":1857,"depth":128,"text":1858},{"id":1885,"depth":128,"text":1886},"2026-10-02","Date cells that hold numbers too large or too small to be dates — a sentinel like 99999999, a yyyymmdd number formatted as a date, an amount column with the wrong format — raise OverflowError in from_excel and older openpyxl, become #VALUE! with a warning in openpyxl 3.1, NaT in pandas, or OutOfBoundsDatetime later. Find the raw values, decide what they mean, and convert them deliberately.","md",[1936,1938,1940,1942],{"q":1863,"a":1937},"A cell with a date number format contains a number outside the range Python can turn into a date, such as 99999999 or a yyyymmdd value like 20261231. Converting it with from_excel, older openpyxl versions, or datetime arithmetic raises OverflowError.",{"q":1869,"a":1939},"openpyxl 3.1 found a date-formatted cell whose serial value is beyond Excel's calendar. Instead of raising, it warns and returns the string #VALUE!, which pandas reads as NaT.",{"q":1875,"a":1941},"Read the file with pd.read_excel(path, engine=\"calamine\"). For date-formatted cells outside the valid range, calamine returns the stored number instead of a date.",{"q":1881,"a":1943},"Map sentinel values such as 9999-12-31 or 99999999 to a separate boolean flag, and either leave the date empty or use a stand-in inside pandas' safe range, so nanosecond-precision code never meets year 9999.","fix overflowerror date value out of range reading excel",null,{"breadcrumb":1947},[1948,1951,1954],{"name":1949,"item":1950},"Home","\u002F",{"name":1952,"item":1953},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":37,"item":36},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel",{"title":1957,"description":1958},"Fix \"OverflowError: date value out of range\" Reading Excel","Why Excel date cells raise OverflowError, a \"serial value is outside the limits for dates\" warning or NaT in pandas: find the raw serials with calamine, convert yyyymmdd numbers and sentinels, fix the number format, and avoid OutOfBoundsDatetime.","fix-overflowerror-date-value-out-of-range-when-reading-excel","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-overflowerror-date-value-out-of-range-when-reading-excel\u002Findex",[1962,1963],"troubleshooting","dates-and-times","how-to","2gVHrXBvWhuXF6wc-J--cCQ07Ksw7DG_FFHRmUKGhW4",[1967,1971],{"title":1968,"path":1969,"stem":1970,"children":-1},"Fix openpyxl \"Value must be one of\" and \"Max value is\" Errors","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-value-must-be-one-of-errors","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-openpyxl-value-must-be-one-of-errors\u002Findex",{"title":1972,"path":1973,"stem":1974,"children":-1},"Fix pandas FutureWarnings in Excel Pipelines","\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines","getting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-pandas-futurewarnings-in-excel-pipelines\u002Findex",[1976,1978],{"path":1977,"title":1952},"\u002Fgetting-started-with-python-excel-automation",{"path":1979,"title":37},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors",[],[1982,1986,1989,1991,1994,1997],{"path":1983,"title":1984,"kind":1985},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation\u002Fhandle-permission-denied-when-writing-excel-in-python","Handle Permission Denied When Writing Excel in Python","fix",{"path":1987,"title":1988,"kind":1964},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fwhat-openpyxl-loses-when-saving-an-existing-workbook","What openpyxl Loses When You Save an Existing Workbook",{"path":1990,"title":1900,"kind":1985},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffix-excel-serial-numbers-showing-instead-of-dates",{"path":1992,"title":1993,"kind":1964},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-daylight-saving-time-in-excel-timestamps","Handle Daylight Saving Time in Excel Timestamps",{"path":1995,"title":1996,"kind":1964},"\u002Fautomating-reporting-workflows\u002Fautomating-excel-online-with-microsoft-graph\u002Fhandle-microsoft-graph-throttling-for-excel","Handle Microsoft Graph Throttling in Excel Automation",{"path":1998,"title":1999,"kind":2000},"\u002Fautomating-reporting-workflows\u002Ferror-handling-and-logging-in-excel-automation","Error Handling and Logging in Excel Automation","guide",1790972067358]