[{"data":1,"prerenderedAt":2049},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month":2015,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month":2024,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month":2029,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month":2030},{"id":4,"title":5,"body":6,"dateModified":1981,"datePublished":1981,"description":1982,"extension":1983,"faq":1984,"keyword":1993,"kind":1994,"meta":1995,"navigation":108,"path":2004,"seo":2005,"slug":2008,"stem":2009,"topics":2010,"type":2013,"__hash__":2014},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month\u002Findex.md","Calculate the Nth Weekday of a Month",{"type":7,"value":8,"toc":1969},"minimark",[9,36,41,73,76,80,268,297,519,523,888,903,907,1227,1298,1324,1394,1398,1567,1574,1578,1589,1719,1734,1822,1826,1867,1871,1892,1896,1905,1913,1926,1932,1936,1965],[10,11,12,13,17,18,21,22,25,26,29,30,35],"p",{},"Many recurring dates are defined by weekday rather than by day number: the board meets on the ",[14,15,16],"em",{},"second Tuesday"," of the month, payroll runs on the ",[14,19,20],{},"last Friday",", a report goes out on the ",[14,23,24],{},"first Monday",", and some public holidays fall on the ",[14,27,28],{},"fourth Thursday"," of November. Calendars, schedules and reminders built in Excel need these dates for every month of a year, and working them out by hand is tedious and easy to get wrong in months that start late in the week. pandas has frequencies built exactly for this, and Excel can compute them with a short formula. This page generates the second Tuesday and the last Friday of every month in 2026 with pandas, writes a single-date function for use anywhere, puts the matching Excel formula into a sheet and checks it against Python, and moves dates that fall on a public holiday. It belongs to ",[31,32,34],"a",{"href":33},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002F","Working with Dates and Times in Excel Data",".",[37,38,40],"h2",{"id":39},"prerequisites","Prerequisites",[42,43,48],"pre",{"className":44,"code":45,"language":46,"meta":47,"style":47},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl holidays\n","bash","",[49,50,51],"code",{"__ignoreMap":47},[52,53,56,60,64,67,70],"span",{"class":54,"line":55},"line",1,[52,57,59],{"class":58},"sMTad","pip",[52,61,63],{"class":62},"srMev"," install",[52,65,66],{"class":62}," pandas",[52,68,69],{"class":62}," openpyxl",[52,71,72],{"class":62}," holidays\n",[10,74,75],{},"LibreOffice is used to recalculate the Excel formulas for the comparison; the formulas themselves work in Excel as written.",[37,77,79],{"id":78},"step-1-every-second-tuesday-and-last-friday-of-a-year","Step 1 — Every second Tuesday and last Friday of a year",[42,81,85],{"className":82,"code":83,"language":84,"meta":47,"style":47},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nsecond_tuesday = pd.date_range(\"2026-01-01\", \"2026-12-31\", freq=\"WOM-2TUE\")\nlast_friday = pd.date_range(\"2026-01-01\", \"2026-12-31\", freq=\"LWOM-FRI\")\n\nmeetings = pd.DataFrame({\"Month\": second_tuesday.strftime(\"%b %Y\"),\n                         \"Second Tuesday\": second_tuesday.strftime(\"%a %d\"),\n                         \"Last Friday\": last_friday.strftime(\"%a %d\")})\nprint(meetings.to_string(index=False))\n","python",[49,86,87,103,110,145,172,177,207,227,247],{"__ignoreMap":47},[52,88,89,93,97,100],{"class":54,"line":55},[52,90,92],{"class":91},"s-kum","import",[52,94,96],{"class":95},"skGVy"," pandas ",[52,98,99],{"class":91},"as",[52,101,102],{"class":95}," pd\n",[52,104,106],{"class":54,"line":105},2,[52,107,109],{"emptyLinePlaceholder":108},true,"\n",[52,111,113,116,119,122,125,128,131,133,137,139,142],{"class":54,"line":112},3,[52,114,115],{"class":95},"second_tuesday ",[52,117,118],{"class":91},"=",[52,120,121],{"class":95}," pd.date_range(",[52,123,124],{"class":62},"\"2026-01-01\"",[52,126,127],{"class":95},", ",[52,129,130],{"class":62},"\"2026-12-31\"",[52,132,127],{"class":95},[52,134,136],{"class":135},"sa561","freq",[52,138,118],{"class":91},[52,140,141],{"class":62},"\"WOM-2TUE\"",[52,143,144],{"class":95},")\n",[52,146,148,151,153,155,157,159,161,163,165,167,170],{"class":54,"line":147},4,[52,149,150],{"class":95},"last_friday ",[52,152,118],{"class":91},[52,154,121],{"class":95},[52,156,124],{"class":62},[52,158,127],{"class":95},[52,160,130],{"class":62},[52,162,127],{"class":95},[52,164,136],{"class":135},[52,166,118],{"class":91},[52,168,169],{"class":62},"\"LWOM-FRI\"",[52,171,144],{"class":95},[52,173,175],{"class":54,"line":174},5,[52,176,109],{"emptyLinePlaceholder":108},[52,178,180,183,185,188,191,194,197,201,204],{"class":54,"line":179},6,[52,181,182],{"class":95},"meetings ",[52,184,118],{"class":91},[52,186,187],{"class":95}," pd.DataFrame({",[52,189,190],{"class":62},"\"Month\"",[52,192,193],{"class":95},": second_tuesday.strftime(",[52,195,196],{"class":62},"\"",[52,198,200],{"class":199},"sSjpA","%b",[52,202,203],{"class":62}," %Y\"",[52,205,206],{"class":95},"),\n",[52,208,210,213,215,217,220,223,225],{"class":54,"line":209},7,[52,211,212],{"class":62},"                         \"Second Tuesday\"",[52,214,193],{"class":95},[52,216,196],{"class":62},[52,218,219],{"class":199},"%a",[52,221,222],{"class":199}," %d",[52,224,196],{"class":62},[52,226,206],{"class":95},[52,228,230,233,236,238,240,242,244],{"class":54,"line":229},8,[52,231,232],{"class":62},"                         \"Last Friday\"",[52,234,235],{"class":95},": last_friday.strftime(",[52,237,196],{"class":62},[52,239,219],{"class":199},[52,241,222],{"class":199},[52,243,196],{"class":62},[52,245,246],{"class":95},")})\n",[52,248,250,254,257,260,262,265],{"class":54,"line":249},9,[52,251,253],{"class":252},"sP0c6","print",[52,255,256],{"class":95},"(meetings.to_string(",[52,258,259],{"class":135},"index",[52,261,118],{"class":91},[52,263,264],{"class":252},"False",[52,266,267],{"class":95},"))\n",[10,269,270,273,274,277,278,281,282,285,286,289,290,277,293,296],{},[49,271,272],{},"date_range"," accepts frequencies that describe exactly these rules. ",[49,275,276],{},"WOM-2TUE"," means ",[14,279,280],{},"week of month: the second Tuesday","; the number can be 1 to 4 and the day any of ",[49,283,284],{},"MON"," to ",[49,287,288],{},"SUN",". ",[49,291,292],{},"LWOM-FRI",[14,294,295],{},"last week of month: the last Friday",". Each produces one date per month between the start and end dates, so a whole year's schedule is one line. The results move around as expected: the second Tuesday falls anywhere from the 8th to the 14th, and the last Friday from the 25th to the 31st, depending on which weekday the month starts on.",[298,299,307,308,307,312,307,316,307,324,307,333,307,337,307,344,307,348,307,352,307,356,307,360,307,364,307,369,307,374,307,378,307,380,307,383,307,385,307,388,307,391,307,395,307,397,307,401,307,403,307,406,307,408,307,411,307,414,307,418,307,420,307,423,307,425,307,428,307,430,307,433,307,436,307,440,307,442,307,445,307,447,307,449,307,451,307,453,307,456,307,460,307,462,307,465,307,467,307,470,307,472,307,475,307,478,307,482,307,484,307,487,307,489,307,492,307,494,307,497,307,500,307,504,307,506,307,509,307,511,307,514,307,516],"svg",{"viewBox":300,"role":301,"ariaLabelledBy":302,"xmlns":305,"style":306},"195 0 370 252","img",[303,304],"nth-2026-t","nth-2026-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:370px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[309,310,311],"title",{"id":303},"Second Tuesday and last Friday, first half of 2026",[313,314,315],"desc",{"id":304},"In 2026 the second Tuesday falls on 13 January, 10 February, 10 March, 14 April, 12 May and 9 June. The last Friday falls on 30 January, 27 February, 27 March, 24 April, 29 May and 26 June.",[317,318],"rect",{"x":319,"y":320,"width":321,"height":322,"fill":323},"195","0","370","252","#ffffff",[317,325],{"x":326,"y":327,"width":328,"height":329,"rx":320,"fill":330,"stroke":331,"style":332},"211.3","16.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[317,334],{"x":335,"y":327,"width":336,"height":329,"rx":320,"fill":330,"stroke":331,"style":332},"243.3","86.2",[338,339,343],"text",{"x":340,"y":341,"style":342},"286.4","33.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[317,345],{"x":346,"y":327,"width":347,"height":329,"rx":320,"fill":330,"stroke":331,"style":332},"329.5","127.3",[338,349,351],{"x":350,"y":341,"style":342},"393.2","B",[317,353],{"x":354,"y":327,"width":355,"height":329,"rx":320,"fill":330,"stroke":331,"style":332},"456.8","91.9",[338,357,359],{"x":358,"y":341,"style":342},"502.8","C",[317,361],{"x":326,"y":362,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"40.0","28.0",[338,365,368],{"x":366,"y":367,"style":342},"227.3","59.0","1",[317,370],{"x":335,"y":362,"width":336,"height":363,"rx":320,"fill":371,"stroke":372,"style":373},"#f0f4ff","var(--brand,#5b5cf0)","stroke-width:1.5px",[338,375,377],{"x":340,"y":367,"style":376},"font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Month",[317,379],{"x":346,"y":362,"width":347,"height":363,"rx":320,"fill":371,"stroke":372,"style":373},[338,381,382],{"x":350,"y":367,"style":376},"Second Tuesday",[317,384],{"x":354,"y":362,"width":355,"height":363,"rx":320,"fill":371,"stroke":372,"style":373},[338,386,387],{"x":358,"y":367,"style":376},"Last Friday",[317,389],{"x":326,"y":390,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"68.0",[338,392,394],{"x":366,"y":393,"style":342},"87.0","2",[317,396],{"x":335,"y":390,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,398,400],{"x":340,"y":393,"style":399},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","Jan 2026",[317,402],{"x":346,"y":390,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,404,405],{"x":350,"y":393,"style":399},"Tue 13",[317,407],{"x":354,"y":390,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,409,410],{"x":358,"y":393,"style":399},"Fri 30",[317,412],{"x":326,"y":413,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"96.0",[338,415,417],{"x":366,"y":416,"style":342},"115.0","3",[317,419],{"x":335,"y":413,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,421,422],{"x":340,"y":416,"style":399},"Feb 2026",[317,424],{"x":346,"y":413,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,426,427],{"x":350,"y":416,"style":399},"Tue 10",[317,429],{"x":354,"y":413,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,431,432],{"x":358,"y":416,"style":399},"Fri 27",[317,434],{"x":326,"y":435,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"124.0",[338,437,439],{"x":366,"y":438,"style":342},"143.0","4",[317,441],{"x":335,"y":435,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,443,444],{"x":340,"y":438,"style":399},"Mar 2026",[317,446],{"x":346,"y":435,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,448,427],{"x":350,"y":438,"style":399},[317,450],{"x":354,"y":435,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,452,432],{"x":358,"y":438,"style":399},[317,454],{"x":326,"y":455,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"152.0",[338,457,459],{"x":366,"y":458,"style":342},"171.0","5",[317,461],{"x":335,"y":455,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,463,464],{"x":340,"y":458,"style":399},"Apr 2026",[317,466],{"x":346,"y":455,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,468,469],{"x":350,"y":458,"style":399},"Tue 14",[317,471],{"x":354,"y":455,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,473,474],{"x":358,"y":458,"style":399},"Fri 24",[317,476],{"x":326,"y":477,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"180.0",[338,479,481],{"x":366,"y":480,"style":342},"199.0","6",[317,483],{"x":335,"y":477,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,485,486],{"x":340,"y":480,"style":399},"May 2026",[317,488],{"x":346,"y":477,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,490,491],{"x":350,"y":480,"style":399},"Tue 12",[317,493],{"x":354,"y":477,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,495,496],{"x":358,"y":480,"style":399},"Fri 29",[317,498],{"x":326,"y":499,"width":328,"height":363,"rx":320,"fill":330,"stroke":331,"style":332},"208.0",[338,501,503],{"x":366,"y":502,"style":342},"227.0","7",[317,505],{"x":335,"y":499,"width":336,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,507,508],{"x":340,"y":502,"style":399},"Jun 2026",[317,510],{"x":346,"y":499,"width":347,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,512,513],{"x":350,"y":502,"style":399},"Tue 09",[317,515],{"x":354,"y":499,"width":355,"height":363,"rx":320,"fill":323,"stroke":331,"style":332},[338,517,518],{"x":358,"y":502,"style":399},"Fri 26",[37,520,522],{"id":521},"step-2-a-function-for-one-date-and-the-fifth-weekday-question","Step 2 — A function for one date, and the fifth-weekday question",[42,524,526],{"className":82,"code":525,"language":84,"meta":47,"style":47},"from datetime import date, timedelta\n\ndef nth_weekday(year, month, weekday, n):\n    \"\"\"n-th weekday (Mon=0 … Sun=6) of a month; n = -1 for the last. None if the month has no such day.\"\"\"\n    if n > 0:\n        first = date(year, month, 1)\n        d = first + timedelta(days=(weekday - first.weekday()) % 7 + 7 * (n - 1))\n        return d if d.month == month else None\n    nxt = date(year + month \u002F\u002F 12, month % 12 + 1, 1)\n    last = nxt - timedelta(days=1)\n    return last - timedelta(days=(last.weekday() - weekday) % 7)\n\nprint(nth_weekday(2026, 11, 3, 4), \"— fourth Thursday of November\")\nprint(nth_weekday(2026, 10, 4, 5), \"— fifth Friday of October\")\nprint(nth_weekday(2026, 2, 0, 5), \"— fifth Monday of February\")\nprint(nth_weekday(2026, 2, 4, -1), \"— last Friday of February\")\n",[49,527,528,541,545,557,562,579,593,647,673,710,733,764,769,801,830,858],{"__ignoreMap":47},[52,529,530,533,536,538],{"class":54,"line":55},[52,531,532],{"class":91},"from",[52,534,535],{"class":95}," datetime ",[52,537,92],{"class":91},[52,539,540],{"class":95}," date, timedelta\n",[52,542,543],{"class":54,"line":105},[52,544,109],{"emptyLinePlaceholder":108},[52,546,547,550,554],{"class":54,"line":112},[52,548,549],{"class":91},"def",[52,551,553],{"class":552},"s_Opv"," nth_weekday",[52,555,556],{"class":95},"(year, month, weekday, n):\n",[52,558,559],{"class":54,"line":147},[52,560,561],{"class":62},"    \"\"\"n-th weekday (Mon=0 … Sun=6) of a month; n = -1 for the last. None if the month has no such day.\"\"\"\n",[52,563,564,567,570,573,576],{"class":54,"line":174},[52,565,566],{"class":91},"    if",[52,568,569],{"class":95}," n ",[52,571,572],{"class":91},">",[52,574,575],{"class":252}," 0",[52,577,578],{"class":95},":\n",[52,580,581,584,586,589,591],{"class":54,"line":179},[52,582,583],{"class":95},"        first ",[52,585,118],{"class":91},[52,587,588],{"class":95}," date(year, month, ",[52,590,368],{"class":252},[52,592,144],{"class":95},[52,594,595,598,600,603,606,609,612,614,617,620,623,626,629,632,634,637,640,642,645],{"class":54,"line":209},[52,596,597],{"class":95},"        d ",[52,599,118],{"class":91},[52,601,602],{"class":95}," first ",[52,604,605],{"class":91},"+",[52,607,608],{"class":95}," timedelta(",[52,610,611],{"class":135},"days",[52,613,118],{"class":91},[52,615,616],{"class":95},"(weekday ",[52,618,619],{"class":91},"-",[52,621,622],{"class":95}," first.weekday()) ",[52,624,625],{"class":91},"%",[52,627,628],{"class":252}," 7",[52,630,631],{"class":91}," +",[52,633,628],{"class":252},[52,635,636],{"class":91}," *",[52,638,639],{"class":95}," (n ",[52,641,619],{"class":91},[52,643,644],{"class":252}," 1",[52,646,267],{"class":95},[52,648,649,652,655,658,661,664,667,670],{"class":54,"line":229},[52,650,651],{"class":91},"        return",[52,653,654],{"class":95}," d ",[52,656,657],{"class":91},"if",[52,659,660],{"class":95}," d.month ",[52,662,663],{"class":91},"==",[52,665,666],{"class":95}," month ",[52,668,669],{"class":91},"else",[52,671,672],{"class":252}," None\n",[52,674,675,678,680,683,685,687,690,693,696,698,700,702,704,706,708],{"class":54,"line":249},[52,676,677],{"class":95},"    nxt ",[52,679,118],{"class":91},[52,681,682],{"class":95}," date(year ",[52,684,605],{"class":91},[52,686,666],{"class":95},[52,688,689],{"class":91},"\u002F\u002F",[52,691,692],{"class":252}," 12",[52,694,695],{"class":95},", month ",[52,697,625],{"class":91},[52,699,692],{"class":252},[52,701,631],{"class":91},[52,703,644],{"class":252},[52,705,127],{"class":95},[52,707,368],{"class":252},[52,709,144],{"class":95},[52,711,713,716,718,721,723,725,727,729,731],{"class":54,"line":712},10,[52,714,715],{"class":95},"    last ",[52,717,118],{"class":91},[52,719,720],{"class":95}," nxt ",[52,722,619],{"class":91},[52,724,608],{"class":95},[52,726,611],{"class":135},[52,728,118],{"class":91},[52,730,368],{"class":252},[52,732,144],{"class":95},[52,734,736,739,742,744,746,748,750,753,755,758,760,762],{"class":54,"line":735},11,[52,737,738],{"class":91},"    return",[52,740,741],{"class":95}," last ",[52,743,619],{"class":91},[52,745,608],{"class":95},[52,747,611],{"class":135},[52,749,118],{"class":91},[52,751,752],{"class":95},"(last.weekday() ",[52,754,619],{"class":91},[52,756,757],{"class":95}," weekday) ",[52,759,625],{"class":91},[52,761,628],{"class":252},[52,763,144],{"class":95},[52,765,767],{"class":54,"line":766},12,[52,768,109],{"emptyLinePlaceholder":108},[52,770,772,774,777,780,782,785,787,789,791,793,796,799],{"class":54,"line":771},13,[52,773,253],{"class":252},[52,775,776],{"class":95},"(nth_weekday(",[52,778,779],{"class":252},"2026",[52,781,127],{"class":95},[52,783,784],{"class":252},"11",[52,786,127],{"class":95},[52,788,417],{"class":252},[52,790,127],{"class":95},[52,792,439],{"class":252},[52,794,795],{"class":95},"), ",[52,797,798],{"class":62},"\"— fourth Thursday of November\"",[52,800,144],{"class":95},[52,802,804,806,808,810,812,815,817,819,821,823,825,828],{"class":54,"line":803},14,[52,805,253],{"class":252},[52,807,776],{"class":95},[52,809,779],{"class":252},[52,811,127],{"class":95},[52,813,814],{"class":252},"10",[52,816,127],{"class":95},[52,818,439],{"class":252},[52,820,127],{"class":95},[52,822,459],{"class":252},[52,824,795],{"class":95},[52,826,827],{"class":62},"\"— fifth Friday of October\"",[52,829,144],{"class":95},[52,831,833,835,837,839,841,843,845,847,849,851,853,856],{"class":54,"line":832},15,[52,834,253],{"class":252},[52,836,776],{"class":95},[52,838,779],{"class":252},[52,840,127],{"class":95},[52,842,394],{"class":252},[52,844,127],{"class":95},[52,846,320],{"class":252},[52,848,127],{"class":95},[52,850,459],{"class":252},[52,852,795],{"class":95},[52,854,855],{"class":62},"\"— fifth Monday of February\"",[52,857,144],{"class":95},[52,859,861,863,865,867,869,871,873,875,877,879,881,883,886],{"class":54,"line":860},16,[52,862,253],{"class":252},[52,864,776],{"class":95},[52,866,779],{"class":252},[52,868,127],{"class":95},[52,870,394],{"class":252},[52,872,127],{"class":95},[52,874,439],{"class":252},[52,876,127],{"class":95},[52,878,619],{"class":91},[52,880,368],{"class":252},[52,882,795],{"class":95},[52,884,885],{"class":62},"\"— last Friday of February\"",[52,887,144],{"class":95},[10,889,890,891,894,895,898,899,902],{},"Outside pandas, or for a single date, the arithmetic is short. The first occurrence of a weekday is the first of the month plus however many days it takes to reach that weekday, modulo seven; each later occurrence adds a week. The last occurrence works backwards from the month's last day. The function returns ",[49,892,893],{},"None"," when the month does not have the requested occurrence — not every month has a fifth Monday — which matters for rules like ",[14,896,897],{},"the fifth Friday",", used for occasional extra meetings or pay runs. October 2026 has one, on the 30th; February 2026, with exactly four weeks, has no fifth weekday of any kind. pandas' ",[49,900,901],{},"WOM"," frequencies stop at the fourth occurrence for that reason, so fifth-weekday rules need the function.",[37,904,906],{"id":905},"step-3-the-same-in-excel-checked-against-python","Step 3 — The same in Excel, checked against Python",[42,908,910],{"className":82,"code":909,"language":84,"meta":47,"style":47},"from openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.title = \"Schedule\"\nws.append([\"Year\", \"Month\", \"Weekday (1=Sun … 7=Sat)\", \"N\", \"Date\", \"Python\"])\ncases = [(2026, m, 3, 2) for m in range(1, 13)]            # second Tuesday: Excel WEEKDAY numbers Tuesday as 3\nfor i, (y, m, wd, n) in enumerate(cases, start=2):\n    ws.append([y, m, wd, n,\n               f\"=DATE(A{i},B{i},1)+MOD(C{i}-WEEKDAY(DATE(A{i},B{i},1)),7)+7*(D{i}-1)\",\n               nth_weekday(y, m, 1, n)])\n    ws.cell(i, 5).number_format = ws.cell(i, 6).number_format = \"ddd dd mmm yyyy\"\nws[\"H1\"], ws[\"H2\"] = \"Last Friday of the month in B2\", \"=EOMONTH(DATE(A2,B2,1),0)-MOD(WEEKDAY(EOMONTH(DATE(A2,B2,1),0))-6,7)\"\nws[\"H2\"].number_format = \"ddd dd mmm yyyy\"\nwb.save(\"nth_weekday.xlsx\")\n",[49,911,912,924,928,938,948,958,993,1046,1071,1076,1143,1153,1177,1204,1217],{"__ignoreMap":47},[52,913,914,916,919,921],{"class":54,"line":55},[52,915,532],{"class":91},[52,917,918],{"class":95}," openpyxl ",[52,920,92],{"class":91},[52,922,923],{"class":95}," Workbook\n",[52,925,926],{"class":54,"line":105},[52,927,109],{"emptyLinePlaceholder":108},[52,929,930,933,935],{"class":54,"line":112},[52,931,932],{"class":95},"wb ",[52,934,118],{"class":91},[52,936,937],{"class":95}," Workbook()\n",[52,939,940,943,945],{"class":54,"line":147},[52,941,942],{"class":95},"ws ",[52,944,118],{"class":91},[52,946,947],{"class":95}," wb.active\n",[52,949,950,953,955],{"class":54,"line":174},[52,951,952],{"class":95},"ws.title ",[52,954,118],{"class":91},[52,956,957],{"class":62}," \"Schedule\"\n",[52,959,960,963,966,968,970,972,975,977,980,982,985,987,990],{"class":54,"line":179},[52,961,962],{"class":95},"ws.append([",[52,964,965],{"class":62},"\"Year\"",[52,967,127],{"class":95},[52,969,190],{"class":62},[52,971,127],{"class":95},[52,973,974],{"class":62},"\"Weekday (1=Sun … 7=Sat)\"",[52,976,127],{"class":95},[52,978,979],{"class":62},"\"N\"",[52,981,127],{"class":95},[52,983,984],{"class":62},"\"Date\"",[52,986,127],{"class":95},[52,988,989],{"class":62},"\"Python\"",[52,991,992],{"class":95},"])\n",[52,994,995,998,1000,1003,1005,1008,1010,1012,1014,1017,1020,1023,1026,1029,1032,1034,1036,1039,1042],{"class":54,"line":209},[52,996,997],{"class":95},"cases ",[52,999,118],{"class":91},[52,1001,1002],{"class":95}," [(",[52,1004,779],{"class":252},[52,1006,1007],{"class":95},", m, ",[52,1009,417],{"class":252},[52,1011,127],{"class":95},[52,1013,394],{"class":252},[52,1015,1016],{"class":95},") ",[52,1018,1019],{"class":91},"for",[52,1021,1022],{"class":95}," m ",[52,1024,1025],{"class":91},"in",[52,1027,1028],{"class":252}," range",[52,1030,1031],{"class":95},"(",[52,1033,368],{"class":252},[52,1035,127],{"class":95},[52,1037,1038],{"class":252},"13",[52,1040,1041],{"class":95},")]            ",[52,1043,1045],{"class":1044},"s-wDw","# second Tuesday: Excel WEEKDAY numbers Tuesday as 3\n",[52,1047,1048,1050,1053,1055,1058,1061,1064,1066,1068],{"class":54,"line":229},[52,1049,1019],{"class":91},[52,1051,1052],{"class":95}," i, (y, m, wd, n) ",[52,1054,1025],{"class":91},[52,1056,1057],{"class":252}," enumerate",[52,1059,1060],{"class":95},"(cases, ",[52,1062,1063],{"class":135},"start",[52,1065,118],{"class":91},[52,1067,394],{"class":252},[52,1069,1070],{"class":95},"):\n",[52,1072,1073],{"class":54,"line":249},[52,1074,1075],{"class":95},"    ws.append([y, m, wd, n,\n",[52,1077,1078,1081,1084,1087,1090,1093,1096,1098,1100,1102,1105,1107,1109,1111,1114,1116,1118,1120,1122,1124,1126,1128,1131,1133,1135,1137,1140],{"class":54,"line":712},[52,1079,1080],{"class":91},"               f",[52,1082,1083],{"class":62},"\"=DATE(A",[52,1085,1086],{"class":199},"{",[52,1088,1089],{"class":95},"i",[52,1091,1092],{"class":199},"}",[52,1094,1095],{"class":62},",B",[52,1097,1086],{"class":199},[52,1099,1089],{"class":95},[52,1101,1092],{"class":199},[52,1103,1104],{"class":62},",1)+MOD(C",[52,1106,1086],{"class":199},[52,1108,1089],{"class":95},[52,1110,1092],{"class":199},[52,1112,1113],{"class":62},"-WEEKDAY(DATE(A",[52,1115,1086],{"class":199},[52,1117,1089],{"class":95},[52,1119,1092],{"class":199},[52,1121,1095],{"class":62},[52,1123,1086],{"class":199},[52,1125,1089],{"class":95},[52,1127,1092],{"class":199},[52,1129,1130],{"class":62},",1)),7)+7*(D",[52,1132,1086],{"class":199},[52,1134,1089],{"class":95},[52,1136,1092],{"class":199},[52,1138,1139],{"class":62},"-1)\"",[52,1141,1142],{"class":95},",\n",[52,1144,1145,1148,1150],{"class":54,"line":735},[52,1146,1147],{"class":95},"               nth_weekday(y, m, ",[52,1149,368],{"class":252},[52,1151,1152],{"class":95},", n)])\n",[52,1154,1155,1158,1160,1163,1165,1168,1170,1172,1174],{"class":54,"line":766},[52,1156,1157],{"class":95},"    ws.cell(i, ",[52,1159,459],{"class":252},[52,1161,1162],{"class":95},").number_format ",[52,1164,118],{"class":91},[52,1166,1167],{"class":95}," ws.cell(i, ",[52,1169,481],{"class":252},[52,1171,1162],{"class":95},[52,1173,118],{"class":91},[52,1175,1176],{"class":62}," \"ddd dd mmm yyyy\"\n",[52,1178,1179,1182,1185,1188,1191,1194,1196,1199,1201],{"class":54,"line":771},[52,1180,1181],{"class":95},"ws[",[52,1183,1184],{"class":62},"\"H1\"",[52,1186,1187],{"class":95},"], ws[",[52,1189,1190],{"class":62},"\"H2\"",[52,1192,1193],{"class":95},"] ",[52,1195,118],{"class":91},[52,1197,1198],{"class":62}," \"Last Friday of the month in B2\"",[52,1200,127],{"class":95},[52,1202,1203],{"class":62},"\"=EOMONTH(DATE(A2,B2,1),0)-MOD(WEEKDAY(EOMONTH(DATE(A2,B2,1),0))-6,7)\"\n",[52,1205,1206,1208,1210,1213,1215],{"class":54,"line":803},[52,1207,1181],{"class":95},[52,1209,1190],{"class":62},[52,1211,1212],{"class":95},"].number_format ",[52,1214,118],{"class":91},[52,1216,1176],{"class":62},[52,1218,1219,1222,1225],{"class":54,"line":832},[52,1220,1221],{"class":95},"wb.save(",[52,1223,1224],{"class":62},"\"nth_weekday.xlsx\"",[52,1226,144],{"class":95},[42,1228,1230],{"className":44,"code":1229,"language":46,"meta":47,"style":47},"soffice --headless --convert-to 'csv:Text - txt - csv (StarCalc):44,34,76,1,,0,false,true,true' nth_weekday.xlsx > \u002Fdev\u002Fnull 2>&1\nawk -F, 'NR>1 && $5!=$6 {bad++} END {print (NR-1) \" months, \" bad+0 \" differences\"}' nth_weekday.csv\nsed -n '2p' nth_weekday.csv | cut -d, -f5-\n",[49,1231,1232,1258,1272],{"__ignoreMap":47},[52,1233,1234,1237,1240,1243,1246,1249,1252,1255],{"class":54,"line":55},[52,1235,1236],{"class":58},"soffice",[52,1238,1239],{"class":252}," --headless",[52,1241,1242],{"class":252}," --convert-to",[52,1244,1245],{"class":62}," 'csv:Text - txt - csv (StarCalc):44,34,76,1,,0,false,true,true'",[52,1247,1248],{"class":62}," nth_weekday.xlsx",[52,1250,1251],{"class":91}," >",[52,1253,1254],{"class":62}," \u002Fdev\u002Fnull",[52,1256,1257],{"class":91}," 2>&1\n",[52,1259,1260,1263,1266,1269],{"class":54,"line":105},[52,1261,1262],{"class":58},"awk",[52,1264,1265],{"class":252}," -F,",[52,1267,1268],{"class":62}," 'NR>1 && $5!=$6 {bad++} END {print (NR-1) \" months, \" bad+0 \" differences\"}'",[52,1270,1271],{"class":62}," nth_weekday.csv\n",[52,1273,1274,1277,1280,1283,1286,1289,1292,1295],{"class":54,"line":112},[52,1275,1276],{"class":58},"sed",[52,1278,1279],{"class":252}," -n",[52,1281,1282],{"class":62}," '2p'",[52,1284,1285],{"class":62}," nth_weekday.csv",[52,1287,1288],{"class":91}," |",[52,1290,1291],{"class":58}," cut",[52,1293,1294],{"class":252}," -d,",[52,1296,1297],{"class":252}," -f5-\n",[10,1299,1300,1301,1304,1305,1308,1309,1312,1313,1316,1317,1319,1320,1323],{},"The Excel formula follows the same logic as the function: ",[49,1302,1303],{},"DATE(year, month, 1)"," is the first of the month, ",[49,1306,1307],{},"WEEKDAY"," gives its weekday, ",[49,1310,1311],{},"MOD(target − weekday, 7)"," is the number of days to the first occurrence, and ",[49,1314,1315],{},"7*(n−1)"," adds the extra weeks. The only trap is numbering: Excel's ",[49,1318,1307],{}," counts Sunday as 1 and Saturday as 7 by default, while Python counts Monday as 0, so Tuesday is 3 in the sheet and 1 in the function. The last-Friday formula steps back from the end of the month, found with ",[49,1321,1322],{},"EOMONTH",". Recalculating the sheet in LibreOffice and comparing the formula column with the Python column for all twelve months shows no differences, which is the reassurance needed before a schedule built either way is trusted.",[298,1325,307,1331,307,1334,307,1337,307,1341,307,1348,307,1354,307,1359,307,1363,307,1367,307,1371,307,1376,307,1381,307,1385,307,1388,307,1391],{"viewBox":1326,"role":301,"ariaLabelledBy":1327,"xmlns":305,"style":1330},"4 0 752 173",[1328,1329],"nth-numbering-t","nth-numbering-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[309,1332,1333],{"id":1328},"Weekday numbers in Excel and Python",[313,1335,1336],{"id":1329},"Excel's WEEKDAY function numbers Sunday as 1 through Saturday as 7 by default. Python's weekday method and pandas' dayofweek number Monday as 0 through Sunday as 6. Tuesday is therefore 3 in Excel and 1 in Python.",[317,1338],{"x":439,"y":320,"width":1339,"height":1340,"fill":323},"752","173",[317,1342],{"x":1343,"y":327,"width":1344,"height":1345,"rx":1346,"fill":371,"stroke":372,"style":1347},"20.0","351.0","141.0","14","stroke-width:2px",[338,1349,1353],{"x":1350,"y":1351,"style":1352},"195.5","44.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Excel WEEKDAY(date)",[54,1355],{"x1":1356,"y1":1357,"x2":1358,"y2":1357,"stroke":372,"style":332},"36.0","57.0","355.0",[338,1360,1362],{"x":1350,"y":1361,"style":399},"77.0","Sunday = 1",[338,1364,1366],{"x":1350,"y":1365,"style":399},"103.0","Tuesday = 3",[338,1368,1370],{"x":1350,"y":1369,"style":399},"129.0","Saturday = 7",[317,1372],{"x":1373,"y":327,"width":1344,"height":1345,"rx":1346,"fill":1374,"stroke":1375,"style":1347},"389.0","#d9f4f1","var(--teal,#0f9488)",[338,1377,1380],{"x":1378,"y":1351,"style":1379},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Python .weekday() \u002F pandas .dayofweek",[54,1382],{"x1":1383,"y1":1357,"x2":1384,"y2":1357,"stroke":1375,"style":332},"405.0","724.0",[338,1386,1387],{"x":1378,"y":1361,"style":399},"Monday = 0",[338,1389,1390],{"x":1378,"y":1365,"style":399},"Tuesday = 1",[338,1392,1393],{"x":1378,"y":1369,"style":399},"Sunday = 6",[37,1395,1397],{"id":1396},"step-4-when-the-date-is-a-public-holiday","Step 4 — When the date is a public holiday",[42,1399,1401],{"className":82,"code":1400,"language":84,"meta":47,"style":47},"import holidays\n\nuk = holidays.country_holidays(\"GB\", subdiv=\"ENG\", years=2026)\nfirst_mondays = pd.date_range(\"2026-01-01\", \"2026-12-31\", freq=\"WOM-1MON\")\nadjusted = [d + pd.offsets.CustomBusinessDay(1, holidays=list(uk)) if d.date() in uk else d for d in first_mondays]\nmoved = [(a.date(), b.date(), uk.get(a.date())) for a, b in zip(first_mondays, adjusted) if a != b]\nprint(moved)\n",[49,1402,1403,1409,1413,1447,1473,1526,1560],{"__ignoreMap":47},[52,1404,1405,1407],{"class":54,"line":55},[52,1406,92],{"class":91},[52,1408,72],{"class":95},[52,1410,1411],{"class":54,"line":105},[52,1412,109],{"emptyLinePlaceholder":108},[52,1414,1415,1418,1420,1423,1426,1428,1431,1433,1436,1438,1441,1443,1445],{"class":54,"line":112},[52,1416,1417],{"class":95},"uk ",[52,1419,118],{"class":91},[52,1421,1422],{"class":95}," holidays.country_holidays(",[52,1424,1425],{"class":62},"\"GB\"",[52,1427,127],{"class":95},[52,1429,1430],{"class":135},"subdiv",[52,1432,118],{"class":91},[52,1434,1435],{"class":62},"\"ENG\"",[52,1437,127],{"class":95},[52,1439,1440],{"class":135},"years",[52,1442,118],{"class":91},[52,1444,779],{"class":252},[52,1446,144],{"class":95},[52,1448,1449,1452,1454,1456,1458,1460,1462,1464,1466,1468,1471],{"class":54,"line":147},[52,1450,1451],{"class":95},"first_mondays ",[52,1453,118],{"class":91},[52,1455,121],{"class":95},[52,1457,124],{"class":62},[52,1459,127],{"class":95},[52,1461,130],{"class":62},[52,1463,127],{"class":95},[52,1465,136],{"class":135},[52,1467,118],{"class":91},[52,1469,1470],{"class":62},"\"WOM-1MON\"",[52,1472,144],{"class":95},[52,1474,1475,1478,1480,1483,1485,1488,1490,1492,1495,1497,1500,1503,1505,1508,1510,1513,1515,1517,1519,1521,1523],{"class":54,"line":174},[52,1476,1477],{"class":95},"adjusted ",[52,1479,118],{"class":91},[52,1481,1482],{"class":95}," [d ",[52,1484,605],{"class":91},[52,1486,1487],{"class":95}," pd.offsets.CustomBusinessDay(",[52,1489,368],{"class":252},[52,1491,127],{"class":95},[52,1493,1494],{"class":135},"holidays",[52,1496,118],{"class":91},[52,1498,1499],{"class":252},"list",[52,1501,1502],{"class":95},"(uk)) ",[52,1504,657],{"class":91},[52,1506,1507],{"class":95}," d.date() ",[52,1509,1025],{"class":91},[52,1511,1512],{"class":95}," uk ",[52,1514,669],{"class":91},[52,1516,654],{"class":95},[52,1518,1019],{"class":91},[52,1520,654],{"class":95},[52,1522,1025],{"class":91},[52,1524,1525],{"class":95}," first_mondays]\n",[52,1527,1528,1531,1533,1536,1538,1541,1543,1546,1549,1551,1554,1557],{"class":54,"line":179},[52,1529,1530],{"class":95},"moved ",[52,1532,118],{"class":91},[52,1534,1535],{"class":95}," [(a.date(), b.date(), uk.get(a.date())) ",[52,1537,1019],{"class":91},[52,1539,1540],{"class":95}," a, b ",[52,1542,1025],{"class":91},[52,1544,1545],{"class":252}," zip",[52,1547,1548],{"class":95},"(first_mondays, adjusted) ",[52,1550,657],{"class":91},[52,1552,1553],{"class":95}," a ",[52,1555,1556],{"class":91},"!=",[52,1558,1559],{"class":95}," b]\n",[52,1561,1562,1564],{"class":54,"line":209},[52,1563,253],{"class":252},[52,1565,1566],{"class":95},"(moved)\n",[10,1568,1569,1570,1573],{},"Rules like ",[14,1571,1572],{},"the first Monday"," often collide with bank holidays, which also tend to fall on Mondays. The usual policy is to move the event to the next working day, and a custom business-day offset that knows the holiday calendar does that in one step. In England in 2026 two first Mondays collide with bank holidays — Easter Monday on 6 April and the early May bank holiday on 4 May — so those months' events move to Tuesday 7 April and Tuesday 5 May. Other policies — skip the month, or move to the previous working day — are a different offset or a filter on the same list.",[37,1575,1577],{"id":1576},"the-reverse-question-which-occurrence-is-this-date","The reverse question: which occurrence is this date?",[10,1579,1580,1581,1584,1585,1588],{},"Sometimes the date is known and the question is the other way round — is this order date the second Tuesday of its month, or the last Friday? The occurrence number of any date is ",[49,1582,1583],{},"(day − 1) \u002F\u002F 7 + 1",": days 1 to 7 are the first occurrence of their weekday, 8 to 14 the second, and so on. A date is the ",[14,1586,1587],{},"last"," occurrence if adding seven days moves it into the next month.",[42,1590,1592],{"className":82,"code":1591,"language":84,"meta":47,"style":47},"dates = pd.Series(pd.to_datetime([\"2026-03-10\", \"2026-03-27\", \"2026-03-31\", \"2026-11-26\"]))\nlabels = pd.DataFrame({\"date\": dates.dt.strftime(\"%a %d %b\"),\n                       \"occurrence\": (dates.dt.day - 1) \u002F\u002F 7 + 1,\n                       \"is last\": (dates + pd.Timedelta(days=7)).dt.month != dates.dt.month})\nprint(labels.to_string(index=False))\n",[49,1593,1594,1625,1653,1677,1704],{"__ignoreMap":47},[52,1595,1596,1599,1601,1604,1607,1609,1612,1614,1617,1619,1622],{"class":54,"line":55},[52,1597,1598],{"class":95},"dates ",[52,1600,118],{"class":91},[52,1602,1603],{"class":95}," pd.Series(pd.to_datetime([",[52,1605,1606],{"class":62},"\"2026-03-10\"",[52,1608,127],{"class":95},[52,1610,1611],{"class":62},"\"2026-03-27\"",[52,1613,127],{"class":95},[52,1615,1616],{"class":62},"\"2026-03-31\"",[52,1618,127],{"class":95},[52,1620,1621],{"class":62},"\"2026-11-26\"",[52,1623,1624],{"class":95},"]))\n",[52,1626,1627,1630,1632,1634,1637,1640,1642,1644,1646,1649,1651],{"class":54,"line":105},[52,1628,1629],{"class":95},"labels ",[52,1631,118],{"class":91},[52,1633,187],{"class":95},[52,1635,1636],{"class":62},"\"date\"",[52,1638,1639],{"class":95},": dates.dt.strftime(",[52,1641,196],{"class":62},[52,1643,219],{"class":199},[52,1645,222],{"class":199},[52,1647,1648],{"class":199}," %b",[52,1650,196],{"class":62},[52,1652,206],{"class":95},[52,1654,1655,1658,1661,1663,1665,1667,1669,1671,1673,1675],{"class":54,"line":112},[52,1656,1657],{"class":62},"                       \"occurrence\"",[52,1659,1660],{"class":95},": (dates.dt.day ",[52,1662,619],{"class":91},[52,1664,644],{"class":252},[52,1666,1016],{"class":95},[52,1668,689],{"class":91},[52,1670,628],{"class":252},[52,1672,631],{"class":91},[52,1674,644],{"class":252},[52,1676,1142],{"class":95},[52,1678,1679,1682,1685,1687,1690,1692,1694,1696,1699,1701],{"class":54,"line":147},[52,1680,1681],{"class":62},"                       \"is last\"",[52,1683,1684],{"class":95},": (dates ",[52,1686,605],{"class":91},[52,1688,1689],{"class":95}," pd.Timedelta(",[52,1691,611],{"class":135},[52,1693,118],{"class":91},[52,1695,503],{"class":252},[52,1697,1698],{"class":95},")).dt.month ",[52,1700,1556],{"class":91},[52,1702,1703],{"class":95}," dates.dt.month})\n",[52,1705,1706,1708,1711,1713,1715,1717],{"class":54,"line":174},[52,1707,253],{"class":252},[52,1709,1710],{"class":95},"(labels.to_string(",[52,1712,259],{"class":135},[52,1714,118],{"class":91},[52,1716,264],{"class":252},[52,1718,267],{"class":95},[10,1720,1721,1722,1725,1726,1729,1730,1733],{},"This is useful for checking data against a rule — flagging meetings that were not held on the second Tuesday, or payments that missed the last Friday — and for building a ",[14,1723,1724],{},"week of month"," column for a report. Tuesday 10 March is the second Tuesday; Friday 27 March is the fourth Friday and also the last; Tuesday 31 March is the fifth and last Tuesday; and Thursday 26 November is the fourth Thursday and, because November 2026 has only four Thursdays, also the last. That double answer is why rules should say which they mean: ",[14,1727,1728],{},"the fourth Thursday"," and ",[14,1731,1732],{},"the last Thursday"," are the same day in some years and a week apart in others.",[298,1735,307,1740,307,1743,307,1746,307,1749,307,1754,307,1760,307,1765,307,1770,307,1775,307,1778,307,1782,307,1785,307,1788,307,1791,307,1796,307,1801,307,1804,307,1808,307,1811,307,1814,307,1819],{"viewBox":1736,"role":301,"ariaLabelledBy":1737,"xmlns":305,"style":1330},"4 0 752 98",[1738,1739],"nth-reverse-t","nth-reverse-d",[309,1741,1742],{"id":1738},"Which occurrence of its weekday is a date?",[313,1744,1745],{"id":1739},"Take the day of the month, subtract one, divide by seven ignoring the remainder and add one to get the occurrence number. Then add seven days; if the result is in the next month, the date is also the last occurrence of its weekday.",[317,1747],{"x":439,"y":320,"width":1339,"height":1748,"fill":323},"98",[317,1750],{"x":1343,"y":327,"width":1751,"height":1752,"rx":1753,"fill":330,"stroke":331,"style":1347},"153.0","66.0","12",[338,1755,1759],{"x":1756,"y":1757,"style":1758},"96.5","45.0","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Day of month",[338,1761,1764],{"x":1756,"y":1762,"style":1763},"64.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","e.g. 27",[54,1766],{"x1":1767,"y1":1768,"x2":1769,"y2":1768,"stroke":372,"style":1347},"178.0","49.0","200.0",[1771,1772],"polygon",{"points":1773,"fill":1774},"204.0,49.0 195.0,54.0 195.0,44.0","#5b5cf0",[317,1776],{"x":1777,"y":327,"width":1751,"height":1752,"rx":1753,"fill":371,"stroke":372,"style":1347},"209.0",[338,1779,1583],{"x":1780,"y":1757,"style":1781},"285.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[338,1783,1784],{"x":1780,"y":1762,"style":1763},"→ 4th occurrence",[54,1786],{"x1":1787,"y1":1768,"x2":1373,"y2":1768,"stroke":372,"style":1347},"367.0",[1771,1789],{"points":1790,"fill":1774},"393.0,49.0 384.0,54.0 384.0,44.0",[317,1792],{"x":1793,"y":327,"width":1751,"height":1752,"rx":1753,"fill":1794,"stroke":1795,"style":1347},"398.0","#fdefd8","var(--gold,#b4740a)",[338,1797,1800],{"x":1798,"y":1757,"style":1799},"474.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","+ 7 days",[338,1802,1803],{"x":1798,"y":1762,"style":1763},"3 April",[54,1805],{"x1":1806,"y1":1768,"x2":1807,"y2":1768,"stroke":372,"style":1347},"556.0","578.0",[1771,1809],{"points":1810,"fill":1774},"582.0,49.0 573.0,54.0 573.0,44.0",[317,1812],{"x":1813,"y":327,"width":1751,"height":1752,"rx":1753,"fill":1374,"stroke":1375,"style":1347},"587.0",[338,1815,1818],{"x":1816,"y":1757,"style":1817},"663.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Next month?",[338,1820,1821],{"x":1816,"y":1762,"style":1763},"yes → also the last",[37,1823,1825],{"id":1824},"common-pitfalls","Common pitfalls",[1827,1828,1829,1840,1846,1855,1861],"ul",{},[1830,1831,1832,1836,1837,1839],"li",{},[1833,1834,1835],"strong",{},"Mixing weekday numbering."," Excel ",[49,1838,1307],{}," is Sunday = 1; Python is Monday = 0.",[1830,1841,1842,1845],{},[1833,1843,1844],{},"Assuming a fifth occurrence exists."," Check the result is still in the same month.",[1830,1847,1848,1854],{},[1833,1849,1850,1851,35],{},"Using ",[49,1852,1853],{},"WOM-5…"," pandas stops at the fourth week; use a function for fifth-weekday rules.",[1830,1856,1857,1860],{},[1833,1858,1859],{},"Ignoring holidays."," Move dates that land on a holiday with a holiday-aware offset.",[1830,1862,1863,1866],{},[1833,1864,1865],{},"Hard-coding a year's dates."," Generate them so next year's schedule is one parameter.",[37,1868,1870],{"id":1869},"conclusion","Conclusion",[10,1872,1873,1874,1877,1878,1880,1881,1883,1884,1887,1888,1891],{},"For schedules built on weekdays, use ",[49,1875,1876],{},"pd.date_range"," with ",[49,1879,276],{},"-style frequencies for the nth weekday and ",[49,1882,292],{}," for the last one; use a small function when a single date or a fifth occurrence is needed; and, in a sheet, ",[49,1885,1886],{},"DATE"," plus ",[49,1889,1890],{},"MOD(target − WEEKDAY(first), 7)"," plus whole weeks, remembering that Excel numbers Sunday as 1. Check one against the other, and shift dates that land on public holidays.",[37,1893,1895],{"id":1894},"frequently-asked-questions","Frequently asked questions",[10,1897,1898,1901,1902,35],{},[1833,1899,1900],{},"How do I get the second Tuesday of every month in pandas?","\nUse ",[49,1903,1904],{},"pd.date_range(start, end, freq=\"WOM-2TUE\")",[10,1906,1907,1901,1910,35],{},[1833,1908,1909],{},"How do I get the last Friday of every month in pandas?",[49,1911,1912],{},"pd.date_range(start, end, freq=\"LWOM-FRI\")",[10,1914,1915,1918,1921,1922,1925],{},[1833,1916,1917],{},"What is the Excel formula for the nth weekday of a month?",[49,1919,1920],{},"=DATE(y,m,1)+MOD(w-WEEKDAY(DATE(y,m,1)),7)+7*(n-1)",", where ",[49,1923,1924],{},"w"," is the weekday number with Sunday as 1.",[10,1927,1928,1931],{},[1833,1929,1930],{},"Does every month have a fifth Friday?","\nNo; only months where the fifth occurrence still falls inside the month, so check the result's month.",[37,1933,1935],{"id":1934},"related","Related",[1827,1937,1938,1944,1951,1958],{},[1830,1939,1940,1941,1943],{},"Up one level: ",[31,1942,34],{"href":33}," — dates in Excel data.",[1830,1945,1946,1950],{},[31,1947,1949],{"href":1948},"\u002Fautomating-reporting-workflows\u002Fscheduling-python-excel-scripts-with-cron\u002Frun-a-report-on-the-last-business-day-of-the-month\u002F","Run a Report on the Last Business Day of the Month"," — business-day rules.",[1830,1952,1953,1957],{},[31,1954,1956],{"href":1955},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fflag-public-holidays-in-excel-data-with-python\u002F","Flag Public Holidays in Excel Data with Python"," — holiday calendars.",[1830,1959,1960,1964],{},[31,1961,1963],{"href":1962},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fconvert-text-months-and-weekdays-to-dates\u002F","Convert Text Months and Weekdays to Dates"," — weekday names into dates.",[1966,1967,1968],"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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}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 .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}",{"title":47,"searchDepth":105,"depth":105,"links":1970},[1971,1972,1973,1974,1975,1976,1977,1978,1979,1980],{"id":39,"depth":105,"text":40},{"id":78,"depth":105,"text":79},{"id":521,"depth":105,"text":522},{"id":905,"depth":105,"text":906},{"id":1396,"depth":105,"text":1397},{"id":1576,"depth":105,"text":1577},{"id":1824,"depth":105,"text":1825},{"id":1869,"depth":105,"text":1870},{"id":1894,"depth":105,"text":1895},{"id":1934,"depth":105,"text":1935},"2026-10-02","Find dates like \"the second Tuesday\", \"the first Monday\" or \"the last Friday\" of every month with pandas: the WOM frequency in date_range, the WeekOfMonth and LastWeekOfMonth offsets, a plain function for a single date, the equivalent Excel formula written into a sheet and checked against Python, and what to do when the date lands on a public holiday.","md",[1985,1987,1989,1991],{"q":1900,"a":1986},"Use pd.date_range(start, end, freq=\"WOM-2TUE\").",{"q":1909,"a":1988},"Use pd.date_range(start, end, freq=\"LWOM-FRI\").",{"q":1917,"a":1990},"=DATE(y,m,1)+MOD(w-WEEKDAY(DATE(y,m,1)),7)+7*(n-1), where w is the weekday number with Sunday as 1.",{"q":1930,"a":1992},"No; only months where the fifth occurrence still falls inside the month, so check the result's month.","nth weekday of month pandas",null,{"breadcrumb":1996},[1997,2000,2003],{"name":1998,"item":1999},"Home","\u002F",{"name":2001,"item":2002},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":34,"item":33},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month",{"title":2006,"description":2007},"Calculate the Nth Weekday of a Month in pandas and Excel","Second Tuesday, first Monday or last Friday of each month in Python: date_range with WOM frequencies, WeekOfMonth and LastWeekOfMonth offsets, the Excel DATE and WEEKDAY formula, and holiday handling.","calculate-the-nth-weekday-of-a-month","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-the-nth-weekday-of-a-month\u002Findex",[2011,2012],"dates-and-times","pandas","how-to","hhJc9rqc62JO6lBOba_RYTr1rEW1dFK0y5cMypJ7jYI",[2016,2020],{"title":2017,"path":2018,"stem":2019,"children":-1},"Calculate Month-to-Date and Year-to-Date Totals with pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-month-to-date-and-year-to-date-totals-with-pandas","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-month-to-date-and-year-to-date-totals-with-pandas\u002Findex",{"title":2021,"path":2022,"stem":2023,"children":-1},"Calculate Working Hours Between Two Timestamps","\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-working-hours-between-two-timestamps","advanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data\u002Fcalculate-working-hours-between-two-timestamps\u002Findex",[2025,2027],{"path":2026,"title":2001},"\u002Fadvanced-data-transformation-and-cleaning",{"path":2028,"title":34},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-dates-and-times-in-excel-data",[],[2031,2034,2037,2040,2043,2046],{"path":2032,"title":2033,"kind":2013},"\u002Fadvanced-data-transformation-and-cleaning\u002Fapplying-conditional-formatting-with-openpyxl\u002Fhighlight-overdue-dates-with-openpyxl","Highlight Overdue Dates in Excel with openpyxl",{"path":2035,"title":2036,"kind":2013},"\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":2038,"title":2039,"kind":2013},"\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":2041,"title":2042,"kind":2013},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-moving-averages-with-pandas-rolling","Calculate Moving Averages with pandas rolling",{"path":2044,"title":2045,"kind":2013},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Feomonth-and-edate-equivalents-in-pandas","EOMONTH and EDATE Equivalents in pandas",{"path":2047,"title":2048,"kind":2013},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fyearfrac-and-days360-equivalents-in-python","YEARFRAC and DAYS360 Equivalents in Python",1790972101155]