C# example

How to calculate the difference between two dates in C#

9 min read Updated Oct 2026 Runs in an isolated runtime
Quick answer

Subtract one date from the other: TimeSpan diff = end - start;. Then read diff.TotalDays for the whole difference in days as a double, or diff.Days for whole days only. For dates with no time of day, use DateOnly (.NET 6+) and end.DayNumber - start.DayNumber. Age, months and "3 hours ago" need a few lines of calendar logic each, shown below.

In C#, subtracting one DateTime from another gives a TimeSpan: a length of time measured in ticks of 100 nanoseconds. That answers "how long between these two moments" in days, hours or seconds. It can't answer "how many months" or "how old is she", because a month or a year has no fixed length, so those are worked out on the calendar instead.

This page covers the three things people search for most: the number of days between two dates, someone's age from their birthday, and relative time like "3 hours ago". It finishes with time zones, where a plain DateTime subtraction can be an hour off. Every snippet uses fixed dates so its output never changes; in your own code you would pass DateTime.UtcNow or DateOnly.FromDateTime(DateTime.Today). Each example runs on this page: hit Run, then edit the code and run it again.

1Subtract two dates to get a TimeSpanRecommended

end - start (or end.Subtract(start), which is the same thing) returns a TimeSpan. It has two families of properties, and mixing them up is the most common bug here. The Total* properties (TotalDays, TotalHours, TotalMinutes, ...) give the whole difference in one unit as a double. The plain ones (Days, Hours, Minutes, ...) give one component each, like the fields of a clock.

Program.cs

Output

The TimeSpan prints as 217.08:15:00: 217 days, 8 hours, 15 minutes. TotalDays is 217.34375 and TotalHours is 5216.25, while Hours is just 8, the hours left over after the whole days. So if you want "how many hours apart", it's TotalHours, never Hours. The components are what you want for display, as in 217 days, 8 hours and 15 minutes or a custom format string like @"d\.hh\:mm" (217.08:15), where literal characters need a backslash. Subtracting the other way round gives -217.08:15:00, and Duration() returns the absolute value. A TimeSpan also compares directly with > and <, so diff > TimeSpan.FromDays(30) reads the way you'd say it.

2Count the days between two dates

TimeSpan.Days counts elapsed 24-hour periods, so the time of day leaks into it: 11pm to 1am the next morning is 0 days. When you mean calendar days, drop the time first with .Date, or better, use DateOnly (.NET 6+), which has no time part at all. DateOnly has no minus operator, but its DayNumber property (days since 1 January 0001) turns the difference into plain integer subtraction.

Program.cs

Output

The two times two hours apart give 0 elapsed days but 1 calendar day once both are cut to .Date. From 1 January to 25 December 2026 is 358 days from Jan 1 to Dec 25, and 359 days counting both ends: whether to add 1 depends on whether you count nights (a hotel stay) or dates (a festival). Going through ToDateTime(TimeOnly.MinValue) gives the same 358 as a TimeSpan. February has 29 days in 2028 and 28 in 2027, so leap years need no special code. For a difference with a fraction, decide how to round on purpose: 2.375 days becomes 2 with a cast, 2 with Math.Round and 3 with Math.Ceiling, which is what a per-day rental charges. The last line, 82 days to go, is the countdown pattern.

3Calculate age from a birthday

Age is the number of birthdays someone has had, which is a calendar question, not a length of time. The standard answer subtracts the years, then takes one off if this year's birthday hasn't happened yet. today.AddYears(-age) does that check without comparing months and days by hand, and it copes with 29 February because AddYears moves it to 28 February in a non-leap year. On .NET Framework, where there is no DateOnly, the same function works with DateTime and DateTime.Today.

Program.cs

Output

On 4 October 2026, someone born on 4 October 1990 is 36 and someone born a day later is still 35. The leap-day birthday from 2000 gives 26, and a baby born today is 0. A baby born on 29 February 2024 is 0 on 28 February 2025 and 1 on 1 March 2025, which is the usual rule; some jurisdictions use 28 February, so check if it matters legally. The yyyyMMdd trick, subtracting dates written as numbers like 20261004 and dividing by 10,000, gives the same 35. Dividing TotalDays by 365.25 does not: on the 26th birthday it gives 25.9986 -> 25, should be 26, because leap days don't fall evenly every four years from a given date. (The [...] array is a C# 12 collection expression; on older compilers write new DateOnly[] { ... }.)

4Years, months and days between two dates

TimeSpan has no Months or Years property, and that's on purpose: a month is 28 to 31 days. To say "36 years, 4 months and 19 days", count whole months with AddMonths the way the age function counts whole years, then count the days left over. MonthsBetween on its own answers "how many full months between these dates".

Program.cs

Output

15 May 1990 to 4 October 2026 is 36y 4m 19d, and 29 February 2024 to the same day is 2y 7m 5d. Month ends are where every library has to pick a rule: 31 January plus one month is 28 February (AddMonths clamps to the last day), so 31 January to 1 March comes out as 0y 1m 1d. Equal dates give 0y 0m 0d. From 15 January, 4 October is 8 full months and 15 October is 9: the ninth month only counts once it is complete. If you need a different month-end convention, such as a finance day-count rule, write it into MonthsBetween; there is no single right answer.

5Relative time: "3 hours ago"

For "posted 3 hours ago" there is nothing built in, so you subtract the timestamp from now and pick the largest unit that fits. Compare Total* values against thresholds, round down, and handle the plural. Store and compare timestamps in UTC (DateTime.UtcNow) so the answer doesn't shift with the server's time zone or daylight saving.

Program.cs

Output

Against a fixed now of 12:00, 20 seconds back is just now, 90 seconds is 1 minute ago (rounded down), then 45 minutes ago, 3 hours ago and 1 day ago for 30 hours. Twelve days is 12 days ago, 75 days is 2 months ago and 800 days is 2 years ago. Months here are 30 days and years 365, which is fine for a label nobody does arithmetic on. Future times read in 10 minutes and in 3 days. Tune the thresholds to taste: many sites switch to a plain date after a week, since "2 years ago" is less useful than the date itself.

6Time zones, DST and DateTimeOffset

A DateTime subtraction compares the two clock readings and ignores the Kind property entirely. That's right for UTC values and for dates, but wrong for local times that straddle a daylight-saving change, or for two values in different zones. A DateTimeOffset stores the UTC offset with the time, so subtracting two of them always gives the real elapsed time. (The sandbox on this page runs in UTC, so the snippet uses an explicit America/New_York zone.)

Program.cs

Output

Noon to noon across the US clock change is wall clock: 1.00:00:00 as DateTimes, but the offset moves from -05:00 to -04:00, so only 23:00:00 really passed. Converting both to UTC with TimeZoneInfo.ConvertTimeToUtc gives the same 23:00:00. The second half is the Kind trap: 08:00 in New York and 12:00 UTC are the same moment, yet subtracting the DateTimes gives 04:00:00, because one is Unspecified and the other Utc and the subtraction doesn't look. The same two moments as DateTimeOffset give 00:00:00. Rule of thumb: store UTC, subtract UTC or DateTimeOffset, and convert to local time only for display.

7Which should you use?

MethodAnswersWatch out forBest for
(end - start).TotalDaysExact length, as a doubleDays vs TotalDays, Hours vs TotalHoursDurations, deadlines, "older than 30 days"
end.DayNumber - start.DayNumberCalendar days, as an intAdd 1 to count both endsDays between dates, countdowns (.NET 6+)
Year diff + AddYears checkAge in whole yearsNever TotalDays / 365.25Age from a birthday
AddMonths countingYears, months and daysMonth-end rules (Jan 31 + 1 month)Tenure, "2y 7m 5d" displays
Thresholds on TotalMinutes...A rough labelUse UTC timestampsRelative time, "3 hours ago"
DateTimeOffset subtractionReal elapsed timeDateTime ignores Kind and DSTLocal times, values from several zones

Frequently asked questions

What is the difference between TimeSpan.Days and TimeSpan.TotalDays?

TotalDays is the whole difference expressed in days as a double, while Days is only the whole-days component, with the rest stored in Hours, Minutes and so on. For 1 March 09:30 to 4 October 17:45, TotalDays is 217.34375 and Days is 217, but TotalHours is 5216.25 while Hours is 8. A negative span keeps the sign on both: -217 and -217.34375. Use the Total* properties for "how long" and the components only for display.

How do I get the number of days between two dates, including both days?

Subtract the day numbers and add 1: to.DayNumber - from.DayNumber + 1 with DateOnly, or (to.Date - from.Date).Days + 1 with DateTime. From 1 January to 25 December 2026 is 358 days, or 359 counting both ends. If you don't know which date comes first, wrap the subtraction in Math.Abs, which also gives 358 with the dates swapped.

How do I calculate the number of business days between two dates?

Loop over the dates and skip weekends: for (DateOnly d = start; d <= end; d = d.AddDays(1)) if (d.DayOfWeek is not (DayOfWeek.Saturday or DayOfWeek.Sunday)) count++;. That counts 22 working days from 1 to 31 October 2026, and 5 from Monday 5 to Friday 9 October. Public holidays differ by country, so keep them in a HashSet<DateOnly> and skip those too. The loop is fast enough for spans of years; only very long ranges need a formula based on whole weeks.

Is there a DateDiff function in C#?

Not in C# itself, but VB's Microsoft.VisualBasic.DateAndTime.DateDiff ships with .NET and can be called from C# after using Microsoft.VisualBasic;. It counts calendar boundaries crossed, not complete units: DateDiff(DateInterval.Month, new DateTime(2026, 1, 31), new DateTime(2026, 2, 1)) returns 1, one day apart, and DateDiff(DateInterval.Year, new DateTime(2025, 12, 31), new DateTime(2026, 1, 1)) also returns 1. That suits a report grouped by month, but for complete months or an age use the AddMonths and AddYears checks shown above.

How do I test code that calculates time differences from DateTime.Now?

Don't read the clock inside the logic. Pass "now" in as a parameter, as the helpers on this page do, or inject a TimeProvider (.NET 8+): production code uses TimeProvider.System.GetUtcNow(), and a test passes a subclass that overrides GetUtcNow() to return a fixed DateTimeOffset. With a fixed clock at 12:00 UTC, a post made at 09:00 UTC is 03:00:00 old on every run. The Microsoft.Extensions.TimeProvider.Testing package adds a ready-made FakeTimeProvider you can advance by hand.

Should I use DateTime.Now or DateTime.UtcNow when calculating a difference?

Use DateTime.UtcNow or DateTimeOffset.UtcNow. DateTime.Now is local wall-clock time, so a difference that spans a daylight-saving change is an hour off: noon to noon across the US spring change looks like 1.00:00:00 but only 23:00:00 passed. UTC never jumps. To measure how long code takes to run, use Stopwatch (or Stopwatch.GetTimestamp() with Stopwatch.GetElapsedTime on .NET 7+) instead, because the system clock can be corrected while your code runs.

Run it yourself

Open any of these in the full C# editor to tweak, run and share.

C# playground