As far as I can see none of the answers provided so far take daylight savings into account. At least in the area where I live there is a night in the spring where the clock on the wall will skip from 2 AM to 3 AM and another night in the autumn where the clock will skip from 3 AM and back to 2 AM once. Different countries will have different rules (or no daylight savings at all).
The spring night has one less hour in the local time zone so if the timestamp is before 2 AM the time difference until 8 AM local time is 1 hour less than you get by doing simple calculations.
In the same way the autumn night has one more hour in the local time zone so if the timestamp is before 2 AM the time difference until 8 AM local time is 1 hour more than you get by doing simple calculations. And even worse: if the local timestamp is between 2 AM and 3 AM it is ambiguous. Was it the first 2:30 AM or the second?
To solve the ambiguity you need to switch from using local DateTime
to DateTimeOffset
. When you use the later there is no ambiguity between the first time during the night the wall clock is 2:30 AM and the second time because they have different UTC offsets and the UTC offset is part of the DateTimeOffset
structure.
So here is some code that will take daylight savings into account:
var now = DateTimeOffset.Now;
if (now.Hour >= 20 || now.Hour < 8)
{
var midnightDateTime = now.Date.AddDays(now.Hour >= 20 ? 1 : 0);
var offsetMidnight = TimeZoneInfo.Local.GetUtcOffset(midnightDateTime);
var midnight = new DateTimeOffset(midnightDateTime, offsetMidnight);
var eightAmDateTime = new DateTime(midnight.Year, midnight.Month, midnight.Day, 8, 0, 0);
var offsetEightAm = TimeZoneInfo.Local.GetUtcOffset(eightAmDateTime);
var eightAm = new DateTimeOffset(eightAmDateTime, offsetEightAm);
var timeLeftUntilEightAm = eightAm - now;
}
When you work with DateTimeOffset
you have to be very careful when you mix them with DateTime
. There is an implicit conversion from DateTime
to DateTimeOffset
. If the kind of the DateTime
is Local
or Unspecified
the offset of the resulting DateTimeOffset
will be the offset of the local timezone. In the code above now.Date
has kind Unspecified
and if you do some arithmetic with this DateTime
and another DateTimeOffset
the conversion kicks in and the result may be off by the offset of your local timezone. That is probably not what you want and at least I have been bitten by this less than obvious conversion.