Inclusive and exclusive counting
The first question any date difference has to answer is whether both endpoints count. From Monday to Friday is four days if you count the gaps between them and five if you count the days themselves. Neither is wrong, and both conventions appear in ordinary use.
Context usually decides. A hotel booking from the 1st to the 5th is four nights. A conference running from the 1st to the 5th is five days. Contracts and legal deadlines frequently specify "clear days", which excludes both the first and last day, producing a third answer again.
Where a deadline matters, work out which convention applies before calculating rather than afterwards. A payment term of "30 days" from an invoice dated the 1st might mean the 30th or the 31st depending on whether the invoice date counts, and that difference has consequences.
Months are not a fixed length
Adding months is genuinely ambiguous, because months have different lengths. What is one month after 31 January? There is no 31 February, and implementations differ: some return 28 February — clamping to the last valid day — and others overflow to 3 March.
Clamping is the more common and generally more useful behaviour, but it breaks reversibility. One month after 31 January clamps to 28 February, and one month before 28 February gives 28 January, not the 31st you started from. Adding a month twice can also differ from adding two months at once, so operations do not compose predictably.
The practical guidance is to avoid month arithmetic where an exact interval matters, and use days instead. Where months are unavoidable — as in monthly billing — decide explicitly what happens to the 29th, 30th and 31st, since a subscription started on the 31st needs a defined behaviour in February.
Leap years and time zones
The leap year rule has three parts, and the third is the one people forget: a year is a leap year if divisible by 4, except centuries, unless divisible by 400. So 1900 was not a leap year and 2000 was. Spreadsheets famously carry a deliberate bug treating 1900 as a leap year, retained for compatibility with an early competitor, which offsets serial date numbers before March 1900.
Time zones cause the more common everyday error. Storing a date as a timestamp and displaying it in a different zone can shift it by a day — a birthday stored as midnight UTC displays as the previous evening for anyone west of Greenwich. For dates without a time component, store a plain calendar date rather than an instant.
Daylight saving means not every day has 24 hours. Two days differ by 23 or 25 hours across a transition, so computing a date difference by dividing elapsed milliseconds by 86,400,000 produces off-by-one errors twice a year. Calendar arithmetic should work on calendar fields, not on durations. The timezone converter covers the display side.