[{"data":1,"prerenderedAt":2398},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas":2364,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas":2373,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas":2378,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas":2379},{"id":4,"title":5,"body":6,"dateModified":2331,"datePublished":2331,"description":2332,"extension":2333,"faq":2334,"keyword":2343,"kind":2344,"meta":2345,"navigation":368,"path":2353,"seo":2354,"slug":2357,"stem":2358,"topics":2359,"type":2362,"__hash__":2363},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas\u002Findex.md","Expand Date Ranges into One Row per Day with pandas",{"type":7,"value":8,"toc":2317},"minimark",[9,27,32,63,74,329,333,340,567,576,649,653,656,844,861,1031,1035,1038,1173,1199,1203,1206,1495,1498,1659,1663,1670,1951,1957,1961,1964,2154,2158,2169,2173,2234,2238,2248,2252,2258,2264,2270,2280,2284,2313],[10,11,12,13,17,18,20,21,26],"p",{},"Many sheets describe things that last: a leave request from the 6th to the 10th, a contract from March to August, a hotel stay, a project assignment. Questions about them are usually asked per day or per month: how many people are off on Friday? How much of this contract's value belongs to April? Which week had the most rooms booked? The simplest way to answer all of them is to expand each range into one row per day it covers. After that, \"per day\" is a ",[14,15,16],"code",{},"groupby"," on the date, and \"per month\" a ",[14,19,16],{}," on the month — no interval arithmetic needed. This page is part of ",[22,23,25],"a",{"href":24},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002F","Working with Dates and Times in Excel Data",".",[28,29,31],"h2",{"id":30},"prerequisites","Prerequisites",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas numpy openpyxl\n","bash","",[14,40,41],{"__ignoreMap":38},[42,43,46,50,54,57,60],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sMTad","pip",[42,51,53],{"class":52},"srMev"," install",[42,55,56],{"class":52}," pandas",[42,58,59],{"class":52}," numpy",[42,61,62],{"class":52}," openpyxl\n",[10,64,65,66,69,70,73],{},"Two sheets, both with inclusive start and end dates. ",[14,67,68],{},"july_leave.xlsx"," has six leave requests in three teams. ",[14,71,72],{},"contracts.xlsx"," has four service contracts with a total value each, some of them spanning several months and one running into next year.",[75,76,84,85,84,89,84,93,84,101,84,110,84,114,84,121,84,125,84,129,84,133,84,137,84,141,84,146,84,148,84,152,84,154,84,157,84,159,84,162,84,165,84,169,84,171,84,175,84,177,84,180,84,182,84,185,84,188,84,191,84,194,84,197,84,200,84,202,84,205,84,207,84,209,84,214,84,218,84,220,84,222,84,224,84,226,84,228,84,230,84,233,84,237,84,239,84,241,84,243,84,246,84,249,84,253,84,255,84,257,84,259,84,262,84,265,84,269,84,271,84,273,84,275,84,278,84,281,84,285,84,287,84,289,84,291,84,293,84,299,84,303,84,310,84,315,84,323],"svg",{"viewBox":77,"role":78,"ariaLabelledBy":79,"xmlns":82,"style":83},"52 0 655 248","img",[80,81],"ex-explode-t","ex-explode-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:655px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[86,87,88],"title",{"id":80},"One range becomes one row per day",[90,91,92],"desc",{"id":81},"On the left a single leave request from 6 to 10 July. On the right five rows, one for each day from 6 to 10 July, each carrying the employee's name.",[94,95],"rect",{"x":96,"y":97,"width":98,"height":99,"fill":100},"52","0","655","248","#ffffff",[94,102],{"x":103,"y":104,"width":105,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"68.7","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[94,111],{"x":112,"y":104,"width":113,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"100.7","79.8",[115,116,120],"text",{"x":117,"y":118,"style":119},"140.6","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[94,122],{"x":123,"y":104,"width":124,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"180.4","59.1",[115,126,128],{"x":127,"y":118,"style":119},"210.0","B",[94,130],{"x":131,"y":104,"width":132,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"239.5","56.6",[115,134,136],{"x":135,"y":118,"style":119},"267.8","C",[94,138],{"x":103,"y":139,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"64.0","28.0",[115,142,145],{"x":143,"y":144,"style":119},"84.7","83.0","1",[94,147],{"x":112,"y":139,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,149,151],{"x":117,"y":144,"style":150},"font-size:11px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Employee",[94,153],{"x":123,"y":139,"width":124,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,155,156],{"x":127,"y":144,"style":150},"Start",[94,158],{"x":131,"y":139,"width":132,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,160,161],{"x":135,"y":144,"style":150},"End",[94,163],{"x":103,"y":164,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"92.0",[115,166,168],{"x":143,"y":167,"style":119},"111.0","2",[94,170],{"x":112,"y":164,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,172,174],{"x":117,"y":167,"style":173},"font-size:11px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Adaeze",[94,176],{"x":123,"y":164,"width":124,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,178,179],{"x":127,"y":167,"style":173},"06 Jul",[94,181],{"x":131,"y":164,"width":132,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,183,184],{"x":135,"y":167,"style":173},"10 Jul",[94,186],{"x":187,"y":104,"width":105,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"520.4",[94,189],{"x":190,"y":104,"width":113,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"552.4",[115,192,120],{"x":193,"y":118,"style":119},"592.3",[94,195],{"x":196,"y":104,"width":124,"height":106,"rx":97,"fill":107,"stroke":108,"style":109},"632.2",[115,198,128],{"x":199,"y":118,"style":119},"661.8",[94,201],{"x":187,"y":139,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},[115,203,145],{"x":204,"y":144,"style":119},"536.4",[94,206],{"x":190,"y":139,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,208,151],{"x":193,"y":144,"style":150},[94,210],{"x":196,"y":139,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},"#d9f4f1","var(--teal,#0f9488)","stroke-width:1.5px",[115,215,217],{"x":199,"y":144,"style":216},"font-size:11px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Day",[94,219],{"x":187,"y":164,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},[115,221,168],{"x":204,"y":167,"style":119},[94,223],{"x":190,"y":164,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,225,174],{"x":193,"y":167,"style":173},[94,227],{"x":196,"y":164,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},[115,229,179],{"x":199,"y":167,"style":216},[94,231],{"x":187,"y":232,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"120.0",[115,234,236],{"x":204,"y":235,"style":119},"139.0","3",[94,238],{"x":190,"y":232,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,240,174],{"x":193,"y":235,"style":173},[94,242],{"x":196,"y":232,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},[115,244,245],{"x":199,"y":235,"style":216},"07 Jul",[94,247],{"x":187,"y":248,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"148.0",[115,250,252],{"x":204,"y":251,"style":119},"167.0","4",[94,254],{"x":190,"y":248,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,256,174],{"x":193,"y":251,"style":173},[94,258],{"x":196,"y":248,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},[115,260,261],{"x":199,"y":251,"style":216},"08 Jul",[94,263],{"x":187,"y":264,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"176.0",[115,266,268],{"x":204,"y":267,"style":119},"195.0","5",[94,270],{"x":190,"y":264,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,272,174],{"x":193,"y":267,"style":173},[94,274],{"x":196,"y":264,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},[115,276,277],{"x":199,"y":267,"style":216},"09 Jul",[94,279],{"x":187,"y":280,"width":105,"height":140,"rx":97,"fill":107,"stroke":108,"style":109},"204.0",[115,282,284],{"x":204,"y":283,"style":119},"223.0","6",[94,286],{"x":190,"y":280,"width":113,"height":140,"rx":97,"fill":100,"stroke":108,"style":109},[115,288,174],{"x":193,"y":283,"style":173},[94,290],{"x":196,"y":280,"width":124,"height":140,"rx":97,"fill":211,"stroke":212,"style":213},[115,292,184],{"x":199,"y":283,"style":216},[115,294,298],{"x":295,"y":296,"style":297},"182.4","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","before",[115,300,302],{"x":301,"y":296,"style":297},"605.9","after",[44,304],{"x1":305,"y1":306,"x2":307,"y2":306,"stroke":308,"style":309},"306.1","80.0","506.4","var(--brand,#5b5cf0)","stroke-width:2px",[311,312],"polygon",{"points":313,"fill":314},"510.4,80.0 501.4,85.0 501.4,75.0","#5b5cf0",[94,316],{"x":317,"y":318,"width":319,"height":320,"rx":321,"fill":100,"stroke":108,"style":322},"334.5","47.0","147.5","22.0","11","stroke-width:1.2px",[115,324,328],{"x":325,"y":326,"style":327},"408.3","62.0","font-size:11.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","date_range + explode",[28,330,332],{"id":331},"step-1-expand-with-date_range-and-explode","Step 1 — Expand with date_range and explode",[10,334,335,336,339],{},"For each row, build the list of days it covers, then ",[14,337,338],{},"explode"," the list so each day becomes its own row with the other columns copied:",[33,341,345],{"className":342,"code":343,"language":344,"meta":38,"style":38},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nleave = pd.read_excel(\"july_leave.xlsx\", parse_dates=[\"Start\", \"End\"])\nleave[\"Day\"] = [pd.date_range(s, e, freq=\"D\") for s, e in zip(leave[\"Start\"], leave[\"End\"])]\ndaily = leave.explode(\"Day\").drop(columns=[\"Start\", \"End\"])\ndaily[\"Day\"] = pd.to_datetime(daily[\"Day\"])\nprint(len(leave), \"requests ->\", len(daily), \"person-days\")\nprint(daily.head(6).to_string(index=False))\n","python",[14,346,347,363,370,408,462,493,512,543],{"__ignoreMap":38},[42,348,349,353,357,360],{"class":44,"line":45},[42,350,352],{"class":351},"s-kum","import",[42,354,356],{"class":355},"skGVy"," pandas ",[42,358,359],{"class":351},"as",[42,361,362],{"class":355}," pd\n",[42,364,366],{"class":44,"line":365},2,[42,367,369],{"emptyLinePlaceholder":368},true,"\n",[42,371,373,376,379,382,385,388,392,394,397,400,402,405],{"class":44,"line":372},3,[42,374,375],{"class":355},"leave ",[42,377,378],{"class":351},"=",[42,380,381],{"class":355}," pd.read_excel(",[42,383,384],{"class":52},"\"july_leave.xlsx\"",[42,386,387],{"class":355},", ",[42,389,391],{"class":390},"sa561","parse_dates",[42,393,378],{"class":351},[42,395,396],{"class":355},"[",[42,398,399],{"class":52},"\"Start\"",[42,401,387],{"class":355},[42,403,404],{"class":52},"\"End\"",[42,406,407],{"class":355},"])\n",[42,409,411,414,417,420,422,425,428,430,433,436,439,442,445,449,452,454,457,459],{"class":44,"line":410},4,[42,412,413],{"class":355},"leave[",[42,415,416],{"class":52},"\"Day\"",[42,418,419],{"class":355},"] ",[42,421,378],{"class":351},[42,423,424],{"class":355}," [pd.date_range(s, e, ",[42,426,427],{"class":390},"freq",[42,429,378],{"class":351},[42,431,432],{"class":52},"\"D\"",[42,434,435],{"class":355},") ",[42,437,438],{"class":351},"for",[42,440,441],{"class":355}," s, e ",[42,443,444],{"class":351},"in",[42,446,448],{"class":447},"sP0c6"," zip",[42,450,451],{"class":355},"(leave[",[42,453,399],{"class":52},[42,455,456],{"class":355},"], leave[",[42,458,404],{"class":52},[42,460,461],{"class":355},"])]\n",[42,463,465,468,470,473,475,478,481,483,485,487,489,491],{"class":44,"line":464},5,[42,466,467],{"class":355},"daily ",[42,469,378],{"class":351},[42,471,472],{"class":355}," leave.explode(",[42,474,416],{"class":52},[42,476,477],{"class":355},").drop(",[42,479,480],{"class":390},"columns",[42,482,378],{"class":351},[42,484,396],{"class":355},[42,486,399],{"class":52},[42,488,387],{"class":355},[42,490,404],{"class":52},[42,492,407],{"class":355},[42,494,496,499,501,503,505,508,510],{"class":44,"line":495},6,[42,497,498],{"class":355},"daily[",[42,500,416],{"class":52},[42,502,419],{"class":355},[42,504,378],{"class":351},[42,506,507],{"class":355}," pd.to_datetime(daily[",[42,509,416],{"class":52},[42,511,407],{"class":355},[42,513,515,518,521,524,527,530,532,534,537,540],{"class":44,"line":514},7,[42,516,517],{"class":447},"print",[42,519,520],{"class":355},"(",[42,522,523],{"class":447},"len",[42,525,526],{"class":355},"(leave), ",[42,528,529],{"class":52},"\"requests ->\"",[42,531,387],{"class":355},[42,533,523],{"class":447},[42,535,536],{"class":355},"(daily), ",[42,538,539],{"class":52},"\"person-days\"",[42,541,542],{"class":355},")\n",[42,544,546,548,551,553,556,559,561,564],{"class":44,"line":545},8,[42,547,517],{"class":447},[42,549,550],{"class":355},"(daily.head(",[42,552,284],{"class":447},[42,554,555],{"class":355},").to_string(",[42,557,558],{"class":390},"index",[42,560,378],{"class":351},[42,562,563],{"class":447},"False",[42,565,566],{"class":355},"))\n",[10,568,569,572,573,575],{},[14,570,571],{},"pd.date_range(start, end)"," includes both ends, which matches inclusive end dates. After ",[14,574,338],{},", the new column holds objects, so convert it back to a datetime column. Check the count straight away: the number of rows after expansion must equal the sum of each range's length in days, and a mismatch means a reversed or missing date somewhere:",[33,577,579],{"className":342,"code":578,"language":344,"meta":38,"style":38},"expected = ((leave[\"End\"] - leave[\"Start\"]).dt.days + 1).sum()\nassert len(daily) == expected, (len(daily), expected)\nprint(\"expected\", expected)\n",[14,580,581,615,637],{"__ignoreMap":38},[42,582,583,586,588,591,593,595,598,601,603,606,609,612],{"class":44,"line":45},[42,584,585],{"class":355},"expected ",[42,587,378],{"class":351},[42,589,590],{"class":355}," ((leave[",[42,592,404],{"class":52},[42,594,419],{"class":355},[42,596,597],{"class":351},"-",[42,599,600],{"class":355}," leave[",[42,602,399],{"class":52},[42,604,605],{"class":355},"]).dt.days ",[42,607,608],{"class":351},"+",[42,610,611],{"class":447}," 1",[42,613,614],{"class":355},").sum()\n",[42,616,617,620,623,626,629,632,634],{"class":44,"line":365},[42,618,619],{"class":351},"assert",[42,621,622],{"class":447}," len",[42,624,625],{"class":355},"(daily) ",[42,627,628],{"class":351},"==",[42,630,631],{"class":355}," expected, (",[42,633,523],{"class":447},[42,635,636],{"class":355},"(daily), expected)\n",[42,638,639,641,643,646],{"class":44,"line":372},[42,640,517],{"class":447},[42,642,520],{"class":355},[42,644,645],{"class":52},"\"expected\"",[42,647,648],{"class":355},", expected)\n",[28,650,652],{"id":651},"step-2-count-per-day","Step 2 — Count per day",[10,654,655],{},"With one row per person per day, the daily headcount away is a group-by. Reindex over every day of the month so days with nobody away appear as zero, and pivot by team to see who is short:",[33,657,659],{"className":342,"code":658,"language":344,"meta":38,"style":38},"july = pd.date_range(\"2026-07-01\", \"2026-07-31\")\nper_day = daily.groupby(\"Day\").size().reindex(july, fill_value=0)\nprint(per_day[\"2026-07-06\":\"2026-07-15\"].rename(lambda d: d.strftime(\"%d %b\")).to_dict())\nprint(\"busiest day:\", per_day.idxmax().date(), \"with\", per_day.max(), \"away\")\n\nby_team = daily.pivot_table(index=\"Day\", columns=\"Team\", values=\"Employee\", aggfunc=\"count\", fill_value=0)\nprint(by_team.loc[\"2026-07-09\":\"2026-07-14\"])\n",[14,660,661,681,705,745,768,772,827],{"__ignoreMap":38},[42,662,663,666,668,671,674,676,679],{"class":44,"line":45},[42,664,665],{"class":355},"july ",[42,667,378],{"class":351},[42,669,670],{"class":355}," pd.date_range(",[42,672,673],{"class":52},"\"2026-07-01\"",[42,675,387],{"class":355},[42,677,678],{"class":52},"\"2026-07-31\"",[42,680,542],{"class":355},[42,682,683,686,688,691,693,696,699,701,703],{"class":44,"line":365},[42,684,685],{"class":355},"per_day ",[42,687,378],{"class":351},[42,689,690],{"class":355}," daily.groupby(",[42,692,416],{"class":52},[42,694,695],{"class":355},").size().reindex(july, ",[42,697,698],{"class":390},"fill_value",[42,700,378],{"class":351},[42,702,97],{"class":447},[42,704,542],{"class":355},[42,706,707,709,712,715,718,721,724,727,730,733,737,740,742],{"class":44,"line":372},[42,708,517],{"class":447},[42,710,711],{"class":355},"(per_day[",[42,713,714],{"class":52},"\"2026-07-06\"",[42,716,717],{"class":355},":",[42,719,720],{"class":52},"\"2026-07-15\"",[42,722,723],{"class":355},"].rename(",[42,725,726],{"class":351},"lambda",[42,728,729],{"class":355}," d: d.strftime(",[42,731,732],{"class":52},"\"",[42,734,736],{"class":735},"sSjpA","%d",[42,738,739],{"class":735}," %b",[42,741,732],{"class":52},[42,743,744],{"class":355},")).to_dict())\n",[42,746,747,749,751,754,757,760,763,766],{"class":44,"line":410},[42,748,517],{"class":447},[42,750,520],{"class":355},[42,752,753],{"class":52},"\"busiest day:\"",[42,755,756],{"class":355},", per_day.idxmax().date(), ",[42,758,759],{"class":52},"\"with\"",[42,761,762],{"class":355},", per_day.max(), ",[42,764,765],{"class":52},"\"away\"",[42,767,542],{"class":355},[42,769,770],{"class":44,"line":464},[42,771,369],{"emptyLinePlaceholder":368},[42,773,774,777,779,782,784,786,788,790,792,794,797,799,802,804,807,809,812,814,817,819,821,823,825],{"class":44,"line":495},[42,775,776],{"class":355},"by_team ",[42,778,378],{"class":351},[42,780,781],{"class":355}," daily.pivot_table(",[42,783,558],{"class":390},[42,785,378],{"class":351},[42,787,416],{"class":52},[42,789,387],{"class":355},[42,791,480],{"class":390},[42,793,378],{"class":351},[42,795,796],{"class":52},"\"Team\"",[42,798,387],{"class":355},[42,800,801],{"class":390},"values",[42,803,378],{"class":351},[42,805,806],{"class":52},"\"Employee\"",[42,808,387],{"class":355},[42,810,811],{"class":390},"aggfunc",[42,813,378],{"class":351},[42,815,816],{"class":52},"\"count\"",[42,818,387],{"class":355},[42,820,698],{"class":390},[42,822,378],{"class":351},[42,824,97],{"class":447},[42,826,542],{"class":355},[42,828,829,831,834,837,839,842],{"class":44,"line":514},[42,830,517],{"class":447},[42,832,833],{"class":355},"(by_team.loc[",[42,835,836],{"class":52},"\"2026-07-09\"",[42,838,717],{"class":355},[42,840,841],{"class":52},"\"2026-07-14\"",[42,843,407],{"class":355},[10,845,846,847,851,852,856,857,860],{},"The busiest days are the 9th, 10th, 13th and 14th, with four people away. The team view shows where it hurts: on the 9th, both Ken and Claire from Sales are off, while Engineering never has more than two people away at once — the fact a manager needs before approving the next request. ",[22,848,850],{"href":849},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffind-overlapping-date-ranges-with-pandas\u002F","Find Overlapping Date Ranges with pandas"," lists ",[853,854,855],"em",{},"which"," requests clash; the daily count shows ",[853,858,859],{},"how bad"," each day is.",[75,862,84,868,84,871,84,874,84,878,84,883,84,888,84,892,84,895,84,898,84,901,84,904,84,907,84,909,84,911,84,914,84,919,84,923,84,927,84,931,84,935,84,938,84,942,84,946,84,950,84,954,84,958,84,962,84,968,84,972,84,975,84,977,84,981,84,984,84,988,84,991,84,994,84,996,84,999,84,1001,84,1004,84,1006,84,1009,84,1011,84,1014,84,1016,84,1019,84,1021,84,1024,84,1026,84,1029],{"viewBox":863,"role":78,"ariaLabelledBy":864,"xmlns":82,"style":867},"4 0 748 212",[865,866],"ex-headcount-t","ex-headcount-d","width:100%;max-width:748px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[86,869,870],{"id":865},"People on leave per day, 6 to 17 July",[90,872,873],{"id":866},"Column chart of the number of employees on leave each day from 6 to 17 July. The count rises from 2 on 6 July to a peak of 4 on 9, 10, 13 and 14 July, then falls to 2 by 16 and 17 July.",[94,875],{"x":252,"y":97,"width":876,"height":877,"fill":100},"748","212",[44,879],{"x1":880,"y1":881,"x2":882,"y2":881,"stroke":108,"style":109},"39.5","174.0","736.0",[115,884,97],{"x":885,"y":886,"style":887},"23.7","178.0","font-size:11px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle",[44,889],{"x1":880,"y1":890,"x2":882,"y2":890,"stroke":108,"style":891},"136.5","stroke-width:1px;stroke-dasharray:5 4",[115,893,145],{"x":885,"y":894,"style":887},"140.5",[44,896],{"x1":880,"y1":897,"x2":882,"y2":897,"stroke":108,"style":891},"99.0",[115,899,168],{"x":885,"y":900,"style":887},"103.0",[44,902],{"x1":880,"y1":903,"x2":882,"y2":903,"stroke":108,"style":891},"61.5",[115,905,236],{"x":885,"y":906,"style":887},"65.5",[44,908],{"x1":880,"y1":106,"x2":882,"y2":106,"stroke":108,"style":891},[115,910,252],{"x":885,"y":140,"style":887},[44,912],{"x1":880,"y1":881,"x2":882,"y2":881,"stroke":913,"style":213},"var(--muted,#5b6780)",[115,915,284],{"x":916,"y":917,"style":918},"68.5","192.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[115,920,922],{"x":921,"y":917,"style":918},"126.5","7",[115,924,926],{"x":925,"y":917,"style":918},"184.6","8",[115,928,930],{"x":929,"y":917,"style":918},"242.6","9",[115,932,934],{"x":933,"y":917,"style":918},"300.7","10",[115,936,321],{"x":937,"y":917,"style":918},"358.7",[115,939,941],{"x":940,"y":917,"style":918},"416.8","12",[115,943,945],{"x":944,"y":917,"style":918},"474.8","13",[115,947,949],{"x":948,"y":917,"style":918},"532.8","14",[115,951,953],{"x":952,"y":917,"style":918},"590.9","15",[115,955,957],{"x":956,"y":917,"style":918},"648.9","16",[115,959,961],{"x":960,"y":917,"style":918},"707.0","17",[94,963],{"x":964,"y":897,"width":965,"height":966,"rx":236,"fill":967,"stroke":308,"style":213},"50.5","36.0","75.0","#f0f4ff",[115,969,168],{"x":916,"y":970,"style":971},"93.0","font-size:10.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[94,973],{"x":974,"y":897,"width":965,"height":966,"rx":236,"fill":967,"stroke":308,"style":213},"108.5",[115,976,168],{"x":921,"y":970,"style":971},[94,978],{"x":979,"y":903,"width":965,"height":980,"rx":236,"fill":967,"stroke":308,"style":213},"166.6","112.5",[115,982,236],{"x":925,"y":983,"style":971},"55.5",[94,985],{"x":986,"y":106,"width":965,"height":987,"rx":236,"fill":967,"stroke":308,"style":213},"224.6","150.0",[115,989,252],{"x":929,"y":990,"style":971},"18.0",[94,992],{"x":993,"y":106,"width":965,"height":987,"rx":236,"fill":967,"stroke":308,"style":213},"282.7",[115,995,252],{"x":933,"y":990,"style":971},[94,997],{"x":998,"y":903,"width":965,"height":980,"rx":236,"fill":967,"stroke":308,"style":213},"340.7",[115,1000,236],{"x":937,"y":983,"style":971},[94,1002],{"x":1003,"y":903,"width":965,"height":980,"rx":236,"fill":967,"stroke":308,"style":213},"398.8",[115,1005,236],{"x":940,"y":983,"style":971},[94,1007],{"x":1008,"y":106,"width":965,"height":987,"rx":236,"fill":967,"stroke":308,"style":213},"456.8",[115,1010,252],{"x":944,"y":990,"style":971},[94,1012],{"x":1013,"y":106,"width":965,"height":987,"rx":236,"fill":967,"stroke":308,"style":213},"514.8",[115,1015,252],{"x":948,"y":990,"style":971},[94,1017],{"x":1018,"y":903,"width":965,"height":980,"rx":236,"fill":967,"stroke":308,"style":213},"572.9",[115,1020,236],{"x":952,"y":983,"style":971},[94,1022],{"x":1023,"y":897,"width":965,"height":966,"rx":236,"fill":967,"stroke":308,"style":213},"630.9",[115,1025,168],{"x":956,"y":970,"style":971},[94,1027],{"x":1028,"y":897,"width":965,"height":966,"rx":236,"fill":967,"stroke":308,"style":213},"689.0",[115,1030,168],{"x":960,"y":970,"style":971},[28,1032,1034],{"id":1033},"step-3-working-days-only","Step 3 — Working days only",[10,1036,1037],{},"Leave is taken on working days; weekends inside a request are not days off. Use business days instead of calendar days, with public holidays excluded:",[33,1039,1041],{"className":342,"code":1040,"language":344,"meta":38,"style":38},"from pandas.tseries.offsets import CustomBusinessDay\n\nholidays = [\"2026-07-03\"]                 # a company holiday\nworkdays = CustomBusinessDay(holidays=holidays)\nleave[\"WorkDay\"] = [pd.date_range(s, e, freq=workdays) for s, e in zip(leave[\"Start\"], leave[\"End\"])]\nwork = leave.explode(\"WorkDay\").dropna(subset=[\"WorkDay\"])\nprint(work.groupby(\"Employee\").size().to_dict())\n",[14,1042,1043,1056,1060,1080,1098,1136,1161],{"__ignoreMap":38},[42,1044,1045,1048,1051,1053],{"class":44,"line":45},[42,1046,1047],{"class":351},"from",[42,1049,1050],{"class":355}," pandas.tseries.offsets ",[42,1052,352],{"class":351},[42,1054,1055],{"class":355}," CustomBusinessDay\n",[42,1057,1058],{"class":44,"line":365},[42,1059,369],{"emptyLinePlaceholder":368},[42,1061,1062,1065,1067,1070,1073,1076],{"class":44,"line":372},[42,1063,1064],{"class":355},"holidays ",[42,1066,378],{"class":351},[42,1068,1069],{"class":355}," [",[42,1071,1072],{"class":52},"\"2026-07-03\"",[42,1074,1075],{"class":355},"]                 ",[42,1077,1079],{"class":1078},"s-wDw","# a company holiday\n",[42,1081,1082,1085,1087,1090,1093,1095],{"class":44,"line":410},[42,1083,1084],{"class":355},"workdays ",[42,1086,378],{"class":351},[42,1088,1089],{"class":355}," CustomBusinessDay(",[42,1091,1092],{"class":390},"holidays",[42,1094,378],{"class":351},[42,1096,1097],{"class":355},"holidays)\n",[42,1099,1100,1102,1105,1107,1109,1111,1113,1115,1118,1120,1122,1124,1126,1128,1130,1132,1134],{"class":44,"line":464},[42,1101,413],{"class":355},[42,1103,1104],{"class":52},"\"WorkDay\"",[42,1106,419],{"class":355},[42,1108,378],{"class":351},[42,1110,424],{"class":355},[42,1112,427],{"class":390},[42,1114,378],{"class":351},[42,1116,1117],{"class":355},"workdays) ",[42,1119,438],{"class":351},[42,1121,441],{"class":355},[42,1123,444],{"class":351},[42,1125,448],{"class":447},[42,1127,451],{"class":355},[42,1129,399],{"class":52},[42,1131,456],{"class":355},[42,1133,404],{"class":52},[42,1135,461],{"class":355},[42,1137,1138,1141,1143,1145,1147,1150,1153,1155,1157,1159],{"class":44,"line":495},[42,1139,1140],{"class":355},"work ",[42,1142,378],{"class":351},[42,1144,472],{"class":355},[42,1146,1104],{"class":52},[42,1148,1149],{"class":355},").dropna(",[42,1151,1152],{"class":390},"subset",[42,1154,378],{"class":351},[42,1156,396],{"class":355},[42,1158,1104],{"class":52},[42,1160,407],{"class":355},[42,1162,1163,1165,1168,1170],{"class":44,"line":514},[42,1164,517],{"class":447},[42,1166,1167],{"class":355},"(work.groupby(",[42,1169,806],{"class":52},[42,1171,1172],{"class":355},").size().to_dict())\n",[10,1174,1175,1178,1179,1182,1183,1185,1186,1189,1190,1193,1194,1198],{},[14,1176,1177],{},"CustomBusinessDay"," skips Saturdays, Sundays and the listed holidays; ",[14,1180,1181],{},"freq=\"B\""," alone skips only weekends. A range that falls entirely on a weekend produces an empty list, which ",[14,1184,338],{}," turns into a single row with ",[14,1187,1188],{},"NaN"," — hence the ",[14,1191,1192],{},"dropna",". Ken's 1–17 July request is thirteen weekdays but only twelve days of leave, because the 3rd is a company holiday. ",[22,1195,1197],{"href":1196},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-business-days-between-excel-dates-with-pandas\u002F","Calculate Business Days Between Excel Dates with pandas"," covers holiday calendars in more depth.",[28,1200,1202],{"id":1201},"step-4-spread-a-value-across-the-days-prorating","Step 4 — Spread a value across the days: prorating",[10,1204,1205],{},"A contract worth 18,200 from 15 March to 14 June earns part of that value in each month. Expanding to days and giving each day an equal share turns \"how much belongs to April\" into a sum:",[33,1207,1209],{"className":342,"code":1208,"language":344,"meta":38,"style":38},"contracts = pd.read_excel(\"contracts.xlsx\", parse_dates=[\"Start\", \"End\"])\ncontracts[\"Days\"] = (contracts[\"End\"] - contracts[\"Start\"]).dt.days + 1\ncontracts[\"Day\"] = [pd.date_range(s, e) for s, e in zip(contracts[\"Start\"], contracts[\"End\"])]\nper_day = contracts.explode(\"Day\")\nper_day[\"Day\"] = pd.to_datetime(per_day[\"Day\"])\nper_day[\"Share\"] = per_day[\"Value\"] \u002F per_day[\"Days\"]\n\nmonthly = (per_day.assign(Month=per_day[\"Day\"].dt.to_period(\"M\"))\n                  .pivot_table(index=\"Contract\", columns=\"Month\", values=\"Share\", aggfunc=\"sum\", fill_value=0)\n                  .round(2))\nprint(monthly.iloc[:, :7])\nprint(\"check:\", monthly.sum(axis=1).round(2).to_dict())\n",[14,1210,1211,1239,1272,1305,1318,1336,1365,1369,1396,1445,1455,1467],{"__ignoreMap":38},[42,1212,1213,1216,1218,1220,1223,1225,1227,1229,1231,1233,1235,1237],{"class":44,"line":45},[42,1214,1215],{"class":355},"contracts ",[42,1217,378],{"class":351},[42,1219,381],{"class":355},[42,1221,1222],{"class":52},"\"contracts.xlsx\"",[42,1224,387],{"class":355},[42,1226,391],{"class":390},[42,1228,378],{"class":351},[42,1230,396],{"class":355},[42,1232,399],{"class":52},[42,1234,387],{"class":355},[42,1236,404],{"class":52},[42,1238,407],{"class":355},[42,1240,1241,1244,1247,1249,1251,1254,1256,1258,1260,1263,1265,1267,1269],{"class":44,"line":365},[42,1242,1243],{"class":355},"contracts[",[42,1245,1246],{"class":52},"\"Days\"",[42,1248,419],{"class":355},[42,1250,378],{"class":351},[42,1252,1253],{"class":355}," (contracts[",[42,1255,404],{"class":52},[42,1257,419],{"class":355},[42,1259,597],{"class":351},[42,1261,1262],{"class":355}," contracts[",[42,1264,399],{"class":52},[42,1266,605],{"class":355},[42,1268,608],{"class":351},[42,1270,1271],{"class":447}," 1\n",[42,1273,1274,1276,1278,1280,1282,1285,1287,1289,1291,1293,1296,1298,1301,1303],{"class":44,"line":372},[42,1275,1243],{"class":355},[42,1277,416],{"class":52},[42,1279,419],{"class":355},[42,1281,378],{"class":351},[42,1283,1284],{"class":355}," [pd.date_range(s, e) ",[42,1286,438],{"class":351},[42,1288,441],{"class":355},[42,1290,444],{"class":351},[42,1292,448],{"class":447},[42,1294,1295],{"class":355},"(contracts[",[42,1297,399],{"class":52},[42,1299,1300],{"class":355},"], contracts[",[42,1302,404],{"class":52},[42,1304,461],{"class":355},[42,1306,1307,1309,1311,1314,1316],{"class":44,"line":410},[42,1308,685],{"class":355},[42,1310,378],{"class":351},[42,1312,1313],{"class":355}," contracts.explode(",[42,1315,416],{"class":52},[42,1317,542],{"class":355},[42,1319,1320,1323,1325,1327,1329,1332,1334],{"class":44,"line":464},[42,1321,1322],{"class":355},"per_day[",[42,1324,416],{"class":52},[42,1326,419],{"class":355},[42,1328,378],{"class":351},[42,1330,1331],{"class":355}," pd.to_datetime(per_day[",[42,1333,416],{"class":52},[42,1335,407],{"class":355},[42,1337,1338,1340,1343,1345,1347,1350,1353,1355,1358,1360,1362],{"class":44,"line":495},[42,1339,1322],{"class":355},[42,1341,1342],{"class":52},"\"Share\"",[42,1344,419],{"class":355},[42,1346,378],{"class":351},[42,1348,1349],{"class":355}," per_day[",[42,1351,1352],{"class":52},"\"Value\"",[42,1354,419],{"class":355},[42,1356,1357],{"class":351},"\u002F",[42,1359,1349],{"class":355},[42,1361,1246],{"class":52},[42,1363,1364],{"class":355},"]\n",[42,1366,1367],{"class":44,"line":514},[42,1368,369],{"emptyLinePlaceholder":368},[42,1370,1371,1374,1376,1379,1382,1384,1386,1388,1391,1394],{"class":44,"line":545},[42,1372,1373],{"class":355},"monthly ",[42,1375,378],{"class":351},[42,1377,1378],{"class":355}," (per_day.assign(",[42,1380,1381],{"class":390},"Month",[42,1383,378],{"class":351},[42,1385,1322],{"class":355},[42,1387,416],{"class":52},[42,1389,1390],{"class":355},"].dt.to_period(",[42,1392,1393],{"class":52},"\"M\"",[42,1395,566],{"class":355},[42,1397,1399,1402,1404,1406,1409,1411,1413,1415,1418,1420,1422,1424,1426,1428,1430,1432,1435,1437,1439,1441,1443],{"class":44,"line":1398},9,[42,1400,1401],{"class":355},"                  .pivot_table(",[42,1403,558],{"class":390},[42,1405,378],{"class":351},[42,1407,1408],{"class":52},"\"Contract\"",[42,1410,387],{"class":355},[42,1412,480],{"class":390},[42,1414,378],{"class":351},[42,1416,1417],{"class":52},"\"Month\"",[42,1419,387],{"class":355},[42,1421,801],{"class":390},[42,1423,378],{"class":351},[42,1425,1342],{"class":52},[42,1427,387],{"class":355},[42,1429,811],{"class":390},[42,1431,378],{"class":351},[42,1433,1434],{"class":52},"\"sum\"",[42,1436,387],{"class":355},[42,1438,698],{"class":390},[42,1440,378],{"class":351},[42,1442,97],{"class":447},[42,1444,542],{"class":355},[42,1446,1448,1451,1453],{"class":44,"line":1447},10,[42,1449,1450],{"class":355},"                  .round(",[42,1452,168],{"class":447},[42,1454,566],{"class":355},[42,1456,1458,1460,1463,1465],{"class":44,"line":1457},11,[42,1459,517],{"class":447},[42,1461,1462],{"class":355},"(monthly.iloc[:, :",[42,1464,922],{"class":447},[42,1466,407],{"class":355},[42,1468,1470,1472,1474,1477,1480,1483,1485,1487,1490,1492],{"class":44,"line":1469},12,[42,1471,517],{"class":447},[42,1473,520],{"class":355},[42,1475,1476],{"class":52},"\"check:\"",[42,1478,1479],{"class":355},", monthly.sum(",[42,1481,1482],{"class":390},"axis",[42,1484,378],{"class":351},[42,1486,145],{"class":447},[42,1488,1489],{"class":355},").round(",[42,1491,168],{"class":447},[42,1493,1494],{"class":355},").to_dict())\n",[10,1496,1497],{},"Every contract's monthly amounts add back up to its value — the check line proves it — so nothing is lost or double-counted by the expansion. The Arden contract earns only 17 days' worth in March, full months in April and May, and 14 days in June. The Dunmore contract runs into 2027, and its months beyond December fall into next year's columns. Daily proration is how straight-line revenue recognition and deferred-income schedules are usually calculated; if your policy uses equal monthly amounts instead of equal daily amounts, count months rather than days.",[75,1499,84,1504,84,1507,84,1510,84,1513,84,1516,84,1522,84,1525,84,1529,84,1534,84,1538,84,1543,84,1547,84,1551,84,1555,84,1558,84,1562,84,1565,84,1569,84,1572,84,1576,84,1579,84,1583,84,1585,84,1589,84,1593,84,1597,84,1601,84,1605,84,1609,84,1614,84,1619,84,1623,84,1628,84,1632,84,1636,84,1641,84,1644,84,1647,84,1651,84,1654,84,1657],{"viewBox":1500,"role":78,"ariaLabelledBy":1501,"xmlns":82,"style":867},"4 0 748 270",[1502,1503],"ex-prorate-t","ex-prorate-d",[86,1505,1506],{"id":1502},"Contract value recognised per month, March to August",[90,1508,1509],{"id":1503},"Stacked columns of monthly amounts from four contracts. March holds only part of Arden's contract; May includes the short Cobalt contract; from June the Dunmore contract adds about 6,000 a month.",[94,1511],{"x":252,"y":97,"width":876,"height":1512,"fill":100},"270",[94,1514],{"x":139,"y":990,"width":1515,"height":1515,"rx":236,"fill":967,"stroke":308,"style":213},"14.0",[115,1517,1521],{"x":1518,"y":1519,"style":1520},"84.0","29.5","font-size:12px;font-weight:600;fill:var(--text,#172033);text-anchor:start","Arden",[94,1523],{"x":1524,"y":990,"width":1515,"height":1515,"rx":236,"fill":211,"stroke":212,"style":213},"149.8",[115,1526,1528],{"x":1527,"y":1519,"style":1520},"169.8","Birch",[94,1530],{"x":1531,"y":990,"width":1515,"height":1515,"rx":236,"fill":1532,"stroke":1533,"style":213},"230.0","#fdefd8","var(--gold,#b4740a)",[115,1535,1537],{"x":1536,"y":1519,"style":1520},"250.0","Cobalt",[94,1539],{"x":1540,"y":990,"width":1515,"height":1515,"rx":236,"fill":1541,"stroke":1542,"style":213},"318.3","#fee8f2","var(--accent,#f43f8f)",[115,1544,1546],{"x":1545,"y":1519,"style":1520},"338.3","Dunmore",[44,1548],{"x1":1549,"y1":1550,"x2":882,"y2":1550,"stroke":108,"style":109},"52.7","232.0",[115,1552,97],{"x":1553,"y":1554,"style":887},"30.3","236.0",[44,1556],{"x1":1549,"y1":1557,"x2":882,"y2":1557,"stroke":108,"style":891},"187.0",[115,1559,1561],{"x":1553,"y":1560,"style":887},"191.0","5k",[44,1563],{"x1":1549,"y1":1564,"x2":882,"y2":1564,"stroke":108,"style":891},"142.0",[115,1566,1568],{"x":1553,"y":1567,"style":887},"146.0","10k",[44,1570],{"x1":1549,"y1":1571,"x2":882,"y2":1571,"stroke":108,"style":891},"97.0",[115,1573,1575],{"x":1553,"y":1574,"style":887},"101.0","15k",[44,1577],{"x1":1549,"y1":1578,"x2":882,"y2":1578,"stroke":108,"style":891},"52.0",[115,1580,1582],{"x":1553,"y":1581,"style":887},"56.0","20k",[44,1584],{"x1":1549,"y1":1550,"x2":882,"y2":1550,"stroke":913,"style":213},[115,1586,1588],{"x":1587,"y":1536,"style":918},"109.6","Mar",[115,1590,1592],{"x":1591,"y":1536,"style":918},"223.5","Apr",[115,1594,1596],{"x":1595,"y":1536,"style":918},"337.4","May",[115,1598,1600],{"x":1599,"y":1536,"style":918},"451.3","Jun",[115,1602,1604],{"x":1603,"y":1536,"style":918},"565.2","Jul",[115,1606,1608],{"x":1607,"y":1536,"style":918},"679.1","Aug",[94,1610],{"x":1611,"y":1612,"width":1613,"height":1553,"rx":236,"fill":967,"stroke":308,"style":213},"80.6","201.7","58.0",[94,1615],{"x":1616,"y":1617,"width":1613,"height":1618,"rx":236,"fill":967,"stroke":308,"style":213},"194.5","178.6","53.4",[94,1620],{"x":1616,"y":1621,"width":1613,"height":1622,"rx":236,"fill":211,"stroke":212,"style":213},"124.6","54.0",[94,1624],{"x":1625,"y":1626,"width":1613,"height":1627,"rx":236,"fill":967,"stroke":308,"style":213},"308.4","176.8","55.2",[94,1629],{"x":1625,"y":1630,"width":1613,"height":1631,"rx":236,"fill":211,"stroke":212,"style":213},"121.0","55.8",[94,1633],{"x":1625,"y":1634,"width":1613,"height":1635,"rx":236,"fill":1532,"stroke":1533,"style":213},"77.8","43.2",[94,1637],{"x":1638,"y":1639,"width":1613,"height":1640,"rx":236,"fill":967,"stroke":308,"style":213},"422.3","207.1","24.9",[94,1642],{"x":1638,"y":1643,"width":1613,"height":1622,"rx":236,"fill":211,"stroke":212,"style":213},"153.1",[94,1645],{"x":1638,"y":1646,"width":1613,"height":1622,"rx":236,"fill":1541,"stroke":1542,"style":213},"99.1",[94,1648],{"x":1649,"y":1650,"width":1613,"height":1631,"rx":236,"fill":211,"stroke":212,"style":213},"536.2","176.2",[94,1652],{"x":1649,"y":1653,"width":1613,"height":1631,"rx":236,"fill":1541,"stroke":1542,"style":213},"120.4",[94,1655],{"x":1656,"y":1650,"width":1613,"height":1631,"rx":236,"fill":211,"stroke":212,"style":213},"650.1",[94,1658],{"x":1656,"y":1653,"width":1613,"height":1631,"rx":236,"fill":1541,"stroke":1542,"style":213},[28,1660,1662],{"id":1661},"step-5-a-faster-expansion-for-large-sheets","Step 5 — A faster expansion for large sheets",[10,1664,1665,1666,1669],{},"Building a Python list of dates per row is fine for thousands of rows. For hundreds of thousands, repeat each row by its length with NumPy and add a day counter, which avoids the per-row ",[14,1667,1668],{},"date_range"," calls:",[33,1671,1673],{"className":342,"code":1672,"language":344,"meta":38,"style":38},"import numpy as np\n\ndef expand_fast(df, start=\"Start\", end=\"End\"):\n    lengths = (df[end] - df[start]).dt.days.to_numpy() + 1\n    rows = df.loc[df.index.repeat(lengths)].copy()\n    offsets = np.arange(lengths.sum()) - np.repeat(np.cumsum(lengths) - lengths, lengths)\n    rows[\"Day\"] = rows[start] + pd.to_timedelta(offsets, unit=\"D\")\n    return rows.reset_index(drop=True)\n\nbig = pd.concat([contracts[[\"Contract\", \"Start\", \"End\", \"Value\"]]] * 5000, ignore_index=True)\nimport time\nt = time.perf_counter()\nfast = expand_fast(big)\nprint(f\"{len(big):,} ranges -> {len(fast):,} day rows in {time.perf_counter() - t:.2f}s\")\n",[14,1674,1675,1687,1691,1717,1736,1746,1766,1794,1812,1816,1860,1867,1877,1888],{"__ignoreMap":38},[42,1676,1677,1679,1682,1684],{"class":44,"line":45},[42,1678,352],{"class":351},[42,1680,1681],{"class":355}," numpy ",[42,1683,359],{"class":351},[42,1685,1686],{"class":355}," np\n",[42,1688,1689],{"class":44,"line":365},[42,1690,369],{"emptyLinePlaceholder":368},[42,1692,1693,1696,1700,1703,1705,1707,1710,1712,1714],{"class":44,"line":372},[42,1694,1695],{"class":351},"def",[42,1697,1699],{"class":1698},"s_Opv"," expand_fast",[42,1701,1702],{"class":355},"(df, start",[42,1704,378],{"class":351},[42,1706,399],{"class":52},[42,1708,1709],{"class":355},", end",[42,1711,378],{"class":351},[42,1713,404],{"class":52},[42,1715,1716],{"class":355},"):\n",[42,1718,1719,1722,1724,1727,1729,1732,1734],{"class":44,"line":410},[42,1720,1721],{"class":355},"    lengths ",[42,1723,378],{"class":351},[42,1725,1726],{"class":355}," (df[end] ",[42,1728,597],{"class":351},[42,1730,1731],{"class":355}," df[start]).dt.days.to_numpy() ",[42,1733,608],{"class":351},[42,1735,1271],{"class":447},[42,1737,1738,1741,1743],{"class":44,"line":464},[42,1739,1740],{"class":355},"    rows ",[42,1742,378],{"class":351},[42,1744,1745],{"class":355}," df.loc[df.index.repeat(lengths)].copy()\n",[42,1747,1748,1751,1753,1756,1758,1761,1763],{"class":44,"line":495},[42,1749,1750],{"class":355},"    offsets ",[42,1752,378],{"class":351},[42,1754,1755],{"class":355}," np.arange(lengths.sum()) ",[42,1757,597],{"class":351},[42,1759,1760],{"class":355}," np.repeat(np.cumsum(lengths) ",[42,1762,597],{"class":351},[42,1764,1765],{"class":355}," lengths, lengths)\n",[42,1767,1768,1771,1773,1775,1777,1780,1782,1785,1788,1790,1792],{"class":44,"line":514},[42,1769,1770],{"class":355},"    rows[",[42,1772,416],{"class":52},[42,1774,419],{"class":355},[42,1776,378],{"class":351},[42,1778,1779],{"class":355}," rows[start] ",[42,1781,608],{"class":351},[42,1783,1784],{"class":355}," pd.to_timedelta(offsets, ",[42,1786,1787],{"class":390},"unit",[42,1789,378],{"class":351},[42,1791,432],{"class":52},[42,1793,542],{"class":355},[42,1795,1796,1799,1802,1805,1807,1810],{"class":44,"line":545},[42,1797,1798],{"class":351},"    return",[42,1800,1801],{"class":355}," rows.reset_index(",[42,1803,1804],{"class":390},"drop",[42,1806,378],{"class":351},[42,1808,1809],{"class":447},"True",[42,1811,542],{"class":355},[42,1813,1814],{"class":44,"line":1398},[42,1815,369],{"emptyLinePlaceholder":368},[42,1817,1818,1821,1823,1826,1828,1830,1832,1834,1836,1838,1840,1843,1846,1849,1851,1854,1856,1858],{"class":44,"line":1447},[42,1819,1820],{"class":355},"big ",[42,1822,378],{"class":351},[42,1824,1825],{"class":355}," pd.concat([contracts[[",[42,1827,1408],{"class":52},[42,1829,387],{"class":355},[42,1831,399],{"class":52},[42,1833,387],{"class":355},[42,1835,404],{"class":52},[42,1837,387],{"class":355},[42,1839,1352],{"class":52},[42,1841,1842],{"class":355},"]]] ",[42,1844,1845],{"class":351},"*",[42,1847,1848],{"class":447}," 5000",[42,1850,387],{"class":355},[42,1852,1853],{"class":390},"ignore_index",[42,1855,378],{"class":351},[42,1857,1809],{"class":447},[42,1859,542],{"class":355},[42,1861,1862,1864],{"class":44,"line":1457},[42,1863,352],{"class":351},[42,1865,1866],{"class":355}," time\n",[42,1868,1869,1872,1874],{"class":44,"line":1469},[42,1870,1871],{"class":355},"t ",[42,1873,378],{"class":351},[42,1875,1876],{"class":355}," time.perf_counter()\n",[42,1878,1880,1883,1885],{"class":44,"line":1879},13,[42,1881,1882],{"class":355},"fast ",[42,1884,378],{"class":351},[42,1886,1887],{"class":355}," expand_fast(big)\n",[42,1889,1891,1893,1895,1898,1900,1903,1905,1908,1911,1914,1917,1919,1921,1924,1926,1928,1931,1933,1936,1938,1941,1944,1946,1949],{"class":44,"line":1890},14,[42,1892,517],{"class":447},[42,1894,520],{"class":355},[42,1896,1897],{"class":351},"f",[42,1899,732],{"class":52},[42,1901,1902],{"class":735},"{",[42,1904,523],{"class":447},[42,1906,1907],{"class":355},"(big)",[42,1909,1910],{"class":351},":,",[42,1912,1913],{"class":735},"}",[42,1915,1916],{"class":52}," ranges -> ",[42,1918,1902],{"class":735},[42,1920,523],{"class":447},[42,1922,1923],{"class":355},"(fast)",[42,1925,1910],{"class":351},[42,1927,1913],{"class":735},[42,1929,1930],{"class":52}," day rows in ",[42,1932,1902],{"class":735},[42,1934,1935],{"class":355},"time.perf_counter() ",[42,1937,597],{"class":351},[42,1939,1940],{"class":355}," t",[42,1942,1943],{"class":351},":.2f",[42,1945,1913],{"class":735},[42,1947,1948],{"class":52},"s\"",[42,1950,542],{"class":355},[10,1952,1953,1956],{},[14,1954,1955],{},"index.repeat(lengths)"," copies each row as many times as it has days, and the offset expression counts 0, 1, 2, … within each block, so the start date plus the offset is each day of the range. Twenty thousand contracts become over three million day rows in about a third of a second here. At that size, ask whether you need the day rows at all — for monthly totals, you can compute each range's overlap with each month directly — but for most reporting sheets, expanding is the clearest route.",[28,1958,1960],{"id":1959},"step-6-write-the-results-to-excel","Step 6 — Write the results to Excel",[10,1962,1963],{},"Put the daily headcount and the monthly recognition schedule into one workbook:",[33,1965,1967],{"className":342,"code":1966,"language":344,"meta":38,"style":38},"with pd.ExcelWriter(\"expanded.xlsx\", engine=\"xlsxwriter\", datetime_format=\"ddd dd mmm\") as xw:\n    per_day_counts = daily.groupby(\"Day\").size().reindex(july, fill_value=0).rename(\"Away\")\n    per_day_counts.to_frame().to_excel(xw, sheet_name=\"Leave per day\", index_label=\"Day\")\n    out = monthly.copy()\n    out.columns = out.columns.astype(str)\n    out.to_excel(xw, sheet_name=\"Recognition\")\n    money = xw.book.add_format({\"num_format\": \"#,##0.00\"})\n    xw.sheets[\"Recognition\"].set_column(1, len(out.columns), 11, money)\nprint(\"written\")\n",[14,1968,1969,2007,2034,2058,2068,2083,2097,2119,2143],{"__ignoreMap":38},[42,1970,1971,1974,1977,1980,1982,1985,1987,1990,1992,1995,1997,2000,2002,2004],{"class":44,"line":45},[42,1972,1973],{"class":351},"with",[42,1975,1976],{"class":355}," pd.ExcelWriter(",[42,1978,1979],{"class":52},"\"expanded.xlsx\"",[42,1981,387],{"class":355},[42,1983,1984],{"class":390},"engine",[42,1986,378],{"class":351},[42,1988,1989],{"class":52},"\"xlsxwriter\"",[42,1991,387],{"class":355},[42,1993,1994],{"class":390},"datetime_format",[42,1996,378],{"class":351},[42,1998,1999],{"class":52},"\"ddd dd mmm\"",[42,2001,435],{"class":355},[42,2003,359],{"class":351},[42,2005,2006],{"class":355}," xw:\n",[42,2008,2009,2012,2014,2016,2018,2020,2022,2024,2026,2029,2032],{"class":44,"line":365},[42,2010,2011],{"class":355},"    per_day_counts ",[42,2013,378],{"class":351},[42,2015,690],{"class":355},[42,2017,416],{"class":52},[42,2019,695],{"class":355},[42,2021,698],{"class":390},[42,2023,378],{"class":351},[42,2025,97],{"class":447},[42,2027,2028],{"class":355},").rename(",[42,2030,2031],{"class":52},"\"Away\"",[42,2033,542],{"class":355},[42,2035,2036,2039,2042,2044,2047,2049,2052,2054,2056],{"class":44,"line":372},[42,2037,2038],{"class":355},"    per_day_counts.to_frame().to_excel(xw, ",[42,2040,2041],{"class":390},"sheet_name",[42,2043,378],{"class":351},[42,2045,2046],{"class":52},"\"Leave per day\"",[42,2048,387],{"class":355},[42,2050,2051],{"class":390},"index_label",[42,2053,378],{"class":351},[42,2055,416],{"class":52},[42,2057,542],{"class":355},[42,2059,2060,2063,2065],{"class":44,"line":410},[42,2061,2062],{"class":355},"    out ",[42,2064,378],{"class":351},[42,2066,2067],{"class":355}," monthly.copy()\n",[42,2069,2070,2073,2075,2078,2081],{"class":44,"line":464},[42,2071,2072],{"class":355},"    out.columns ",[42,2074,378],{"class":351},[42,2076,2077],{"class":355}," out.columns.astype(",[42,2079,2080],{"class":447},"str",[42,2082,542],{"class":355},[42,2084,2085,2088,2090,2092,2095],{"class":44,"line":495},[42,2086,2087],{"class":355},"    out.to_excel(xw, ",[42,2089,2041],{"class":390},[42,2091,378],{"class":351},[42,2093,2094],{"class":52},"\"Recognition\"",[42,2096,542],{"class":355},[42,2098,2099,2102,2104,2107,2110,2113,2116],{"class":44,"line":514},[42,2100,2101],{"class":355},"    money ",[42,2103,378],{"class":351},[42,2105,2106],{"class":355}," xw.book.add_format({",[42,2108,2109],{"class":52},"\"num_format\"",[42,2111,2112],{"class":355},": ",[42,2114,2115],{"class":52},"\"#,##0.00\"",[42,2117,2118],{"class":355},"})\n",[42,2120,2121,2124,2126,2129,2131,2133,2135,2138,2140],{"class":44,"line":545},[42,2122,2123],{"class":355},"    xw.sheets[",[42,2125,2094],{"class":52},[42,2127,2128],{"class":355},"].set_column(",[42,2130,145],{"class":447},[42,2132,387],{"class":355},[42,2134,523],{"class":447},[42,2136,2137],{"class":355},"(out.columns), ",[42,2139,321],{"class":447},[42,2141,2142],{"class":355},", money)\n",[42,2144,2145,2147,2149,2152],{"class":44,"line":1398},[42,2146,517],{"class":447},[42,2148,520],{"class":355},[42,2150,2151],{"class":52},"\"written\"",[42,2153,542],{"class":355},[28,2155,2157],{"id":2156},"when-not-to-expand","When not to expand",[10,2159,2160,2161,2164,2165,2168],{},"Expanding is the most readable approach, but it is not the only one. For monthly totals over long ranges — ten-year leases, multi-year service contracts — the overlap of each range with each month can be computed directly: the number of days in ",[14,2162,2163],{},"max(start, month start)"," to ",[14,2166,2167],{},"min(end, month end)",", times the daily rate. That produces one row per contract per month instead of one per day, which matters when there are millions of ranges. For \"how many are active on each date\", a running sum of +1 at each start and −1 on the day after each end gives the same daily counts without materialising the day rows. Both are faster and both are easier to get subtly wrong; expand first, and keep the expanded version as a test for any optimised replacement.",[28,2170,2172],{"id":2171},"common-pitfalls","Common pitfalls",[2174,2175,2176,2188,2205,2214,2224],"ul",{},[2177,2178,2179,2183,2184,2187],"li",{},[2180,2181,2182],"strong",{},"Exclusive end dates."," ",[14,2185,2186],{},"date_range(start, end)"," includes the end; subtract a day first if the end date is exclusive, such as a check-out date.",[2177,2189,2190,2193,2194,2197,2198,2201,2202,26],{},[2180,2191,2192],{},"Forgetting to convert after explode."," The exploded column is ",[14,2195,2196],{},"object","; wrap it in ",[14,2199,2200],{},"pd.to_datetime"," before using ",[14,2203,2204],{},".dt",[2177,2206,2207,2210,2211,2213],{},[2180,2208,2209],{},"Empty ranges."," A weekend-only range with business days, or a reversed range, explodes to ",[14,2212,1188],{}," rows; drop them and report reversed ranges.",[2177,2215,2216,2219,2220,2223],{},[2180,2217,2218],{},"Counting rows instead of people."," Two overlapping requests from one person make two rows for the same day; use ",[14,2221,2222],{},"nunique"," on the person if that matters.",[2177,2225,2226,2229,2230,2233],{},[2180,2227,2228],{},"Memory."," Long ranges times many rows grow quickly; estimate ",[14,2231,2232],{},"sum of lengths"," before expanding.",[28,2235,2237],{"id":2236},"conclusion","Conclusion",[10,2239,2240,2241,2244,2245,2247],{},"Build each row's list of days with ",[14,2242,2243],{},"pd.date_range"," — daily, business-day or a custom calendar with holidays — and ",[14,2246,338],{}," it into one row per day, checking that the row count equals the total length of the ranges. Group by day for headcounts and occupancy, give each day an equal share of a value to prorate it across months, and switch to a NumPy repeat when the sheet is large.",[28,2249,2251],{"id":2250},"frequently-asked-questions","Frequently asked questions",[10,2253,2254,2257],{},[2180,2255,2256],{},"How do I create one row per day between a start and end date in pandas?","\nAdd a column with pd.date_range(start, end) for each row and call explode on it. Each day becomes its own row with the other columns copied; convert the new column back with pd.to_datetime.",[10,2259,2260,2263],{},[2180,2261,2262],{},"How do I expand only business days?","\nUse pd.date_range with freq=\"B\" for weekdays, or with a CustomBusinessDay that lists your holidays. Drop the NaN rows that ranges containing no working days produce after explode.",[10,2265,2266,2269],{},[2180,2267,2268],{},"How do I split a contract value across months?","\nExpand each contract into days, give each day the value divided by the contract's length in days, and sum the shares by month with a pivot table. Check that the months add back up to the total value.",[10,2271,2272,2275,2276,2279],{},[2180,2273,2274],{},"Is there a faster way than explode for large data?","\nYes: repeat each row by its length with df.loc",[42,2277,2278],{},"df.index.repeat(lengths)"," and add a within-range day counter built with NumPy. It avoids calling date_range once per row.",[28,2281,2283],{"id":2282},"related","Related",[2174,2285,2286,2292,2299,2306],{},[2177,2287,2288,2289,2291],{},"Up one level: ",[22,2290,25],{"href":24}," — parsing, grouping and date arithmetic.",[2177,2293,2294,2298],{},[22,2295,2297],{"href":2296},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffill-missing-dates-in-a-time-series-with-pandas\u002F","Fill Missing Dates in a Time Series with pandas"," — the reindex step that adds zero days.",[2177,2300,2301,2305],{},[22,2302,2304],{"href":2303},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fgroup-excel-rows-by-month-and-quarter-with-pandas\u002F","Group Excel Rows by Month and Quarter with pandas"," — monthly totals from daily rows.",[2177,2307,2308,2312],{},[22,2309,2311],{"href":2310},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-cash-flow-forecast-report\u002F","Build a Cash Flow Forecast Report"," — spreading amounts over future periods.",[2314,2315,2316],"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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}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}",{"title":38,"searchDepth":365,"depth":365,"links":2318},[2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330],{"id":30,"depth":365,"text":31},{"id":331,"depth":365,"text":332},{"id":651,"depth":365,"text":652},{"id":1033,"depth":365,"text":1034},{"id":1201,"depth":365,"text":1202},{"id":1661,"depth":365,"text":1662},{"id":1959,"depth":365,"text":1960},{"id":2156,"depth":365,"text":2157},{"id":2171,"depth":365,"text":2172},{"id":2236,"depth":365,"text":2237},{"id":2250,"depth":365,"text":2251},{"id":2282,"depth":365,"text":2283},"2026-09-29","Turn rows with a start and an end date into one row per day — or per working day — to count how many people are away on each date, spread a contract's value across the months it covers, and summarise by month. With explode, a vectorised repeat for large sheets, business-day calendars and a check that nothing was lost.","md",[2335,2337,2339,2341],{"q":2256,"a":2336},"Add a column with pd.date_range(start, end) for each row and call explode on it. Each day becomes its own row with the other columns copied; convert the new column back with pd.to_datetime.",{"q":2262,"a":2338},"Use pd.date_range with freq=\"B\" for weekdays, or with a CustomBusinessDay that lists your holidays. Drop the NaN rows that ranges containing no working days produce after explode.",{"q":2268,"a":2340},"Expand each contract into days, give each day the value divided by the contract's length in days, and sum the shares by month with a pivot table. Check that the months add back up to the total value.",{"q":2274,"a":2342},"Yes: repeat each row by its length with df.loc[df.index.repeat(lengths)] and add a within-range day counter built with NumPy. It avoids calling date_range once per row.","expand date ranges into one row per day with pandas",null,{"breadcrumb":2346},[2347,2349,2352],{"name":2348,"item":1357},"Home",{"name":2350,"item":2351},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":25,"item":24},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas",{"title":2355,"description":2356},"Expand Start and End Dates into Daily Rows in pandas","Expand date ranges to one row per day with pandas: date_range plus explode, a fast np.repeat version, business days and holidays with bdate_range, daily headcount from leave requests, and prorating contract value across months.","expand-date-ranges-into-one-row-per-day-with-pandas","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fexpand-date-ranges-into-one-row-per-day-with-pandas\u002Findex",[2360,2361],"dates-and-times","pandas","how-to","_KN15lDu6r3DEOjwETUFL_L2FTs3HQmk3zSfq27Ouic",[2365,2369],{"title":2366,"path":2367,"stem":2368,"children":-1},"Create a Shift Calendar with Rotating Patterns","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcreate-a-shift-calendar-with-rotating-patterns","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcreate-a-shift-calendar-with-rotating-patterns\u002Findex",{"title":2370,"path":2371,"stem":2372,"children":-1},"Fill Missing Dates in a Time Series from Excel with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffill-missing-dates-in-a-time-series-with-pandas","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Ffill-missing-dates-in-a-time-series-with-pandas\u002Findex",[2374,2376],{"path":2375,"title":2350},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2377,"title":25},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data",[],[2380,2383,2386,2389,2392,2395],{"path":2381,"title":2382,"kind":2362},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-overdue-dates-with-openpyxl","Highlight Overdue Dates in Excel with openpyxl",{"path":2384,"title":2385,"kind":2362},"\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":2387,"title":2388,"kind":2362},"\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":2390,"title":2391,"kind":2362},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-moving-averages-with-pandas-rolling","Calculate Moving Averages with pandas rolling",{"path":2393,"title":2394,"kind":2362},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Feomonth-and-edate-equivalents-in-pandas","EOMONTH and EDATE Equivalents in pandas",{"path":2396,"title":2397,"kind":2362},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fyearfrac-and-days360-equivalents-in-python","YEARFRAC and DAYS360 Equivalents in Python",1790972106165]