[{"data":1,"prerenderedAt":2029},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas":1995,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas":2004,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas":2009,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas":2010},{"id":4,"title":5,"body":6,"dateModified":1962,"datePublished":1962,"description":1963,"extension":1964,"faq":1965,"keyword":1974,"kind":1975,"meta":1976,"navigation":107,"path":1985,"seo":1986,"slug":1988,"stem":1989,"topics":1990,"type":1993,"__hash__":1994},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas\u002Findex.md","Convert Unix Timestamps to Excel Dates with pandas",{"type":7,"value":8,"toc":1948},"minimark",[9,28,33,61,75,79,351,357,507,511,517,616,648,652,655,747,758,923,927,1131,1134,1365,1369,1372,1644,1651,1655,1658,1780,1786,1790,1807,1811,1865,1869,1883,1887,1893,1899,1905,1911,1915,1944],[10,11,12,13,17,18,21,22,27],"p",{},"A CSV from a web analytics tool, a JSON response from a payments API, a database dump of event logs: all of them tend to store time as a Unix timestamp, the number of seconds (or milliseconds) since 1 January 1970 UTC. Pasted into Excel, ",[14,15,16],"code",{},"1790920800"," is just a large number; a report needs ",[14,19,20],{},"2 Oct 2026 06:00",". The conversion is one pandas call — once you know the unit, which the data rarely tells you, and once you have decided which time zone the readers expect, because Unix time is UTC and Excel has no concept of time zones. This page covers detection, conversion, time zones, messy values and the reverse trip. It belongs to ",[23,24,26],"a",{"href":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002F","Working with Dates and Times in Excel Data",".",[29,30,32],"h2",{"id":31},"prerequisites","Prerequisites",[34,35,40],"pre",{"className":36,"code":37,"language":38,"meta":39,"style":39},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,41,42],{"__ignoreMap":39},[43,44,47,51,55,58],"span",{"class":45,"line":46},"line",1,[43,48,50],{"class":49},"sMTad","pip",[43,52,54],{"class":53},"srMev"," install",[43,56,57],{"class":53}," pandas",[43,59,60],{"class":53}," openpyxl\n",[10,62,63,66,67,70,71,74],{},[14,64,65],{},"events.xlsx"," has six events from three sources. The API sends seconds, the mobile app milliseconds, and the database export contains a ",[14,68,69],{},"0"," (a placeholder for \"unknown\" that would otherwise become 1 January 1970) and the text ",[14,72,73],{},"not set",". All values arrived as text, which is common for IDs and timestamps in exports.",[29,76,78],{"id":77},"step-1-detect-the-unit-from-the-magnitude","Step 1 — Detect the unit from the magnitude",[34,80,84],{"className":81,"code":82,"language":83,"meta":39,"style":39},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nev = pd.read_excel(\"events.xlsx\", dtype={\"Timestamp\": str})\nraw = pd.to_numeric(ev[\"Timestamp\"], errors=\"coerce\")\n\ndef epoch_unit(value):\n    if pd.isna(value) or value \u003C= 0:\n        return None\n    digits = len(str(int(value)))\n    return {10: \"s\", 13: \"ms\", 16: \"us\", 19: \"ns\"}.get(digits)\n\nev[\"Unit\"] = raw.map(epoch_unit)\nprint(ev.assign(Numeric=raw).to_string(index=False))\n","python",[14,85,86,102,109,149,176,181,194,218,227,251,301,306,323],{"__ignoreMap":39},[43,87,88,92,96,99],{"class":45,"line":46},[43,89,91],{"class":90},"s-kum","import",[43,93,95],{"class":94},"skGVy"," pandas ",[43,97,98],{"class":90},"as",[43,100,101],{"class":94}," pd\n",[43,103,105],{"class":45,"line":104},2,[43,106,108],{"emptyLinePlaceholder":107},true,"\n",[43,110,112,115,118,121,124,127,131,133,136,139,142,146],{"class":45,"line":111},3,[43,113,114],{"class":94},"ev ",[43,116,117],{"class":90},"=",[43,119,120],{"class":94}," pd.read_excel(",[43,122,123],{"class":53},"\"events.xlsx\"",[43,125,126],{"class":94},", ",[43,128,130],{"class":129},"sa561","dtype",[43,132,117],{"class":90},[43,134,135],{"class":94},"{",[43,137,138],{"class":53},"\"Timestamp\"",[43,140,141],{"class":94},": ",[43,143,145],{"class":144},"sP0c6","str",[43,147,148],{"class":94},"})\n",[43,150,152,155,157,160,162,165,168,170,173],{"class":45,"line":151},4,[43,153,154],{"class":94},"raw ",[43,156,117],{"class":90},[43,158,159],{"class":94}," pd.to_numeric(ev[",[43,161,138],{"class":53},[43,163,164],{"class":94},"], ",[43,166,167],{"class":129},"errors",[43,169,117],{"class":90},[43,171,172],{"class":53},"\"coerce\"",[43,174,175],{"class":94},")\n",[43,177,179],{"class":45,"line":178},5,[43,180,108],{"emptyLinePlaceholder":107},[43,182,184,187,191],{"class":45,"line":183},6,[43,185,186],{"class":90},"def",[43,188,190],{"class":189},"s_Opv"," epoch_unit",[43,192,193],{"class":94},"(value):\n",[43,195,197,200,203,206,209,212,215],{"class":45,"line":196},7,[43,198,199],{"class":90},"    if",[43,201,202],{"class":94}," pd.isna(value) ",[43,204,205],{"class":90},"or",[43,207,208],{"class":94}," value ",[43,210,211],{"class":90},"\u003C=",[43,213,214],{"class":144}," 0",[43,216,217],{"class":94},":\n",[43,219,221,224],{"class":45,"line":220},8,[43,222,223],{"class":90},"        return",[43,225,226],{"class":144}," None\n",[43,228,230,233,235,238,241,243,245,248],{"class":45,"line":229},9,[43,231,232],{"class":94},"    digits ",[43,234,117],{"class":90},[43,236,237],{"class":144}," len",[43,239,240],{"class":94},"(",[43,242,145],{"class":144},[43,244,240],{"class":94},[43,246,247],{"class":144},"int",[43,249,250],{"class":94},"(value)))\n",[43,252,254,257,260,263,265,268,270,273,275,278,280,283,285,288,290,293,295,298],{"class":45,"line":253},10,[43,255,256],{"class":90},"    return",[43,258,259],{"class":94}," {",[43,261,262],{"class":144},"10",[43,264,141],{"class":94},[43,266,267],{"class":53},"\"s\"",[43,269,126],{"class":94},[43,271,272],{"class":144},"13",[43,274,141],{"class":94},[43,276,277],{"class":53},"\"ms\"",[43,279,126],{"class":94},[43,281,282],{"class":144},"16",[43,284,141],{"class":94},[43,286,287],{"class":53},"\"us\"",[43,289,126],{"class":94},[43,291,292],{"class":144},"19",[43,294,141],{"class":94},[43,296,297],{"class":53},"\"ns\"",[43,299,300],{"class":94},"}.get(digits)\n",[43,302,304],{"class":45,"line":303},11,[43,305,108],{"emptyLinePlaceholder":107},[43,307,309,312,315,318,320],{"class":45,"line":308},12,[43,310,311],{"class":94},"ev[",[43,313,314],{"class":53},"\"Unit\"",[43,316,317],{"class":94},"] ",[43,319,117],{"class":90},[43,321,322],{"class":94}," raw.map(epoch_unit)\n",[43,324,326,329,332,335,337,340,343,345,348],{"class":45,"line":325},13,[43,327,328],{"class":144},"print",[43,330,331],{"class":94},"(ev.assign(",[43,333,334],{"class":129},"Numeric",[43,336,117],{"class":90},[43,338,339],{"class":94},"raw).to_string(",[43,341,342],{"class":129},"index",[43,344,117],{"class":90},[43,346,347],{"class":144},"False",[43,349,350],{"class":94},"))\n",[10,352,353,354,356],{},"Present-day timestamps have 10 digits in seconds (",[14,355,16],{},"), 13 in milliseconds, 16 in microseconds and 19 in nanoseconds — a rule that holds from September 2001 until the year 2286. That makes the length of the number a reliable guide for current data. Zero and text get no unit, which marks them for special handling instead of letting them turn into 1970. When one source sends a consistent unit, set it explicitly from documentation and use detection only as a check.",[358,359,367,368,367,372,367,376,367,383,367,391,367,398,367,405,367,408,367,412,367,415,367,419,367,424,367,430,367,432,367,436,367,438,367,440,367,442,367,444,367,447,367,451,367,453,367,456,367,458,367,461,367,463,367,465,367,468,367,472,367,474,367,477,367,479,367,482,367,484,367,486,367,489,367,493,367,495,367,498,367,500,367,503,367,505],"svg",{"viewBox":360,"role":361,"ariaLabelledBy":362,"xmlns":365,"style":366},"4 0 752 208","img",[363,364],"ux-units-t","ux-units-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[369,370,371],"title",{"id":363},"Telling epoch units apart by digit count",[373,374,375],"desc",{"id":364},"For dates between 2001 and 2286, Unix timestamps have 10 digits in seconds, 13 in milliseconds, 16 in microseconds and 19 in nanoseconds. Each maps to a unit argument for pd.to_datetime.",[377,378],"rect",{"x":379,"y":69,"width":380,"height":381,"fill":382},"4","752","208","#ffffff",[377,384],{"x":385,"y":386,"width":387,"height":388,"rx":69,"fill":382,"stroke":389,"style":390},"20.0","16.0","119.4","40.0","var(--line,#cdd5e6)","stroke-width:1px",[377,392],{"x":393,"y":386,"width":394,"height":388,"rx":69,"fill":395,"stroke":396,"style":397},"139.4","200.2","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.2px",[399,400,404],"text",{"x":401,"y":402,"style":403},"239.5","41.0","font-size:13px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","digits today",[377,406],{"x":407,"y":386,"width":394,"height":388,"rx":69,"fill":395,"stroke":396,"style":397},"339.6",[399,409,411],{"x":410,"y":402,"style":403},"439.7","example",[377,413],{"x":414,"y":386,"width":394,"height":388,"rx":69,"fill":395,"stroke":396,"style":397},"539.8",[399,416,418],{"x":417,"y":402,"style":403},"639.9","unit=",[377,420],{"x":385,"y":421,"width":387,"height":422,"rx":69,"fill":423,"stroke":389,"style":390},"56.0","34.0","#e7ebef",[399,425,429],{"x":426,"y":427,"style":428},"32.0","78.0","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:start","seconds",[377,431],{"x":393,"y":421,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,433,262],{"x":401,"y":434,"style":435},"77.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[377,437],{"x":407,"y":421,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,439,16],{"x":410,"y":434,"style":435},[377,441],{"x":414,"y":421,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,443,267],{"x":417,"y":434,"style":435},[377,445],{"x":385,"y":446,"width":387,"height":422,"rx":69,"fill":423,"stroke":389,"style":390},"90.0",[399,448,450],{"x":426,"y":449,"style":428},"112.0","milliseconds",[377,452],{"x":393,"y":446,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,454,272],{"x":401,"y":455,"style":435},"111.0",[377,457],{"x":407,"y":446,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,459,460],{"x":410,"y":455,"style":435},"1790920800000",[377,462],{"x":414,"y":446,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,464,277],{"x":417,"y":455,"style":435},[377,466],{"x":385,"y":467,"width":387,"height":422,"rx":69,"fill":423,"stroke":389,"style":390},"124.0",[399,469,471],{"x":426,"y":470,"style":428},"146.0","microseconds",[377,473],{"x":393,"y":467,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,475,282],{"x":401,"y":476,"style":435},"145.0",[377,478],{"x":407,"y":467,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,480,481],{"x":410,"y":476,"style":435},"1790920800000000",[377,483],{"x":414,"y":467,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,485,287],{"x":417,"y":476,"style":435},[377,487],{"x":385,"y":488,"width":387,"height":422,"rx":69,"fill":423,"stroke":389,"style":390},"158.0",[399,490,492],{"x":426,"y":491,"style":428},"180.0","nanoseconds",[377,494],{"x":393,"y":488,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,496,292],{"x":401,"y":497,"style":435},"179.0",[377,499],{"x":407,"y":488,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,501,502],{"x":410,"y":497,"style":435},"1790920800000000000",[377,504],{"x":414,"y":488,"width":394,"height":422,"rx":69,"fill":382,"stroke":389,"style":390},[399,506,297],{"x":417,"y":497,"style":435},[29,508,510],{"id":509},"step-2-convert-to-utc-datetimes","Step 2 — Convert to UTC datetimes",[10,512,513,516],{},[14,514,515],{},"pd.to_datetime"," takes the unit; with mixed units, convert each group with its own:",[34,518,520],{"className":81,"code":519,"language":83,"meta":39,"style":39},"parts = [pd.to_datetime(raw[idx], unit=unit, utc=True)\n         for unit, idx in ev.groupby(\"Unit\").groups.items()]\nev[\"UTC\"] = pd.concat(parts).reindex(ev.index)\nprint(ev[[\"EventID\", \"Timestamp\", \"Unit\", \"UTC\"]].to_string(index=False))\n",[14,521,522,550,569,583],{"__ignoreMap":39},[43,523,524,527,529,532,535,537,540,543,545,548],{"class":45,"line":46},[43,525,526],{"class":94},"parts ",[43,528,117],{"class":90},[43,530,531],{"class":94}," [pd.to_datetime(raw[idx], ",[43,533,534],{"class":129},"unit",[43,536,117],{"class":90},[43,538,539],{"class":94},"unit, ",[43,541,542],{"class":129},"utc",[43,544,117],{"class":90},[43,546,547],{"class":144},"True",[43,549,175],{"class":94},[43,551,552,555,558,561,564,566],{"class":45,"line":104},[43,553,554],{"class":90},"         for",[43,556,557],{"class":94}," unit, idx ",[43,559,560],{"class":90},"in",[43,562,563],{"class":94}," ev.groupby(",[43,565,314],{"class":53},[43,567,568],{"class":94},").groups.items()]\n",[43,570,571,573,576,578,580],{"class":45,"line":111},[43,572,311],{"class":94},[43,574,575],{"class":53},"\"UTC\"",[43,577,317],{"class":94},[43,579,117],{"class":90},[43,581,582],{"class":94}," pd.concat(parts).reindex(ev.index)\n",[43,584,585,587,590,593,595,597,599,601,603,605,608,610,612,614],{"class":45,"line":151},[43,586,328],{"class":144},[43,588,589],{"class":94},"(ev[[",[43,591,592],{"class":53},"\"EventID\"",[43,594,126],{"class":94},[43,596,138],{"class":53},[43,598,126],{"class":94},[43,600,314],{"class":53},[43,602,126],{"class":94},[43,604,575],{"class":53},[43,606,607],{"class":94},"]].to_string(",[43,609,342],{"class":129},[43,611,117],{"class":90},[43,613,347],{"class":144},[43,615,350],{"class":94},[10,617,618,619,622,623,626,627,630,631,635,636,638,639,641,642,644,645,647],{},"Each unit group is converted separately and the pieces are put back in the original row order with ",[14,620,621],{},"reindex","; rows without a unit get ",[14,624,625],{},"NaT",". ",[14,628,629],{},"utc=True"," marks the results as UTC, which is what Unix time ",[632,633,634],"em",{},"is",". The seconds value ",[14,637,16],{}," and the milliseconds value ",[14,640,460],{}," both become 2 October 2026 06:00 UTC — the same instant from two sources. The zero and the text stay ",[14,643,625],{},". Without ",[14,646,629],{}," pandas returns naive datetimes that silently assume UTC, and the next step would be easy to forget.",[29,649,651],{"id":650},"step-3-convert-to-the-readers-time-zone-then-drop-the-zone","Step 3 — Convert to the readers' time zone, then drop the zone",[10,653,654],{},"Excel stores no time zone, so pandas refuses to write zone-aware datetimes. Convert to the zone the readers think in, then remove the zone information:",[34,656,658],{"className":81,"code":657,"language":83,"meta":39,"style":39},"ev[\"Local (London)\"] = ev[\"UTC\"].dt.tz_convert(\"Europe\u002FLondon\").dt.tz_localize(None)\nev[\"Local (New York)\"] = ev[\"UTC\"].dt.tz_convert(\"America\u002FNew_York\").dt.tz_localize(None)\nprint(ev[[\"EventID\", \"UTC\", \"Local (London)\", \"Local (New York)\"]].dropna().to_string(index=False))\n",[14,659,660,690,716],{"__ignoreMap":39},[43,661,662,664,667,669,671,674,676,679,682,685,688],{"class":45,"line":46},[43,663,311],{"class":94},[43,665,666],{"class":53},"\"Local (London)\"",[43,668,317],{"class":94},[43,670,117],{"class":90},[43,672,673],{"class":94}," ev[",[43,675,575],{"class":53},[43,677,678],{"class":94},"].dt.tz_convert(",[43,680,681],{"class":53},"\"Europe\u002FLondon\"",[43,683,684],{"class":94},").dt.tz_localize(",[43,686,687],{"class":144},"None",[43,689,175],{"class":94},[43,691,692,694,697,699,701,703,705,707,710,712,714],{"class":45,"line":104},[43,693,311],{"class":94},[43,695,696],{"class":53},"\"Local (New York)\"",[43,698,317],{"class":94},[43,700,117],{"class":90},[43,702,673],{"class":94},[43,704,575],{"class":53},[43,706,678],{"class":94},[43,708,709],{"class":53},"\"America\u002FNew_York\"",[43,711,684],{"class":94},[43,713,687],{"class":144},[43,715,175],{"class":94},[43,717,718,720,722,724,726,728,730,732,734,736,739,741,743,745],{"class":45,"line":111},[43,719,328],{"class":144},[43,721,589],{"class":94},[43,723,592],{"class":53},[43,725,126],{"class":94},[43,727,575],{"class":53},[43,729,126],{"class":94},[43,731,666],{"class":53},[43,733,126],{"class":94},[43,735,696],{"class":53},[43,737,738],{"class":94},"]].dropna().to_string(",[43,740,342],{"class":129},[43,742,117],{"class":90},[43,744,347],{"class":144},[43,746,350],{"class":94},[10,748,749,750,753,754,27],{},"06:00 UTC on 2 October is 07:00 in London (British Summer Time) and 02:00 in New York. ",[14,751,752],{},"tz_localize(None)"," keeps the local clock time and discards the zone, which is exactly what Excel can store. Converting first matters: dropping the zone from the UTC values would leave UTC clock times that readers take for local time. Label the column with the zone so nobody has to guess. The error you get if you skip this step is covered in ",[23,755,757],{"href":756},"\u002Fgetting-started-with-python-excel-automation\u002Ftroubleshooting-common-python-excel-errors\u002Ffix-excel-does-not-support-timezones-in-datetimes\u002F","Fix \"Excel does not support datetimes with timezones\" in pandas",[358,759,367,764,367,767,367,770,367,773,367,779,367,790,367,795,367,799,367,804,367,809,367,812,367,819,367,824,367,827,367,831,367,834,367,837,367,843,367,848,367,852,367,856,367,860,367,863,367,868,367,875,367,881,367,884,367,887,367,890,367,894,367,897,367,902,367,909,367,914,367,917,367,920],{"viewBox":760,"role":361,"ariaLabelledBy":761,"xmlns":365,"style":366},"4 0 752 160",[762,763],"ux-flow-t","ux-flow-d",[369,765,766],{"id":762},"From a Unix timestamp to an Excel date",[373,768,769],{"id":763},"The raw number 1790920800 is identified as seconds, converted to 2 October 2026 06:00 UTC, converted to London time 07:00, stripped of its zone, and written to Excel as a date-time with a format.",[377,771],{"x":379,"y":69,"width":380,"height":772,"fill":382},"160",[377,774],{"x":385,"y":386,"width":775,"height":776,"rx":777,"fill":423,"stroke":389,"style":778},"115.2","128.0","12","stroke-width:2px",[780,781,783],"g",{"transform":782},"translate(65.6,46.5) scale(1.000)",[784,785],"path",{"d":786,"fill":787,"stroke":788,"style":789},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[399,791,16],{"x":792,"y":793,"style":794},"77.6","93.0","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle",[399,796,798],{"x":792,"y":797,"style":435},"112.5","raw number",[45,800],{"x1":801,"y1":802,"x2":803,"y2":802,"stroke":396,"style":778},"140.2","80.0","162.2",[805,806],"polygon",{"points":807,"fill":808},"166.2,80.0 157.2,85.0 157.2,75.0","#5b5cf0",[377,810],{"x":811,"y":386,"width":775,"height":776,"rx":777,"fill":395,"stroke":396,"style":778},"171.2",[780,813,815],{"transform":814},"translate(216.8,46.5) scale(1.000)",[784,816],{"d":817,"fill":787,"stroke":818,"style":789},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","var(--brand-strong,#4338ca)",[399,820,823],{"x":821,"y":793,"style":822},"228.8","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","unit = s",[399,825,826],{"x":821,"y":797,"style":435},"10 digits",[45,828],{"x1":829,"y1":802,"x2":830,"y2":802,"stroke":396,"style":778},"291.4","313.4",[805,832],{"points":833,"fill":808},"317.4,80.0 308.4,85.0 308.4,75.0",[377,835],{"x":836,"y":386,"width":775,"height":776,"rx":777,"fill":395,"stroke":396,"style":778},"322.4",[780,838,840],{"transform":839},"translate(368.0,37.8) scale(1.000)",[784,841],{"d":842,"fill":787,"stroke":818,"style":789},"M12 3a9 9 0 1 0 .01 0z M12 7v5l3.5 2",[399,844,847],{"x":845,"y":846,"style":822},"380.0","84.2","06:00 UTC",[399,849,851],{"x":845,"y":850,"style":435},"103.8","to_datetime(…,",[399,853,855],{"x":845,"y":854,"style":435},"121.2","utc=True)",[45,857],{"x1":858,"y1":802,"x2":859,"y2":802,"stroke":396,"style":778},"442.6","464.6",[805,861],{"points":862,"fill":808},"468.6,80.0 459.6,85.0 459.6,75.0",[377,864],{"x":865,"y":386,"width":775,"height":776,"rx":777,"fill":866,"stroke":867,"style":778},"473.6","#fdefd8","var(--gold,#b4740a)",[780,869,871],{"transform":870},"translate(519.2,29.0) scale(1.000)",[784,872],{"d":873,"fill":787,"stroke":874,"style":789},"M12 3a9 9 0 1 0 .01 0z M3 12h18 M12 3c3.2 3 3.2 15 0 18 M12 3c-3.2 3-3.2 15 0 18","var(--gold-ink,#7a4e06)",[399,876,880],{"x":877,"y":878,"style":879},"531.2","75.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","07:00",[399,882,883],{"x":877,"y":793,"style":879},"London",[399,885,886],{"x":877,"y":797,"style":435},"tz_convert,",[399,888,752],{"x":877,"y":889,"style":435},"130.0",[45,891],{"x1":892,"y1":802,"x2":893,"y2":802,"stroke":396,"style":778},"593.8","615.8",[805,895],{"points":896,"fill":808},"619.8,80.0 610.8,85.0 610.8,75.0",[377,898],{"x":899,"y":386,"width":775,"height":776,"rx":777,"fill":900,"stroke":901,"style":778},"624.8","#d9f4f1","var(--teal,#0f9488)",[780,903,905],{"transform":904},"translate(670.4,29.0) scale(1.000)",[784,906],{"d":907,"fill":787,"stroke":908,"style":789},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","var(--teal-ink,#0b6157)",[399,910,913],{"x":911,"y":878,"style":912},"682.4","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Excel",[399,915,916],{"x":911,"y":793,"style":912},"date-time",[399,918,919],{"x":911,"y":797,"style":435},"dd mmm yyyy",[399,921,922],{"x":911,"y":889,"style":435},"hh:mm",[29,924,926],{"id":925},"step-4-write-to-excel-with-a-readable-format","Step 4 — Write to Excel with a readable format",[34,928,930],{"className":81,"code":929,"language":83,"meta":39,"style":39},"out = ev[[\"EventID\", \"Source\", \"Timestamp\", \"Local (London)\"]].copy()\nout[\"Note\"] = ev[\"Unit\"].isna().map({True: \"no valid timestamp\", False: \"\"})\nwith pd.ExcelWriter(\"events_converted.xlsx\", engine=\"xlsxwriter\", datetime_format=\"dd mmm yyyy hh:mm:ss\") as xw:\n    out.to_excel(xw, sheet_name=\"Events\", index=False)\n    xw.sheets[\"Events\"].set_column(\"D:D\", 22)\nfrom openpyxl import load_workbook\ncell = load_workbook(\"events_converted.xlsx\")[\"Events\"][\"D2\"]\nprint(cell.value, \"|\", cell.number_format)\n",[14,931,932,960,997,1036,1059,1079,1092,1118],{"__ignoreMap":39},[43,933,934,937,939,942,944,946,949,951,953,955,957],{"class":45,"line":46},[43,935,936],{"class":94},"out ",[43,938,117],{"class":90},[43,940,941],{"class":94}," ev[[",[43,943,592],{"class":53},[43,945,126],{"class":94},[43,947,948],{"class":53},"\"Source\"",[43,950,126],{"class":94},[43,952,138],{"class":53},[43,954,126],{"class":94},[43,956,666],{"class":53},[43,958,959],{"class":94},"]].copy()\n",[43,961,962,965,968,970,972,974,976,979,981,983,986,988,990,992,995],{"class":45,"line":104},[43,963,964],{"class":94},"out[",[43,966,967],{"class":53},"\"Note\"",[43,969,317],{"class":94},[43,971,117],{"class":90},[43,973,673],{"class":94},[43,975,314],{"class":53},[43,977,978],{"class":94},"].isna().map({",[43,980,547],{"class":144},[43,982,141],{"class":94},[43,984,985],{"class":53},"\"no valid timestamp\"",[43,987,126],{"class":94},[43,989,347],{"class":144},[43,991,141],{"class":94},[43,993,994],{"class":53},"\"\"",[43,996,148],{"class":94},[43,998,999,1002,1005,1008,1010,1013,1015,1018,1020,1023,1025,1028,1031,1033],{"class":45,"line":111},[43,1000,1001],{"class":90},"with",[43,1003,1004],{"class":94}," pd.ExcelWriter(",[43,1006,1007],{"class":53},"\"events_converted.xlsx\"",[43,1009,126],{"class":94},[43,1011,1012],{"class":129},"engine",[43,1014,117],{"class":90},[43,1016,1017],{"class":53},"\"xlsxwriter\"",[43,1019,126],{"class":94},[43,1021,1022],{"class":129},"datetime_format",[43,1024,117],{"class":90},[43,1026,1027],{"class":53},"\"dd mmm yyyy hh:mm:ss\"",[43,1029,1030],{"class":94},") ",[43,1032,98],{"class":90},[43,1034,1035],{"class":94}," xw:\n",[43,1037,1038,1041,1044,1046,1049,1051,1053,1055,1057],{"class":45,"line":151},[43,1039,1040],{"class":94},"    out.to_excel(xw, ",[43,1042,1043],{"class":129},"sheet_name",[43,1045,117],{"class":90},[43,1047,1048],{"class":53},"\"Events\"",[43,1050,126],{"class":94},[43,1052,342],{"class":129},[43,1054,117],{"class":90},[43,1056,347],{"class":144},[43,1058,175],{"class":94},[43,1060,1061,1064,1066,1069,1072,1074,1077],{"class":45,"line":178},[43,1062,1063],{"class":94},"    xw.sheets[",[43,1065,1048],{"class":53},[43,1067,1068],{"class":94},"].set_column(",[43,1070,1071],{"class":53},"\"D:D\"",[43,1073,126],{"class":94},[43,1075,1076],{"class":144},"22",[43,1078,175],{"class":94},[43,1080,1081,1084,1087,1089],{"class":45,"line":183},[43,1082,1083],{"class":90},"from",[43,1085,1086],{"class":94}," openpyxl ",[43,1088,91],{"class":90},[43,1090,1091],{"class":94}," load_workbook\n",[43,1093,1094,1097,1099,1102,1104,1107,1109,1112,1115],{"class":45,"line":196},[43,1095,1096],{"class":94},"cell ",[43,1098,117],{"class":90},[43,1100,1101],{"class":94}," load_workbook(",[43,1103,1007],{"class":53},[43,1105,1106],{"class":94},")[",[43,1108,1048],{"class":53},[43,1110,1111],{"class":94},"][",[43,1113,1114],{"class":53},"\"D2\"",[43,1116,1117],{"class":94},"]\n",[43,1119,1120,1122,1125,1128],{"class":45,"line":220},[43,1121,328],{"class":144},[43,1123,1124],{"class":94},"(cell.value, ",[43,1126,1127],{"class":53},"\"|\"",[43,1129,1130],{"class":94},", cell.number_format)\n",[10,1132,1133],{},"The cell holds a real Excel date-time, so it sorts and filters as a date.",[358,1135,367,1141,367,1144,367,1147,367,1152,367,1156,367,1160,367,1166,367,1170,367,1174,367,1178,367,1182,367,1186,367,1190,367,1194,367,1198,367,1201,367,1206,367,1209,367,1213,367,1215,367,1218,367,1220,367,1223,367,1225,367,1228,367,1230,367,1233,367,1236,367,1240,367,1242,367,1245,367,1247,367,1250,367,1252,367,1254,367,1256,367,1260,367,1262,367,1265,367,1269,367,1271,367,1273,367,1275,367,1277,367,1279,367,1282,367,1284,367,1287,367,1289,367,1291,367,1294,367,1296,367,1298,367,1300,367,1303,367,1305,367,1307,367,1309,367,1311,367,1313,367,1316,367,1320,367,1322,367,1324,367,1326,367,1329,367,1331,367,1333,367,1335,367,1337,367,1341,367,1343,367,1347,367,1349,367,1351,367,1353,367,1355,367,1357,367,1359,367,1361,367,1363],{"viewBox":1136,"role":361,"ariaLabelledBy":1137,"xmlns":365,"style":1140},"90 0 579 224",[1138,1139],"ux-sheet-t","ux-sheet-d","width:100%;max-width:579px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[369,1142,1143],{"id":1138},"The converted events sheet",[373,1145,1146],{"id":1139},"The output sheet with EventID, Source, the original Timestamp text, the London local time as a real date-time, and a Note column. The two database rows have no valid timestamp and are labelled instead of showing 1970.",[377,1148],{"x":1149,"y":69,"width":1150,"height":1151,"fill":382},"90","579","224",[377,1153],{"x":1154,"y":386,"width":426,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"106.7","24.0",[377,1157],{"x":1158,"y":386,"width":1159,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"138.7","65.8",[399,1161,1165],{"x":1162,"y":1163,"style":1164},"171.6","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[377,1167],{"x":1168,"y":386,"width":1169,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"204.6","62.4",[399,1171,1173],{"x":1172,"y":1163,"style":1164},"235.7","B",[377,1175],{"x":1176,"y":386,"width":1177,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"266.9","115.6",[399,1179,1181],{"x":1180,"y":1163,"style":1164},"324.8","C",[377,1183],{"x":1184,"y":386,"width":1185,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"382.6","144.6",[399,1187,1189],{"x":1188,"y":1163,"style":1164},"454.9","D",[377,1191],{"x":1192,"y":386,"width":1193,"height":1155,"rx":69,"fill":423,"stroke":389,"style":390},"527.2","126.1",[399,1195,1197],{"x":1196,"y":1163,"style":1164},"590.2","E",[377,1199],{"x":1154,"y":388,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},"28.0",[399,1202,1205],{"x":1203,"y":1204,"style":1164},"122.7","59.0","1",[377,1207],{"x":1158,"y":388,"width":1159,"height":1200,"rx":69,"fill":395,"stroke":396,"style":1208},"stroke-width:1.5px",[399,1210,1212],{"x":1162,"y":1204,"style":1211},"font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","EventID",[377,1214],{"x":1168,"y":388,"width":1169,"height":1200,"rx":69,"fill":395,"stroke":396,"style":1208},[399,1216,1217],{"x":1172,"y":1204,"style":1211},"Source",[377,1219],{"x":1176,"y":388,"width":1177,"height":1200,"rx":69,"fill":395,"stroke":396,"style":1208},[399,1221,1222],{"x":1180,"y":1204,"style":1211},"Timestamp",[377,1224],{"x":1184,"y":388,"width":1185,"height":1200,"rx":69,"fill":395,"stroke":396,"style":1208},[399,1226,1227],{"x":1188,"y":1204,"style":1211},"Local (London)",[377,1229],{"x":1192,"y":388,"width":1193,"height":1200,"rx":69,"fill":395,"stroke":396,"style":1208},[399,1231,1232],{"x":1196,"y":1204,"style":1211},"Note",[377,1234],{"x":1154,"y":1235,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},"68.0",[399,1237,1239],{"x":1203,"y":1238,"style":1164},"87.0","2",[377,1241],{"x":1158,"y":1235,"width":1159,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1243,1205],{"x":1162,"y":1238,"style":1244},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[377,1246],{"x":1168,"y":1235,"width":1169,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1248,1249],{"x":1172,"y":1238,"style":1244},"api",[377,1251],{"x":1176,"y":1235,"width":1177,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1253,16],{"x":1180,"y":1238,"style":1244},[377,1255],{"x":1184,"y":1235,"width":1185,"height":1200,"rx":69,"fill":900,"stroke":901,"style":1208},[399,1257,1259],{"x":1188,"y":1238,"style":1258},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","02 Oct 2026 07:00:00",[377,1261],{"x":1192,"y":1235,"width":1193,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[377,1263],{"x":1154,"y":1264,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},"96.0",[399,1266,1268],{"x":1203,"y":1267,"style":1164},"115.0","3",[377,1270],{"x":1158,"y":1264,"width":1159,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1272,1239],{"x":1162,"y":1267,"style":1244},[377,1274],{"x":1168,"y":1264,"width":1169,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1276,1249],{"x":1172,"y":1267,"style":1244},[377,1278],{"x":1176,"y":1264,"width":1177,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1280,1281],{"x":1180,"y":1267,"style":1244},"1790942400",[377,1283],{"x":1184,"y":1264,"width":1185,"height":1200,"rx":69,"fill":900,"stroke":901,"style":1208},[399,1285,1286],{"x":1188,"y":1267,"style":1258},"02 Oct 2026 13:00:00",[377,1288],{"x":1192,"y":1264,"width":1193,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[377,1290],{"x":1154,"y":467,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},[399,1292,379],{"x":1203,"y":1293,"style":1164},"143.0",[377,1295],{"x":1158,"y":467,"width":1159,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1297,1268],{"x":1162,"y":1293,"style":1244},[377,1299],{"x":1168,"y":467,"width":1169,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1301,1302],{"x":1172,"y":1293,"style":1244},"app",[377,1304],{"x":1176,"y":467,"width":1177,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1306,460],{"x":1180,"y":1293,"style":1244},[377,1308],{"x":1184,"y":467,"width":1185,"height":1200,"rx":69,"fill":900,"stroke":901,"style":1208},[399,1310,1259],{"x":1188,"y":1293,"style":1258},[377,1312],{"x":1192,"y":467,"width":1193,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[377,1314],{"x":1154,"y":1315,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},"152.0",[399,1317,1319],{"x":1203,"y":1318,"style":1164},"171.0","5",[377,1321],{"x":1158,"y":1315,"width":1159,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1323,1319],{"x":1162,"y":1318,"style":1244},[377,1325],{"x":1168,"y":1315,"width":1169,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1327,1328],{"x":1172,"y":1318,"style":1244},"db",[377,1330],{"x":1176,"y":1315,"width":1177,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1332,69],{"x":1180,"y":1318,"style":1244},[377,1334],{"x":1184,"y":1315,"width":1185,"height":1200,"rx":69,"fill":900,"stroke":901,"style":1208},[377,1336],{"x":1192,"y":1315,"width":1193,"height":1200,"rx":69,"fill":866,"stroke":867,"style":1208},[399,1338,1340],{"x":1196,"y":1318,"style":1339},"font-size:10.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","no valid timestamp",[377,1342],{"x":1154,"y":491,"width":426,"height":1200,"rx":69,"fill":423,"stroke":389,"style":390},[399,1344,1346],{"x":1203,"y":1345,"style":1164},"199.0","6",[377,1348],{"x":1158,"y":491,"width":1159,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1350,1346],{"x":1162,"y":1345,"style":1244},[377,1352],{"x":1168,"y":491,"width":1169,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1354,1328],{"x":1172,"y":1345,"style":1244},[377,1356],{"x":1176,"y":491,"width":1177,"height":1200,"rx":69,"fill":382,"stroke":389,"style":390},[399,1358,73],{"x":1180,"y":1345,"style":1244},[377,1360],{"x":1184,"y":491,"width":1185,"height":1200,"rx":69,"fill":900,"stroke":901,"style":1208},[377,1362],{"x":1192,"y":491,"width":1193,"height":1200,"rx":69,"fill":866,"stroke":867,"style":1208},[399,1364,1340],{"x":1196,"y":1345,"style":1339},[29,1366,1368],{"id":1367},"step-5-the-same-conversion-as-an-excel-formula","Step 5 — The same conversion as an Excel formula",[10,1370,1371],{},"When the conversion must live in the workbook — a sheet that people paste new exports into — the formula divides seconds by the seconds in a day and adds the Excel serial of 1 January 1970:",[34,1373,1375],{"className":81,"code":1374,"language":83,"meta":39,"style":39},"import subprocess\nfrom openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.append([\"Seconds\", \"Milliseconds\", \"From seconds\", \"From ms\", \"London (BST, +1h)\"])\nws.append([1790920800, 1790920800000, \"=A2\u002F86400+DATE(1970,1,1)\", \"=B2\u002F86400000+DATE(1970,1,1)\",\n           \"=C2+1\u002F24\"])\nfor col in \"CDE\":\n    ws[f\"{col}2\"].number_format = \"dd mmm yyyy hh:mm\"\nwb.save(\"epoch_formulas.xlsx\")\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"recalc\", \"epoch_formulas.xlsx\"],\n               check=True, capture_output=True)\nrow = [c.value for c in load_workbook(\"recalc\u002Fepoch_formulas.xlsx\", data_only=True).active[2]]\nprint(row)\n",[14,1376,1377,1384,1395,1399,1409,1419,1450,1473,1480,1495,1526,1536,1576,1596,1636],{"__ignoreMap":39},[43,1378,1379,1381],{"class":45,"line":46},[43,1380,91],{"class":90},[43,1382,1383],{"class":94}," subprocess\n",[43,1385,1386,1388,1390,1392],{"class":45,"line":104},[43,1387,1083],{"class":90},[43,1389,1086],{"class":94},[43,1391,91],{"class":90},[43,1393,1394],{"class":94}," Workbook\n",[43,1396,1397],{"class":45,"line":111},[43,1398,108],{"emptyLinePlaceholder":107},[43,1400,1401,1404,1406],{"class":45,"line":151},[43,1402,1403],{"class":94},"wb ",[43,1405,117],{"class":90},[43,1407,1408],{"class":94}," Workbook()\n",[43,1410,1411,1414,1416],{"class":45,"line":178},[43,1412,1413],{"class":94},"ws ",[43,1415,117],{"class":90},[43,1417,1418],{"class":94}," wb.active\n",[43,1420,1421,1424,1427,1429,1432,1434,1437,1439,1442,1444,1447],{"class":45,"line":183},[43,1422,1423],{"class":94},"ws.append([",[43,1425,1426],{"class":53},"\"Seconds\"",[43,1428,126],{"class":94},[43,1430,1431],{"class":53},"\"Milliseconds\"",[43,1433,126],{"class":94},[43,1435,1436],{"class":53},"\"From seconds\"",[43,1438,126],{"class":94},[43,1440,1441],{"class":53},"\"From ms\"",[43,1443,126],{"class":94},[43,1445,1446],{"class":53},"\"London (BST, +1h)\"",[43,1448,1449],{"class":94},"])\n",[43,1451,1452,1454,1456,1458,1460,1462,1465,1467,1470],{"class":45,"line":196},[43,1453,1423],{"class":94},[43,1455,16],{"class":144},[43,1457,126],{"class":94},[43,1459,460],{"class":144},[43,1461,126],{"class":94},[43,1463,1464],{"class":53},"\"=A2\u002F86400+DATE(1970,1,1)\"",[43,1466,126],{"class":94},[43,1468,1469],{"class":53},"\"=B2\u002F86400000+DATE(1970,1,1)\"",[43,1471,1472],{"class":94},",\n",[43,1474,1475,1478],{"class":45,"line":220},[43,1476,1477],{"class":53},"           \"=C2+1\u002F24\"",[43,1479,1449],{"class":94},[43,1481,1482,1485,1488,1490,1493],{"class":45,"line":229},[43,1483,1484],{"class":90},"for",[43,1486,1487],{"class":94}," col ",[43,1489,560],{"class":90},[43,1491,1492],{"class":53}," \"CDE\"",[43,1494,217],{"class":94},[43,1496,1497,1500,1503,1506,1509,1512,1515,1518,1521,1523],{"class":45,"line":253},[43,1498,1499],{"class":94},"    ws[",[43,1501,1502],{"class":90},"f",[43,1504,1505],{"class":53},"\"",[43,1507,135],{"class":1508},"sSjpA",[43,1510,1511],{"class":94},"col",[43,1513,1514],{"class":1508},"}",[43,1516,1517],{"class":53},"2\"",[43,1519,1520],{"class":94},"].number_format ",[43,1522,117],{"class":90},[43,1524,1525],{"class":53}," \"dd mmm yyyy hh:mm\"\n",[43,1527,1528,1531,1534],{"class":45,"line":303},[43,1529,1530],{"class":94},"wb.save(",[43,1532,1533],{"class":53},"\"epoch_formulas.xlsx\"",[43,1535,175],{"class":94},[43,1537,1538,1541,1544,1546,1549,1551,1554,1556,1559,1561,1564,1566,1569,1571,1573],{"class":45,"line":308},[43,1539,1540],{"class":94},"subprocess.run([",[43,1542,1543],{"class":53},"\"soffice\"",[43,1545,126],{"class":94},[43,1547,1548],{"class":53},"\"--headless\"",[43,1550,126],{"class":94},[43,1552,1553],{"class":53},"\"--convert-to\"",[43,1555,126],{"class":94},[43,1557,1558],{"class":53},"\"xlsx\"",[43,1560,126],{"class":94},[43,1562,1563],{"class":53},"\"--outdir\"",[43,1565,126],{"class":94},[43,1567,1568],{"class":53},"\"recalc\"",[43,1570,126],{"class":94},[43,1572,1533],{"class":53},[43,1574,1575],{"class":94},"],\n",[43,1577,1578,1581,1583,1585,1587,1590,1592,1594],{"class":45,"line":325},[43,1579,1580],{"class":129},"               check",[43,1582,117],{"class":90},[43,1584,547],{"class":144},[43,1586,126],{"class":94},[43,1588,1589],{"class":129},"capture_output",[43,1591,117],{"class":90},[43,1593,547],{"class":144},[43,1595,175],{"class":94},[43,1597,1599,1602,1604,1607,1609,1612,1614,1616,1619,1621,1624,1626,1628,1631,1633],{"class":45,"line":1598},14,[43,1600,1601],{"class":94},"row ",[43,1603,117],{"class":90},[43,1605,1606],{"class":94}," [c.value ",[43,1608,1484],{"class":90},[43,1610,1611],{"class":94}," c ",[43,1613,560],{"class":90},[43,1615,1101],{"class":94},[43,1617,1618],{"class":53},"\"recalc\u002Fepoch_formulas.xlsx\"",[43,1620,126],{"class":94},[43,1622,1623],{"class":129},"data_only",[43,1625,117],{"class":90},[43,1627,547],{"class":144},[43,1629,1630],{"class":94},").active[",[43,1632,1239],{"class":144},[43,1634,1635],{"class":94},"]]\n",[43,1637,1639,1641],{"class":45,"line":1638},15,[43,1640,328],{"class":144},[43,1642,1643],{"class":94},"(row)\n",[10,1645,1646,1647,1650],{},"Both formulas give 2 October 2026 06:00, matching pandas. Time zones in a formula are only a fixed offset — the ",[14,1648,1649],{},"+1\u002F24"," adds one hour for BST — and the offset changes with daylight saving, which a formula cannot know. That is the strongest argument for converting in Python, where the zone database handles every change.",[29,1652,1654],{"id":1653},"step-6-convert-back-to-unix-time","Step 6 — Convert back to Unix time",[10,1656,1657],{},"APIs often want timestamps in requests, so the reverse is common too:",[34,1659,1661],{"className":81,"code":1660,"language":83,"meta":39,"style":39},"local = pd.Series(pd.to_datetime([\"2026-10-02 07:00\", \"2026-12-24 18:30\"]))\nas_utc = local.dt.tz_localize(\"Europe\u002FLondon\").dt.tz_convert(\"UTC\")\nseconds = (as_utc - pd.Timestamp(\"1970-01-01\", tz=\"UTC\")) \u002F\u002F pd.Timedelta(seconds=1)\nprint(pd.DataFrame({\"Local\": local, \"UTC\": as_utc, \"Unix seconds\": seconds}).to_string(index=False))\n",[14,1662,1663,1684,1703,1748],{"__ignoreMap":39},[43,1664,1665,1668,1670,1673,1676,1678,1681],{"class":45,"line":46},[43,1666,1667],{"class":94},"local ",[43,1669,117],{"class":90},[43,1671,1672],{"class":94}," pd.Series(pd.to_datetime([",[43,1674,1675],{"class":53},"\"2026-10-02 07:00\"",[43,1677,126],{"class":94},[43,1679,1680],{"class":53},"\"2026-12-24 18:30\"",[43,1682,1683],{"class":94},"]))\n",[43,1685,1686,1689,1691,1694,1696,1699,1701],{"class":45,"line":104},[43,1687,1688],{"class":94},"as_utc ",[43,1690,117],{"class":90},[43,1692,1693],{"class":94}," local.dt.tz_localize(",[43,1695,681],{"class":53},[43,1697,1698],{"class":94},").dt.tz_convert(",[43,1700,575],{"class":53},[43,1702,175],{"class":94},[43,1704,1705,1708,1710,1713,1716,1719,1722,1724,1727,1729,1731,1734,1737,1740,1742,1744,1746],{"class":45,"line":111},[43,1706,1707],{"class":94},"seconds ",[43,1709,117],{"class":90},[43,1711,1712],{"class":94}," (as_utc ",[43,1714,1715],{"class":90},"-",[43,1717,1718],{"class":94}," pd.Timestamp(",[43,1720,1721],{"class":53},"\"1970-01-01\"",[43,1723,126],{"class":94},[43,1725,1726],{"class":129},"tz",[43,1728,117],{"class":90},[43,1730,575],{"class":53},[43,1732,1733],{"class":94},")) ",[43,1735,1736],{"class":90},"\u002F\u002F",[43,1738,1739],{"class":94}," pd.Timedelta(",[43,1741,429],{"class":129},[43,1743,117],{"class":90},[43,1745,1205],{"class":144},[43,1747,175],{"class":94},[43,1749,1750,1752,1755,1758,1761,1763,1766,1769,1772,1774,1776,1778],{"class":45,"line":151},[43,1751,328],{"class":144},[43,1753,1754],{"class":94},"(pd.DataFrame({",[43,1756,1757],{"class":53},"\"Local\"",[43,1759,1760],{"class":94},": local, ",[43,1762,575],{"class":53},[43,1764,1765],{"class":94},": as_utc, ",[43,1767,1768],{"class":53},"\"Unix seconds\"",[43,1770,1771],{"class":94},": seconds}).to_string(",[43,1773,342],{"class":129},[43,1775,117],{"class":90},[43,1777,347],{"class":144},[43,1779,350],{"class":94},[10,1781,1782,1783,1785],{},"Localise the naive local times to their zone first, convert to UTC, then count whole seconds since the epoch. Subtracting the epoch and floor-dividing by one second avoids depending on the internal resolution of the datetime column, which in pandas 3 is not always nanoseconds. 07:00 in London on 2 October gives back ",[14,1784,16],{},". The Christmas Eve time shows the zone database at work: in December London is on GMT, so 18:30 local is 18:30 UTC, while the October time was an hour ahead of UTC. A fixed offset applied to both would have got one of them wrong.",[29,1787,1789],{"id":1788},"performance-notes","Performance notes",[10,1791,1792,1794,1795,1798,1799,1802,1803,1806],{},[14,1793,515],{}," with a unit is vectorised and converts millions of timestamps per second; time zone conversion is similarly fast because it works on whole arrays with the zone database. The per-unit grouping adds one conversion per unit, not per row. The expensive mistake is converting row by row with ",[14,1796,1797],{},"datetime.fromtimestamp"," in a loop or ",[14,1800,1801],{},"apply",", which is easily a hundred times slower and, worse, uses the ",[632,1804,1805],{},"machine's"," local time zone unless told otherwise — so the same script gives different answers on a laptop in London and a server in UTC.",[29,1808,1810],{"id":1809},"common-pitfalls","Common pitfalls",[1812,1813,1814,1822,1831,1837,1847,1855],"ul",{},[1815,1816,1817,1821],"li",{},[1818,1819,1820],"strong",{},"Guessing the unit."," A milliseconds value read as seconds lands tens of thousands of years in the future; detect or document the unit.",[1815,1823,1824,1827,1828,1830],{},[1818,1825,1826],{},"Zero placeholders."," ",[14,1829,69],{}," becomes 1 January 1970; treat it as missing.",[1815,1832,1833,1836],{},[1818,1834,1835],{},"Forgetting the time zone."," Unix time is UTC; convert to local time before dropping the zone.",[1815,1838,1839,1842,1843,1846],{},[1818,1840,1841],{},"Numbers read as floats."," Large timestamps read as ",[14,1844,1845],{},"float64"," can lose precision at the microsecond level; read them as text or integers.",[1815,1848,1849,1827,1852,1854],{},[1818,1850,1851],{},"Fixed offsets in formulas.",[14,1853,1649],{}," is right only half the year in the UK.",[1815,1856,1857,1860,1861,1864],{},[1818,1858,1859],{},"Local midnight boundaries."," An event at 03:59 UTC on 3 October belongs to 2 October in New York; aggregate by day ",[632,1862,1863],{},"after"," converting to the readers' zone, not before.",[29,1866,1868],{"id":1867},"conclusion","Conclusion",[10,1870,1871,1872,1875,1876,1878,1879,1882],{},"Unix timestamps count seconds (or milliseconds, microseconds) since 1970 in UTC. Detect the unit from the digit count, convert with ",[14,1873,1874],{},"pd.to_datetime(values, unit=..., utc=True)",", convert to the readers' zone and drop the zone with ",[14,1877,752],{}," before writing to Excel, treat zeros and text as missing, and keep the original value alongside. Use ",[14,1880,1881],{},"=A2\u002F86400+DATE(1970,1,1)"," only when the conversion must stay in the sheet, accepting that it cannot follow daylight saving.",[29,1884,1886],{"id":1885},"frequently-asked-questions","Frequently asked questions",[10,1888,1889,1892],{},[1818,1890,1891],{},"How do I convert a Unix timestamp to a date in pandas?","\nUse pd.to_datetime(series, unit=\"s\", utc=True) for seconds or unit=\"ms\" for milliseconds. The result is a UTC datetime that you can convert to a local time zone.",[10,1894,1895,1898],{},[1818,1896,1897],{},"How can I tell whether a timestamp is in seconds or milliseconds?","\nFor dates between 2001 and 2286, timestamps in seconds have 10 digits, milliseconds 13, microseconds 16 and nanoseconds 19, so the length of the number identifies the unit.",[10,1900,1901,1904],{},[1818,1902,1903],{},"How do I write the converted timestamps to Excel?","\nConvert the UTC datetimes to the readers' zone with dt.tz_convert, remove the zone with dt.tz_localize(None), and write them with to_excel; Excel cannot store time-zone-aware values.",[10,1906,1907,1910],{},[1818,1908,1909],{},"What is the Excel formula for a Unix timestamp?","\n=A2\u002F86400+DATE(1970,1,1) for seconds, or =A2\u002F86400000+DATE(1970,1,1) for milliseconds, formatted as a date-time. The result is in UTC unless you add a fixed offset.",[29,1912,1914],{"id":1913},"related","Related",[1812,1916,1917,1923,1930,1937],{},[1815,1918,1919,1920,1922],{},"Up one level: ",[23,1921,26],{"href":25}," — dates and times in spreadsheets.",[1815,1924,1925,1929],{},[23,1926,1928],{"href":1927},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fhandle-timezones-in-excel-timestamps-with-python\u002F","Handle Timezones in Excel Timestamps with Python"," — zone conversion in depth.",[1815,1931,1932,1936],{},[23,1933,1935],{"href":1934},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmoving-data-between-excel-and-databases\u002Ffetch-api-data-into-excel-with-python-requests\u002F","Fetch API Data into Excel with Python Requests"," — where epoch timestamps usually come from.",[1815,1938,1939,1943],{},[23,1940,1942],{"href":1941},"\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"," — Excel's own number-based dates.",[1945,1946,1947],"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_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":39,"searchDepth":104,"depth":104,"links":1949},[1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,1960,1961],{"id":31,"depth":104,"text":32},{"id":77,"depth":104,"text":78},{"id":509,"depth":104,"text":510},{"id":650,"depth":104,"text":651},{"id":925,"depth":104,"text":926},{"id":1367,"depth":104,"text":1368},{"id":1653,"depth":104,"text":1654},{"id":1788,"depth":104,"text":1789},{"id":1809,"depth":104,"text":1810},{"id":1867,"depth":104,"text":1868},{"id":1885,"depth":104,"text":1886},{"id":1913,"depth":104,"text":1914},"2026-10-02","Exports from APIs, logs and databases give times as Unix timestamps — 1790920800, or 1790920800000 in milliseconds. Detect the unit from the magnitude, convert with pd.to_datetime(unit=..., utc=True), move to the reader's time zone and drop the zone so Excel accepts it, handle zeros and text, convert back, and use the equivalent Excel formula when the conversion must stay in the sheet.","md",[1966,1968,1970,1972],{"q":1891,"a":1967},"Use pd.to_datetime(series, unit=\"s\", utc=True) for seconds or unit=\"ms\" for milliseconds. The result is a UTC datetime that you can convert to a local time zone.",{"q":1897,"a":1969},"For dates between 2001 and 2286, timestamps in seconds have 10 digits, milliseconds 13, microseconds 16 and nanoseconds 19, so the length of the number identifies the unit.",{"q":1903,"a":1971},"Convert the UTC datetimes to the readers' zone with dt.tz_convert, remove the zone with dt.tz_localize(None), and write them with to_excel; Excel cannot store time-zone-aware values.",{"q":1909,"a":1973},"=A2\u002F86400+DATE(1970,1,1) for seconds, or =A2\u002F86400000+DATE(1970,1,1) for milliseconds, formatted as a date-time. The result is in UTC unless you add a fixed offset.","convert unix timestamps to excel dates with pandas",null,{"breadcrumb":1977},[1978,1981,1984],{"name":1979,"item":1980},"Home","\u002F",{"name":1982,"item":1983},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":26,"item":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas",{"title":5,"description":1987},"Turn epoch seconds, milliseconds or microseconds into Excel dates: detect the unit by magnitude, to_datetime(unit, utc=True), tz_convert and tz_localize(None) for Excel, sentinel zeros, the =A2\u002F86400+DATE(1970,1,1) formula, and converting back.","convert-unix-timestamps-to-excel-dates-with-pandas","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-unix-timestamps-to-excel-dates-with-pandas\u002Findex",[1991,1992],"dates-and-times","pandas","how-to","dBnQzb3oOQH8x8pbEmNa6-zS_IYbhM1Rww0F0locLYI",[1996,2000],{"title":1997,"path":1998,"stem":1999,"children":-1},"Convert Text Months and Weekdays to Dates","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-text-months-and-weekdays-to-dates","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-text-months-and-weekdays-to-dates\u002Findex",{"title":2001,"path":2002,"stem":2003,"children":-1},"Convert Year-Week Codes to Dates with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-year-week-codes-to-dates-with-pandas","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-year-week-codes-to-dates-with-pandas\u002Findex",[2005,2007],{"path":2006,"title":1982},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2008,"title":26},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data",[],[2011,2014,2017,2020,2023,2026],{"path":2012,"title":2013,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-overdue-dates-with-openpyxl","Highlight Overdue Dates in Excel with openpyxl",{"path":2015,"title":2016,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-weekends-and-holidays-in-a-date-column","Highlight Weekends and Holidays in a Date Column",{"path":2018,"title":2019,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fkeep-the-latest-record-per-key-with-pandas","Keep the Latest Record per Key When Deduplicating with pandas",{"path":2021,"title":2022,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-moving-averages-with-pandas-rolling","Calculate Moving Averages with pandas rolling",{"path":2024,"title":2025,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Feomonth-and-edate-equivalents-in-pandas","EOMONTH and EDATE Equivalents in pandas",{"path":2027,"title":2028,"kind":1993},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fyearfrac-and-days360-equivalents-in-python","YEARFRAC and DAYS360 Equivalents in Python",1790972105309]