The following c# code is supposed to return a timespan that indicates how much time there is between the current time and the next occurence of an event, supposed to happen at 5am. It must handle the case when the code is called before or after 5am.
The code manages to return negative delays on our servers (+1GMT) between 4 and 5am, which I cannot comprehend. Would anyone know what the explanation is ?
TimeSpan EverydayAt(int hourOfDay)
{
DateTimeOffset now = DateTimeOffset.UtcNow;
DateTimeOffset nextTime = now.Date.AddDays(now.Hour < hourOfDay ? 0 : 1).AddHours(hourOfDay);
TimeSpan delay = nextTime - now;
return delay;
}
Would anyone know what the explanation is ?
To expound the issue is coming in from this line.
now.Date.AddDays(now.Hour < hourOfDay ? 0 : 1).AddHours(hourOfDay);
This is a DateTime
object unbeknownst to you, you are actually doing an implicit conversion to the DateTimeOffset
object nextTime
.
This nextTime
object created will have an Offset
of 1 hour since "our servers(+1GMT)".
So essentially time close to 5am (1 hr and less) will generate a DateTimeOffset
object of the current day with an Offset
of 1 hour which you compared with now
(DateTimeOffset
object of the current day with an Offset
of 0 hours).
Alternative solution:
Is to convert it back to a DateTimeOffset
with zero Offset
int hourOfDay = 15;
DateTimeOffset now = DateTimeOffset.UtcNow;
DateTimeOffset nextTime = new DateTimeOffset(now.Date.AddDays(now.Hour < hourOfDay ? 0 : 1).AddHours(hourOfDay), TimeSpan.Zero);
TimeSpan delay = nextTime - now;
Additional Info
Conversions from DateTime to DateTimeOffset
The DateTimeOffset structure provides two equivalent ways to perform DateTime to DateTimeOffset conversion that are suitable for most conversions:
- The DateTimeOffset constructor, which creates a new DateTimeOffset object based on a DateTime value.
- The implicit conversion operator, which allows you to assign a DateTime value to a DateTimeOffset object.
An Implicit conversion is what you're doing on that line.
However, for DateTime values whose Kind property is DateTimeKind.Unspecified, these two conversion methods produce a DateTimeOffset value whose offset is that of the local time zone.