3

I feel like this is something really simple, but my Google Fu is letting me down as I keep finding difference calculations.

I have a time (e.g. 1800 hours) stored in a DateTime object. The date is null and immaterial. All I want to know is how many milliseconds until the NEXT occurrence of that time.

So, if I run the calculation at 0600 - it will return 12 hours (in ms). At 1750, it will return ten minutes (in ms) and at 1900 it will return 24 hours (in ms).

All the things I can find show me how to calculate differences, which doesn't work once you're past the time.

Here is what I tried, but fails once you're past the time and gives negative values:

DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
4

2 回答 2

4

You're already doing everything you should, except for one thing: handling negative results.

If the result is negative, it means the time you want to calculate the duration until has already passed, and then you want it to mean "tomorrow" instead, and get a positive value.

In this case, simply add 24 hours:

DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result < 0)
    result += TimeSpan.FromHours(24).TotalMilliseconds;

The next thing to consider is this: If the time you want to calculate the duration until is 19:00 hours, and the current time is exactly 19:00 hours, do you want it to return 0 (zero) or 24 hours worth of time? Meaning, do you really want the next such occurrence?

If so, then change the above if-statement to use <=:

DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result <= 0)
    result += TimeSpan.FromHours(24).TotalMilliseconds;

However, note that this will be prone to the usual problems with floating point values. If the current time is 18:59:59.9999999, do you still want it to return the current time (a minuscule portion of time) until 19:00 today, or do you want it to flip to tomorrow? If so, change the comparison to be slightly different:

DateTime nowTime = DateTime.Now;
TimeSpan difference = _shutdownTime.TimeOfDay - nowTime.TimeOfDay;
double result = difference.TotalMilliseconds;
if (result <= -0.0001)
    result += TimeSpan.FromHours(24).TotalMilliseconds;

where -0.0001 is a value that corresponds to "the range of inaccuracy you're prepared to accept being tomorrow instead of today in terms of milliseconds".

于 2013-06-29T18:30:59.447 回答
2

When doing calculations like this it is important to take possible DST changes under consideration so that your results remain correct.

Suppose your operational parameters are:

var shutdownTime = TimeSpan.FromHours(18);
// just to illustrate, in Europe there is a DST change on 2013-10-27
// normally you 'd just use DateTime.Now here
var now = new DateTime(2013, 10, 26, 20, 00, 00);

// do your calculations in local time
var nextShutdown = now.Date + shutdownTime;
if (nextShutdown < now) {
    nextShutdown = nextShutdown.AddDays(1);
}

// when you want to calculate time spans in absolute time
// (vs. wall clock time) always convert to UTC first
var remaining = nextShutdown.ToUniversalTime() - now.ToUniversalTime();
Console.WriteLine(remaining);

The answer to your question would now be remaining.TotalMilliseconds.

于 2013-06-29T19:25:39.173 回答