My understanding is that DateTime.Today
gives the time of midnight today in the local timezone.
That is mostly correct, but has an edge case. It will indeed give you the current date, using the local time zone in determining it, with the time set to 00:00:00.0000000
. The resulting .Kind
will be DateTimeKind.Local
. What it does is equivalent to any of the following:
DateTime.Now.Date
DateTime.UtcNow.ToLocalTime().Date
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).Date
// etc.
(See Difference between System.DateTime.Now and System.DateTime.Today for a complete list.)
Notice in all my examples, .Date
is last. That property simply sets the time to zero. It keeps the .Kind
, but it doesn't evaluate it in any way.
Where the edge case comes into play is if you are dealing with a time zone which has a transition at midnight - where the clocks go from 23:59
to 01:00
. Since there is no 00:00
, then the result from DateTime.Today
will be a local time that doesn't exist. One such example is Santiago, Chile on 2019-09-08
. Midnight doesn't exist there on that day.
Does DateTime.Today.AddDays(1)
always give midnight tomorrow in the local timezone, or will it sometimes be off due to daylight savings?
i.e is .AddDays(1) == .AddHours(24)
, or is it sometimes different as it adjusts for daylight savings.
Neither the AddDays
or AddHours
functions take time zone into account. They both simply add exactly 24 hours. Like the .Date
property, these functions retain the .Kind
, but they do not evaluate it in way.
If .AddDays(1) == .AddHours(24)
, is there a way to get the time of midnight tomorrow local (which may be 23, 24 or 25 hours from now)?
Keeping in mind that midnight might not exist, as mentioned earlier, you simply need to adjust for that possibility. Here is an extension method to do that using only DateTime
:
static DateTime AdjustToValidTime(this DateTime dt, TimeZoneInfo tz)
{
if (!tz.IsInvalidTime(dt))
{
// The time is already valid
return dt;
}
// Get the adjustment rule that applies
var rule = tz.GetAdjustmentRules()
.First(x => x.DateStart <= dt && x.DateEnd > dt);
// Get the transition gap. Often will be one hour, but not always
TimeSpan gap = rule.DaylightDelta;
// Add the gap to adjust to a valid time
return dt.Add(gap);
}
You could use it like this (for example):
DateTime tomorrow = DateTime.Today.AddDays(1).AdjustToValidTime(TimeZoneInfo.Local);
If you want to see the case of a day without midnight, you can use it like this:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific SA Standard Time");
DateTime today = new DateTime(2019, 9, 8);
DateTime adjusted = today.AdjustToValidTime(tz); // Will be 2019-09-08 01:00