Excel like a finance pro.
Do date arithmetic in VBA
Month-ends, quarter starts and ages in code — and the locale trap when a date is written back.
1What it does
VBA stores dates as numbers the same way Excel does, so arithmetic works: add 30 to a date and you have a date 30 days later. The functions that make it readable are `DateSerial` (build a date from year, month and day), `DateAdd` (move by months or quarters) and `DateDiff` (measure between two). VBA has no EOMONTH, but DateSerial gives you the month-end trick for free: day zero of next month is the last day of this one, so every month-end lands correctly including February. The trap is writing a date into a cell as TEXT, which Excel then re-reads in the machine's locale order.
2The code
Sub PeriodDates()
Dim asOf As Date
asOf = DateSerial(2026, 8, 17)
' Month-end: day ZERO of next month is the last day of this one.
' Handles February and 30-day months with no special cases.
Dim monthEnd As Date
monthEnd = DateSerial(Year(asOf), Month(asOf) + 1, 0) ' 31 Aug 2026
' Start of the quarter the date falls in.
Dim qStart As Date
qStart = DateSerial(Year(asOf), ((Month(asOf) - 1) \ 3) * 3 + 1, 1) ' 1 Jul 2026
' Move by months — DateAdd clamps to month-end, so 31 Jan + 1 month = 28/29 Feb.
Dim nextMonth As Date
nextMonth = DateAdd("m", 1, asOf)
' Whole months between two dates.
Dim monthsOld As Long
monthsOld = DateDiff("m", DateSerial(2026, 3, 31), asOf)
With ActiveSheet
' Write the DATE value, not Format(...) text, or the locale reorders it.
.Range("B2").Value = monthEnd
.Range("B3").Value = qStart
.Range("B4").Value = nextMonth
.Range("B5").Value = monthsOld
.Range("B2:B4").NumberFormat = "d mmm yyyy"
End With
End SubPaste into the Visual Basic Editor (Alt + F11 → Insert → Module), then run and save as macro-enabled (.xlsm).
New to macros? Set up in 5 minutes▾
- 1
Don't see the Developer tab in the ribbon?
You don't strictly need it — Alt + F11 opens the editor directly — but it makes running macros easier.- Windows: File → Options → Customize Ribbon → tick Developer in the right-hand list → OK.
- Mac: Excel → Preferences → Ribbon & Toolbar → tick Developer → Save.
- 2
Paste in the code
Press Alt + F11 to open the Visual Basic editor, then Insert → Module and paste the snippet's code into the blank window. Close it with Alt + Q. - 3
Run it
Press Alt + F8, pick the macro's name, and click Run — that's it. (Pasted a custom function instead? Just type it into a cell like any built-in:=GrossMargin(B2, B3).) - 4
Keep the macro — save as .xlsm
File → Save As → Excel Macro-Enabled Workbook (.xlsm). A plain .xlsx silently drops the code when you save. - 5
Macros blocked?
Click Enable Content on the yellow bar. If you downloaded the file, you may first need to right-click it → Properties → tick Unblock → OK, then reopen.
Heads up: macros can't be undone with Ctrl + Z — save a copy before running one that changes your workbook.
3When you use it
- Compute month-ends and quarter starts for a reporting macro.
- Roll a period forward by a month or a year inside a loop.
- Age invoices in whole months without worksheet formulas.
4See it in action
A simulation — press Run to perform what the macro does to a sample workbook.
| Month-end: DateSerial(y, m + 1, 0) | 28 Feb 2026 |
| Quarter start | 1 Jan 2026 |
| DateAdd("m", 1, asOf) | 17 Mar 2026 |
Day ZERO of next month is the last day of this one. Try 31 January and a leap-year February.
5Pitfalls
A date written as Format(d, "dd/mm/yyyy") text is re-read by Excel in US order, swapping day and month for days 1-12.
Fix: Write the Date value itself and apply a NumberFormat to the cell, as above.
DateDiff("m") counts month BOUNDARIES crossed, so 31 Jan to 1 Feb is one month.
Fix: That's by design. For complete months, compare day numbers too, or use DATEDIF on the sheet.
A literal like #08/17/2026# is always read month-first regardless of locale, which surprises non-US readers of the code.
Fix: Use DateSerial(2026, 8, 17) — unambiguous to anyone reading it.
The quarter formula uses / instead of \ and produces a fraction.
Fix: Integer division in VBA is the backslash: (Month - 1) \ 3.
6No-code alternatives
- EOMONTH and EDATE on the sheet — The formula equivalents, which recalculate and are easier to audit.
- WorksheetFunction.EoMonth — Calls the sheet function from VBA when you'd rather not use the DateSerial trick.
Rather not write macros? Wauvel's free tools generate branded, formula-driven Excel for you — no VBA required.
Learn the moves here — or let Wauvel run them on your numbers.
Meet your AI CFO →One CFO-grade Excel tip a week
A short, practical email for finance operators — functions, shortcuts, and the moves that save an afternoon. Free, unsubscribe anytime.