Dates
These methods cover the DateTime chores that every business app writes by hand: the start and end of a day, week, month, quarter or year, working days, ages, "5 minutes ago" labels, day-by-day loops, ISO week numbers, "the second Tuesday of the month", Unix timestamps and rounding to a 15-minute slot. Reach for them in billing, scheduling and reporting code.
All methods are extension methods on DateTime (and on long for Unix time) in the System namespace, so you do not need a using directive.
At a glance
| Method | What it does |
|---|---|
StartOfDay | Midnight at the start of the day. |
EndOfDay | The last tick of the day (23:59:59.9999999). |
StartOfWeek | Midnight on the first day of the week (Monday by default). |
EndOfWeek | The last tick of the last day of the week. |
StartOfMonth | Midnight on the 1st of the month. |
EndOfMonth | The last tick of the last day of the month. |
StartOfQuarter | Midnight on January, April, July or October 1st. |
EndOfQuarter | The last tick of the quarter. |
StartOfYear | Midnight on January 1st. |
EndOfYear | The last tick of December 31st. |
IsWeekend | true on Saturday and Sunday. |
AddBusinessDays | Adds Monday-to-Friday days, skipping weekends. |
BusinessDaysUntil | Counts the working days between two dates. |
Age | Age in completed years on a given day. |
ToRelativeTime | English text such as "5 minutes ago" or "in 3 days". |
To | Walks from one moment to another, one day or one step at a time. |
Quarter | The calendar quarter, 1 to 4. |
WeekOfYear | The ISO 8601 week number, 1 to 53. |
Next | The next date that falls on a given weekday. |
Previous | The previous date that fell on a given weekday. |
IsSameDay | Whether two moments fall on the same calendar day. |
IsSameWeek | Whether two moments fall in the same week. |
IsSameMonth | Whether two moments fall in the same month of the same year. |
NthWeekdayOfMonth | The first, second, ... fifth given weekday of the month, or null. |
LastWeekdayOfMonth | The last given weekday of the month. |
ToUnixTimeSeconds | Seconds since 1970-01-01 UTC. |
ToUnixTimeMilliseconds | Milliseconds since 1970-01-01 UTC. |
FromUnixTimeSeconds | A UTC DateTime from Unix seconds. |
FromUnixTimeMilliseconds | A UTC DateTime from Unix milliseconds. |
RoundTo | Rounds to the nearest multiple of an interval. |
FloorTo | Rounds down to a multiple of an interval. |
CeilingTo | Rounds up to a multiple of an interval. |
C# has no DateTime literal, so the examples on this page show DateTime results as yyyy-MM-dd HH:mm:ss, plus the Kind when it matters.
"Now" is always passed in
No method on this page reads the system clock. A method that needs "today" or "now" takes it as an argument: Age(today), ToRelativeTime(reference). The same input always gives the same output, so you can test date logic with fixed dates and no clock mocking.
In application code, get "now" from one place, such as TimeProvider (.NET 8 and later, or the Microsoft.Bcl.TimeProvider package), and pass it down.
public sealed class MembershipService
{
private readonly TimeProvider _clock;
public MembershipService(TimeProvider clock)
{
_clock = clock;
}
public bool IsAdult(Customer customer)
{
DateTime today = _clock.GetUtcNow().UtcDateTime.Date;
return customer.BirthDate.Age(today) >= 18;
}
public string LastSeenLabel(Customer customer)
{
DateTime now = _clock.GetUtcNow().UtcDateTime;
return customer.LastSeenAt.ToRelativeTime(now);
}
}
public sealed record Customer(string Email, DateTime BirthDate, DateTime LastSeenAt);
Every method keeps the Kind (Utc, Local, Unspecified) of its input. None of them converts between time zones; convert first when two values come from different zones.
Start and end of a period
Each Start… method returns midnight on the first day of the period. Each End… method returns the last tick (23:59:59.9999999) of the last day. The time of day of the input is ignored, and the Kind is kept.
StartOfDay and EndOfDay
Use these to turn a moment into the bounds of its calendar day.
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime dayStart = orderedAt.StartOfDay(); // → 2024-05-15 00:00:00 (Utc)
DateTime dayEnd = orderedAt.EndOfDay(); // → 2024-05-15 23:59:59.9999999 (Utc)
StartOfDay() returns the same value as the built-in date.Date property. It exists so the code reads the same way as EndOfDay().
SQL Server's datetime type cannot store 23:59:59.9999999; it rounds it up to midnight of the next day, so a filter <= dayEnd can include the next day's rows. For queries, a half-open range (>= dayStart and < dayStart.AddDays(1)) is safer. datetime2 stores the full value.
StartOfWeek and EndOfWeek
StartOfWeek returns midnight on the first day of the week that contains the date. Weeks start on Monday by default (ISO 8601). Pass firstDayOfWeek for a different start day, for example DayOfWeek.Sunday in the United States.
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc); // a Wednesday
DateTime weekStart = orderedAt.StartOfWeek(); // → 2024-05-13 00:00:00 (Monday)
DateTime weekEnd = orderedAt.EndOfWeek(); // → 2024-05-19 23:59:59.9999999 (Sunday)
DateTime usWeekStart = orderedAt.StartOfWeek(DayOfWeek.Sunday); // → 2024-05-12 00:00:00 (Sunday)
DateTime usWeekEnd = orderedAt.EndOfWeek(DayOfWeek.Sunday); // → 2024-05-18 23:59:59.9999999 (Saturday)
A Sunday belongs to the week that started the Monday before: new DateTime(2024, 5, 19).StartOfWeek() returns 2024-05-13.
StartOfMonth and EndOfMonth
EndOfMonth knows how many days each month has, including February in leap years.
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime periodStart = orderedAt.StartOfMonth(); // → 2024-05-01 00:00:00 (Utc)
DateTime periodEnd = orderedAt.EndOfMonth(); // → 2024-05-31 23:59:59.9999999 (Utc)
DateTime leapFebruaryEnd = new DateTime(2024, 2, 10).EndOfMonth(); // → 2024-02-29 23:59:59.9999999
DateTime februaryEnd = new DateTime(2023, 2, 10).EndOfMonth(); // → 2023-02-28 23:59:59.9999999
StartOfQuarter and EndOfQuarter
Calendar quarters start on January, April, July and October 1st. Fiscal years that start in another month are not supported.
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime quarterStart = orderedAt.StartOfQuarter(); // → 2024-04-01 00:00:00 (Utc)
DateTime quarterEnd = orderedAt.EndOfQuarter(); // → 2024-06-30 23:59:59.9999999 (Utc)
StartOfYear and EndOfYear
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime yearStart = orderedAt.StartOfYear(); // → 2024-01-01 00:00:00 (Utc)
DateTime yearEnd = orderedAt.EndOfYear(); // → 2024-12-31 23:59:59.9999999 (Utc)
Business days
These methods treat Monday to Friday as working days and Saturday and Sunday as the weekend.
The library does not know any holiday calendar. Holidays are counted as working days. If you need holidays, check the result against your own holiday list.
IsWeekend
IsWeekend() returns true when the date falls on a Saturday or a Sunday.
bool saturday = new DateTime(2024, 5, 18).IsWeekend(); // → true
bool friday = new DateTime(2024, 5, 17).IsWeekend(); // → false
AddBusinessDays
AddBusinessDays(days) moves forward by the given number of working days and skips weekends. A negative number moves back. The time of day is kept.
DateTime issuedOn = new DateTime(2024, 5, 17); // a Friday
DateTime dueOn = issuedOn.AddBusinessDays(10); // → 2024-05-31 00:00:00
DateTime fridayMorning = new DateTime(2024, 5, 17, 9, 30, 0);
DateTime nextWorkingDay = fridayMorning.AddBusinessDays(1); // → 2024-05-20 09:30:00 (Monday)
DateTime previousWorkingDay = new DateTime(2024, 5, 20).AddBusinessDays(-1); // → 2024-05-17 00:00:00 (Friday)
AddBusinessDays(0) returns the date unchanged, even when it is a Saturday or Sunday. From a Saturday, AddBusinessDays(1) returns the next Monday, and AddBusinessDays(5) returns the next Friday.
BusinessDaysUntil
BusinessDaysUntil(end) counts the working days after the start date, up to and including the end date. Only the date parts are used, so the time of day does not matter. The result is negative when end is earlier, and zero for the same day.
It is the inverse of AddBusinessDays: for a start date on a weekday, start.BusinessDaysUntil(start.AddBusinessDays(n)) returns n.
DateTime friday = new DateTime(2024, 5, 17);
int toMonday = friday.BusinessDaysUntil(new DateTime(2024, 5, 20)); // → 1
int toSunday = friday.BusinessDaysUntil(new DateTime(2024, 5, 19)); // → 0
int backwards = new DateTime(2024, 5, 20).BusinessDaysUntil(friday); // → -1
DateTime openedOn = new DateTime(2024, 5, 13);
int open = openedOn.BusinessDaysUntil(new DateTime(2024, 5, 31)); // → 14
int workingDaysIn2024 = new DateTime(2024, 1, 1).BusinessDaysUntil(new DateTime(2024, 12, 31)); // → 261
The start date is never counted. In 2024, January 1st is a Monday, so the year has 262 weekdays and the call above returns 261. To include the start day, count from the day before: start.AddDays(-1).BusinessDaysUntil(end).
Age
Age(today) returns the number of completed years between a birth date and today. Only the date parts are compared. Someone born on February 29 has a birthday on February 28 in non-leap years.
DateTime birthDate = new DateTime(2000, 6, 15);
int dayBefore = birthDate.Age(new DateTime(2024, 6, 14)); // → 23
int onBirthday = birthDate.Age(new DateTime(2024, 6, 15)); // → 24
DateTime leapBirthDate = new DateTime(2000, 2, 29);
int leapAge = leapBirthDate.Age(new DateTime(2023, 2, 28)); // → 23
int leapAgeDayBefore = leapBirthDate.Age(new DateTime(2023, 2, 27)); // → 22
Age throws ArgumentOutOfRangeException (parameter today) when today is before the birth date.
Relative time
ToRelativeTime
ToRelativeTime(reference) describes a moment relative to reference ("now") in English: "just now", "5 minutes ago", "yesterday", "in 3 days". Use it for activity feeds, comment timestamps and "last seen" labels.
DateTime now = new DateTime(2024, 5, 15, 12, 0, 0, DateTimeKind.Utc);
string a = now.AddSeconds(-10).ToRelativeTime(now); // → "just now"
string b = now.AddMinutes(-5).ToRelativeTime(now); // → "5 minutes ago"
string c = now.AddHours(-3).ToRelativeTime(now); // → "3 hours ago"
string d = now.AddDays(-1).ToRelativeTime(now); // → "yesterday"
string e = now.AddDays(-3).ToRelativeTime(now); // → "3 days ago"
string f = now.AddDays(61).ToRelativeTime(now); // → "in 2 months"
string g = now.AddMinutes(5).ToRelativeTime(now); // → "in 5 minutes"
string h = now.AddDays(1).ToRelativeTime(now); // → "tomorrow"
string i = now.AddDays(-730).ToRelativeTime(now); // → "2 years ago"
The distance between the two moments picks the wording. Past moments get "… ago", future moments get "in …".
| Distance | Text |
|---|---|
| under 45 seconds | just now |
| 45 to 90 seconds | a minute |
| 90 seconds to 45 minutes | N minutes |
| 45 to 90 minutes | an hour |
| 90 minutes to 22 hours | N hours |
| 22 to 36 hours | yesterday / tomorrow |
| 36 hours to 26 days | N days |
| 26 to 45 days | a month |
| 45 to 320 days | N months (a month counts as 30.44 days) |
| 320 to 548 days | a year |
| 548 days or more | N years (a year counts as 365.25 days) |
N is rounded to the nearest whole number (halves round up) and is at least 2.
"yesterday"means 22 to 36 hours ago, not "the previous calendar day". A moment from 23:00 last night, seen at 08:00, is"9 hours ago".- The text is always English and does not depend on the current culture.
- The method subtracts the two values as they are. Pass a
referencewith the sameKindas the value, for example both UTC.
Date ranges
To
start.To(end) walks from start to end one day at a time and keeps the start's time of day. Every step that is not after end is included. start.To(end, step) walks in steps of any positive TimeSpan. Both are lazy sequences, so you can use them in foreach or LINQ.
For whole calendar days, pass dates without a time. Then both ends are included.
DateTime checkIn = new DateTime(2024, 5, 1, 14, 30, 0);
DateTime checkOut = new DateTime(2024, 5, 3, 9, 0, 0);
List<DateTime> nights = checkIn.Date.To(checkOut.Date).ToList();
// → [2024-05-01, 2024-05-02, 2024-05-03]
If start has a time of day and end is midnight, the last day is left out, because 2024-05-03 14:30 is after 2024-05-03 00:00:
DateTime start = new DateTime(2024, 5, 1, 14, 30, 0);
DateTime end = new DateTime(2024, 5, 3);
List<DateTime> days = start.To(end).ToList();
// → [2024-05-01 14:30:00, 2024-05-02 14:30:00]
With a step, the sequence includes end only when a step lands on it exactly:
DateTime opening = new DateTime(2024, 5, 15, 9, 0, 0);
List<string> slots = opening
.To(opening.AddHours(2), 30.Minutes())
.Select(slot => slot.ToString("HH:mm", CultureInfo.InvariantCulture))
.ToList();
// → ["09:00", "09:30", "10:00", "10:30", "11:00"]
List<string> uneven = opening
.To(opening.AddHours(1), 25.Minutes())
.Select(slot => slot.ToString("HH:mm", CultureInfo.InvariantCulture))
.ToList();
// → ["09:00", "09:25", "09:50"]
30.Minutes() comes from the Durations page; TimeSpan.FromMinutes(30) works the same way.
- The sequence is empty when
endis beforestart. - A zero or negative
stepthrowsArgumentOutOfRangeException(parameterstep) when you callTo, not when you start the loop. - The walk stops at
DateTime.MaxValueinstead of overflowing. - Every item keeps the
Kindofstart.
See foreach and deconstruction for more on looping over dates.
Calendar numbers
Quarter
Quarter() returns the calendar quarter: 1 for January to March, 2 for April to June, 3 for July to September, 4 for October to December.
int q2 = new DateTime(2024, 5, 15).Quarter(); // → 2
int q4 = new DateTime(2024, 11, 2).Quarter(); // → 4
string label = $"Q{new DateTime(2024, 5, 15).Quarter()} 2024"; // → "Q2 2024"
WeekOfYear
WeekOfYear() returns the ISO 8601 week number, 1 to 53. ISO weeks start on Monday, and week 1 is the week that contains the first Thursday of the year. It returns the same value as ISOWeek.GetWeekOfYear(date).
int week = new DateTime(2024, 5, 15).WeekOfYear(); // → 20
int newYearsDay = new DateTime(2027, 1, 1).WeekOfYear(); // → 53
int lateDecember = new DateTime(2024, 12, 30).WeekOfYear(); // → 1
Around New Year, the ISO week belongs to the neighbouring year: 2027-01-01 is in week 53 of 2026, and 2024-12-30 is in week 1 of 2025. When you build a label such as 2026-W53, take the year from ISOWeek.GetYear(date) (namespace System.Globalization), not from date.Year.
Weekday lookups
Next and Previous
Next(dayOfWeek) returns the next date that falls on that weekday. It is always after the date, so a Friday's next Friday is 7 days later. Previous(dayOfWeek) works the same way backwards. Both keep the time of day.
DateTime orderedAt = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc); // a Wednesday
DateTime nextFriday = orderedAt.Next(DayOfWeek.Friday); // → 2024-05-17 14:30:15 (Utc)
DateTime nextWednesday = orderedAt.Next(DayOfWeek.Wednesday); // → 2024-05-22 14:30:15 (Utc)
DateTime lastMonday = orderedAt.Previous(DayOfWeek.Monday); // → 2024-05-13 14:30:15 (Utc)
DateTime lastWednesday = orderedAt.Previous(DayOfWeek.Wednesday); // → 2024-05-08 14:30:15 (Utc)
Both cross month and year boundaries: new DateTime(2024, 1, 1).Previous(DayOfWeek.Friday) returns 2023-12-29.
Step back one day first: date.Date.AddDays(-1).Next(DayOfWeek.Friday). On a Friday this returns the same day; on any other day it returns the coming Friday. The .Date makes the result midnight; leave it out to keep the original time of day.
NthWeekdayOfMonth
NthWeekdayOfMonth(dayOfWeek, occurrence) returns the first, second, third, fourth or fifth given weekday in the date's month, at midnight. Every month has at least four of each weekday, but not always five; the method returns null when the fifth one does not exist. Use it for rules such as "the second Tuesday" or "the fourth Thursday of November".
DateTime may = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime? releaseDay = may.NthWeekdayOfMonth(DayOfWeek.Tuesday, 2); // → 2024-05-14 00:00:00 (Utc)
DateTime? firstMonday = may.NthWeekdayOfMonth(DayOfWeek.Monday, 1); // → 2024-05-06 00:00:00 (Utc)
DateTime? fifthFriday = may.NthWeekdayOfMonth(DayOfWeek.Friday, 5); // → 2024-05-31 00:00:00 (Utc)
DateTime? fifthMonday = may.NthWeekdayOfMonth(DayOfWeek.Monday, 5); // → null
DateTime? thanksgiving = new DateTime(2024, 11, 1).NthWeekdayOfMonth(DayOfWeek.Thursday, 4); // → 2024-11-28 00:00:00
The receiver can be any date in the month. The result keeps its Kind.
An occurrence outside 1 to 5 throws ArgumentOutOfRangeException (parameter occurrence).
LastWeekdayOfMonth
LastWeekdayOfMonth(dayOfWeek) returns the last given weekday in the date's month, at midnight. It never returns null.
DateTime may = new DateTime(2024, 5, 15, 14, 30, 15, DateTimeKind.Utc);
DateTime payday = may.LastWeekdayOfMonth(DayOfWeek.Friday); // → 2024-05-31 00:00:00 (Utc)
DateTime lastSaturday = may.LastWeekdayOfMonth(DayOfWeek.Saturday); // → 2024-05-25 00:00:00 (Utc)
DateTime memorialDay = new DateTime(2024, 5, 1).LastWeekdayOfMonth(DayOfWeek.Monday); // → 2024-05-27 00:00:00
DateTime leapThursday = new DateTime(2024, 2, 3).LastWeekdayOfMonth(DayOfWeek.Thursday); // → 2024-02-29 00:00:00
Comparing periods
IsSameDay(other), IsSameWeek(other) and IsSameMonth(other) check whether two moments fall in the same calendar period. The time of day does not matter. IsSameMonth also compares the year, so May 2024 and May 2023 are different months.
IsSameWeek uses Monday-to-Sunday weeks. The overload IsSameWeek(other, firstDayOfWeek) lets you choose the first day.
bool sameDay = new DateTime(2024, 5, 15, 8, 0, 0).IsSameDay(new DateTime(2024, 5, 15, 23, 0, 0)); // → true
bool sameMonth = new DateTime(2024, 5, 1).IsSameMonth(new DateTime(2024, 5, 31, 23, 0, 0)); // → true
bool otherYear = new DateTime(2024, 5, 15).IsSameMonth(new DateTime(2023, 5, 15)); // → false
DateTime sunday = new DateTime(2024, 5, 19);
DateTime monday = new DateTime(2024, 5, 20);
bool isoWeek = sunday.IsSameWeek(monday); // → false
bool usWeek = sunday.IsSameWeek(monday, DayOfWeek.Sunday); // → true
These methods compare the calendar fields only. A UTC value and a local value with the same date are "the same day" even if they are hours apart in real time. Convert both values to the same zone first.
Unix time
ToUnixTimeSeconds and ToUnixTimeMilliseconds
ToUnixTimeSeconds() returns the seconds since 1970-01-01 00:00:00 UTC, the same number that DateTimeOffset.ToUnixTimeSeconds() gives. ToUnixTimeMilliseconds() returns milliseconds, the number JavaScript's Date.now() uses. Use them for JWT claims, API payloads and log correlation.
DateTime createdAt = new DateTime(2024, 5, 15, 12, 0, 0, DateTimeKind.Utc);
long seconds = createdAt.ToUnixTimeSeconds(); // → 1715774400
DateTime paidAt = new DateTime(2024, 5, 15, 12, 0, 0, 250, DateTimeKind.Utc);
long milliseconds = paidAt.ToUnixTimeMilliseconds(); // → 1715774400250
How the Kind is handled:
Utcvalues are used as they are.Localvalues are converted to UTC first.Unspecifiedvalues are treated as UTC. The machine's time zone is never used.
Fractions are dropped toward the earlier second or millisecond. Moments before 1970 give negative numbers: half a second before the epoch is -1.
new DateTimeOffset(value) treats an Unspecified value as local time, so new DateTimeOffset(value).ToUnixTimeSeconds() can differ from value.ToUnixTimeSeconds() by your UTC offset. This library treats Unspecified as UTC, so the result does not depend on the server's time zone.
FromUnixTimeSeconds and FromUnixTimeMilliseconds
FromUnixTimeSeconds() and FromUnixTimeMilliseconds() are extension methods on long. They return a DateTime with Kind set to Utc.
DateTime created = 1715774400L.FromUnixTimeSeconds(); // → 2024-05-15 12:00:00 (Utc)
DateTime paid = 1715774400250L.FromUnixTimeMilliseconds(); // → 2024-05-15 12:00:00.250 (Utc)
long expiresAt = 1715778000; // e.g. a JWT "exp" claim
DateTime expiry = expiresAt.FromUnixTimeSeconds(); // → 2024-05-15 13:00:00 (Utc)
C# does not widen the receiver of an extension method, so 1715774400.FromUnixTimeSeconds() does not compile: the literal is an int. Write 1715774400L, cast to long, or use a long variable.
With a C# 14 compiler you can also call them as static members on DateTime, like DateTimeOffset has: DateTime.FromUnixTimeSeconds(1715774400). See Extension members.
A value outside the DateTime range (years 0001 to 9999) throws ArgumentOutOfRangeException with the parameter name seconds or milliseconds.
Rounding to an interval
RoundTo, FloorTo and CeilingTo move a moment to a multiple of any positive TimeSpan. Use them to bucket events into 15-minute slots, snap a booking to the hour or group metrics by day. They keep the Kind.
Multiples are counted from DateTime.MinValue (0001-01-01 00:00). Intervals that divide a day evenly, such as 5 minutes, 15 minutes, 1 hour or 1 day, therefore line up with the clock and the calendar.
RoundTo
RoundTo(interval) returns the nearest multiple. A value exactly halfway rounds up.
DateTime a = new DateTime(2024, 5, 15, 10, 7, 0).RoundTo(15.Minutes()); // → 2024-05-15 10:00:00
DateTime b = new DateTime(2024, 5, 15, 10, 8, 0).RoundTo(15.Minutes()); // → 2024-05-15 10:15:00
DateTime c = new DateTime(2024, 5, 15, 10, 7, 30).RoundTo(15.Minutes()); // → 2024-05-15 10:15:00 (midpoint)
DateTime d = new DateTime(2024, 5, 15, 23, 53, 0).RoundTo(15.Minutes()); // → 2024-05-16 00:00:00
DateTime e = new DateTime(2024, 5, 15, 12, 0, 0).RoundTo(1.Days()); // → 2024-05-16 00:00:00
FloorTo
FloorTo(interval) rounds down to the previous multiple, or returns the value unchanged when it is already a multiple. This is the usual choice for bucketing events.
DateTime viewedAt = new DateTime(2024, 5, 15, 10, 59, 59);
DateTime bucket = viewedAt.FloorTo(15.Minutes()); // → 2024-05-15 10:45:00
DateTime loggedAt = new DateTime(2024, 5, 15, 10, 8, 0, DateTimeKind.Utc);
DateTime hour = loggedAt.FloorTo(1.Hours()); // → 2024-05-15 10:00:00 (Utc)
CeilingTo
CeilingTo(interval) rounds up to the next multiple, or returns the value unchanged when it is already a multiple.
DateTime a = new DateTime(2024, 5, 15, 10, 1, 0).CeilingTo(15.Minutes()); // → 2024-05-15 10:15:00
DateTime b = new DateTime(2024, 5, 15, 10, 46, 0).CeilingTo(15.Minutes()); // → 2024-05-15 11:00:00
DateTime c = new DateTime(2024, 5, 15, 10, 15, 0).CeilingTo(15.Minutes()); // → 2024-05-15 10:15:00
- A zero or negative interval throws
ArgumentOutOfRangeException(parameterinterval). RoundToandCeilingTothrowArgumentOutOfRangeExceptionwhen the result would be afterDateTime.MaxValue, for exampleDateTime.MaxValue.CeilingTo(1.Hours()).- For weeks, use
StartOfWeek.FloorTo(7.Days())happens to land on a Monday, because 0001-01-01 was a Monday, but it cannot start weeks on another day, andRoundTo(7.Days())goes to the nearest Monday, which may be in the next week. - To round a
TimeSpaninstead of aDateTime, see Durations.
See also
- Durations:
5.Minutes(),Before/After, human-readable durations andTimeSpanrounding. - foreach and deconstruction:
(int year, int month, int day) = date;. - Extension members: the C# 14 static
DateTime.FromUnixTimeSeconds. - Conventions: argument checks, invariant formatting and why nothing reads the clock.