18

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?

Shegit Brahm
  • 725
  • 2
  • 9
  • 22
Alex
  • 37,502
  • 51
  • 204
  • 332

6 Answers6

31

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 7
    `DateTime today3am = DateTime.Today.AddHours(3);` – Blixt Jul 17 '09 at 11:14
  • 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 Jul 17 '09 at 11:18
  • 1
    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 Jul 17 '09 at 11:19
  • 4
    @Clement H: What lambda expressions? – LukeH Jul 17 '09 at 11:20
  • 1
    @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 Jul 17 '09 at 11:21
  • @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 Jul 17 '09 at 11:23
  • @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 Jul 17 '09 at 11:52
  • @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 Jul 17 '09 at 12:01
  • @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 Jul 17 '09 at 12:17
  • 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 Jul 17 '09 at 15:04
5
DateTime now = DateTime.Now;
DateTime threeAM = now.Date.AddHours(3);

if (threeAM < now)
    threeAM = threeAM.AddDays(1);
LukeH
  • 263,068
  • 57
  • 365
  • 409
3
//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
  • 847
  • 1
  • 11
  • 21
1

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
  • 168,566
  • 31
  • 210
  • 223
1

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
  • 687,336
  • 108
  • 737
  • 1,005
0

I think this One:

DateTime.Now.Date.AddHours(3).AddMinutes(0).AddSeconds(0).AddDays(1);
Dot_NET Pro
  • 2,095
  • 2
  • 21
  • 38