tags:

views:

695

answers:

6

I'm sure this is very easy, but I've got a sudden mental block.... I'm trying to get a DateTime object for the next occurence of 3am... for example, if DateTime.Now is 16/july/2009 : 12:04pm - the next occurance of 3am would be 17/july/2009 : 03:00

However, if DateTime.Now was 17/july/2009 : 01:00 then the next occurence would still be 17/july/2009 : 03:00 (not the day after) does that make sense?

A: 

Dunno a shortcut but you could clone the datetime object you're checking, set the time to 3am and see if its before or after the one you're checking

David Archer
+10  A: 

One option:

DateTime now = DateTime.Now;
DateTime today3am = now.Date.AddHours(3);
DateTime next3am = now <= today3am ? today3am : today3am.AddDays(1);

Another:

DateTime now = DateTime.Now;
DateTime today = now.Date;
DateTime next3am = today.AddHours(3).AddDays(now.Hour >= 3 ? 1 : 0)

Lots of ways of skinning that particular cat :)

This is all in local time of course, which means you don't need to worry about time zones. Life becomes trickier if you want to get time zones involved...

Note that it's a good idea to take DateTime.Now once to avoid problems if the date rolls over while you're calculating...

Jon Skeet
`DateTime today3am = DateTime.Today.AddHours(3);`
Blixt
Definetely i hate this way to do an inline if, and the lambda expressions... really not developper friendly to read :/. However this works just fine.
Clement Herreman
Good point about taking `Now` once and re-using it. I made that mistake yesterday in an answer, and Eric Lippert called me out for it!
LukeH
@Clement H: What lambda expressions?
LukeH
@Blixt: Yes, that's nicer for the second line - will edit.
Jon Skeet
@ClementH: I prefer the conditional approach to a reassignment... I'm coming round to the functional way of thinking :) Basically the logic is that it's *either* today at 3am *or* tomorrow at 3am, depending on a condition. That situation is crying out for the conditional operator.
Jon Skeet
@Jon: It's actually safe to mix `DateTime.Now` and `DateTime.Today` (i.e. two gets of the current time) in this case, but is there a performance penalty for doing so vs. storing it once?
Blixt
perfect, thanks
alex
@Blixt: No, if you get the current date/time twice in the calculation, you risk that it has changed in between. The risk is small so it won't happen often, but there is no reason to let it happen at all.
Guffa
@Clement H: The conditional operator is actually not needed (see my answer below(/above)). It's not a lambda expression in Jon's code, it's just the greater than or equal operator.
Guffa
@Guffa: I'm well aware that it might change. But as I said, in this case it's safe because all that will happen is that the conditional will result in the other value (i.e. if `Today` is 17th and `Now` is 18th it'll return `today3am.AddDays(1)` instead of `today3am`.)
Blixt
Disclaimer: If the code stops executing (hangs) before the date changes, and does not continue until 3am or later the next day, you will indeed have a problem with fetching the time twice.
Blixt
+3  A: 
DateTime now = DateTime.Now;
DateTime threeAM = now.Date.AddHours(3);

if (threeAM < now)
    threeAM = threeAM.AddDays(1);
LukeH
A: 

An alternative (using a function):

DateTime NextAt(TimeSpan time)
{
  DateTime now = DateTime.Now;
  DateTime result = now.Date + time;

  return (now <= result) ? result : result.AddDays(1);
}

call it like:

DateTime next3am = NextAt(new TimeSpan(3,0,0));
Philippe Leybaert
+1  A: 

You can do it without an if statement (or conditional operator):

// get the current time
DateTime now = DateTime.Now;
// get a 3:00 AM point in time in the future
DateTime next = now.Date.AddHours(24 + 3);
// subtract the number of whole extra days
next = next.AddDays((now - next).Days);

I always explain that you should get the point in time (DateTime.Now) only once in a calculation like this, as it's a changing value, so do I have to repeat it? Well, I just did. ;)

Guffa
+1  A: 
//just add 24 - 3 = 21 hours and get Today (start of day) and Add 3 hour

DateTime now = DateTime.Now.AddHours(21).Today.AddHours(3);
Chernikov
+1: good thinking, although it fails if it is exactly 3:00am (although it is debatable if this should return the next day or not)
Philippe Leybaert