Click here to Skip to main content
15,879,096 members
Articles / Programming Languages / C#

Midnight Timer - A Way to Detect When it is Midnight

Rate me:
Please Sign up or sign in to vote.
2.85/5 (30 votes)
29 Mar 2007CPOL4 min read 91.7K   1.6K   13   21
An article on how to detect when it is midnight

Introduction

I'm sure that a large percentage of developers have wished for a way to detect when it is midnight on a machine and execute code which updates something simple and non complex (i.e. display dates, instead of "Today" you would want it to show "Yesterday" and so forth).

I pondered over this for some time until I had inspiration one late night. Let's use a Timer to do it, but with some intelligence.

Background

While working on a larger project, I needed a way to ensure that an event would fire which would execute code to update the displayed days (much how Outlook displays emails by date) at midnight.

I thought of various methods to accomplish this. Check the datetime every second.. no, Check the time ever x hours... no... Just loop until midnight is reached... no!

Each way I thought of included heavy looping or polling in order to check the time to know when it turns midnight. So a new approach was needed.

I realised that I could use a system Timer to achieve what I wanted without reinventing the wheel.

Using the Code

I've designed the code in a simplistic way in order for you to use the code more effectively.

I have contained the logic in a single class, which has 3 public method, Start(), Restart() and Stop().

When the class is first executed via the Start() method, the code obtains a datetime of the current time, then gets a datetime object of midnight and subtracts the 2 times in order to give a time until it is midnight.

With this time, it sets the timer interval and starts the timer. Now when the interval is reached and the timer fires its event, I reset the timer using the same process. This will make the interval for 24. When this timer expires, it is then reset and repeated indefinitely.

To use the class in your code, simply add these lines.

Insert the following into the method you wish to call the Timer from:

C#
// Create the instance of the timer
MidnightTimer m_MidnightTimer = new MidnightTimer();

// Set the Event Handler to be fired when it is midnight
m_MidnightTimer.TimeReached += new TimeReachedEventHandler(this.m_MidnightTimer_TimeReached);

// Start the Midnight Timer
m_MidnightTimer.Start();

Add the Event Handler method:

C#
private void m_MidnightTimer_TimeReached(DateTime Time)
{
    // do something here...
}

That's it! The timer will now execute the method m_MidnightTimer_TimeReached at Midnight.

Behind the scenes

Let's look at the main piece behind this code:

C#
public void Start()
{           
    // Subtract the current time, from midnight (tomorrow).
    // This will return a value, which will be used to set the Timer interval
    TimeSpan ts = this.GetMidnight(s_MinutesAfterMidnight).Subtract(DateTime.Now);

    // We only want the Hours, Minutes and Seconds until midnight
    TimeSpan tsMidnight = new TimeSpan(ts.Hours, ts.Minutes, ts.Seconds);

    // Create the Timer
    s_timer = new Timer(tsMidnight.TotalMilliseconds);

    // Set the event handler
    s_timer.Elapsed += new ElapsedEventHandler(this.timer_Elapsed);

    // Hook into when Windows Time changes
    // Thanks to Nicole1982 for the suggestion & BruceN for the help
    Microsoft.Win32.SystemEvents.TimeChanged += new EventHandler(this.WindowsTimeChangeHandler);

    // Start the timer
    s_timer.Start();
}

private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    // Stop the orginial timer
    s_timer.Stop(); // swapped order thanks to Jeremy

    // now raise a event that the timer has elapsed
    OnTimeReached(); // swapped order thanks to Jeremy

    // reset the timer
    this.Start();
}

 

Windows Time Change

Thanks to Nicole1982 and BruceN for this (see the comments).

When the time of Windows is changed, the timer picks it up and automatically resets for you.

This is done via the Microsoft.Win32.SystemEvents.TimeChanged event in the Start() method which invokes the WindowsTimeChangeHandlerWindowsTimeChangeHandler method, which simply calls the Restart() method.

C#
private void WindowsTimeChangeHandler(object sender, EventArgs e)
{
    // Please see https://connect.microsoft.com/VisualStudio/feedback/details/776003/systemevent-timechanged-is-fired-twice
    // The event is fired twice.. I assume 'once' for the change from the old system time and 'once' when the time has been changed.
    // i.e Event is fired when System time has Changed and is Changing

    // Restart the timer -> note as above, this is called twice
    this.Restart();
}

Note: This is a known issue with the Microsoft.Win32.SystemEvents.TimeChanged firing twice when the system is changed as outlined at https://connect.microsoft.com/VisualStudio/feedback/details/776003/systemevent-timechanged-is-fired-twice

Inside GetMidnight

As you can guess, the GetMidnight, simply returns midnight. Additionally the method allows for the supply of how many minutes after midnight you have

C#
private DateTime GetMidnight(int MinutesAfterMidnight)
{
    // Lets work out the next occurring midnight
    // Add 1 day and use hours 0, min 0 and second 0 (remember this is 24 hour time)

    // Thanks to Yashar for this code/fix
    DateTime Tomorrow = DateTime.Now.AddDays(1);

    // Return a datetime for Tomorrow, but with how many minutes after midnight
    return new DateTime(Tomorrow.Year, Tomorrow.Month, Tomorrow.Day, 0, MinutesAfterMidnight, 0);
}

What the Start() method actually does is obtain the current time and midnight of the next day (DateTime.Now.Day+1) and subtracts them to give us how many hours, minutes, seconds until midnight occurs. This is the value we use to set the initial timer to fire at midnight.

Now after a few hours pass by and it hits midnight, the timer fires and recalls Start() (as well as stops the original timer, etc.) and repeats the process of getting the time now, and the time of the next midnight (in this case, 24 hours) and resets the timer.

Minutes after Midnight

The timer also supports supplying how many minutes after midnights you would like it to fire at.

To enable this, simply supply how many minutes via an integer parameter in the midnight timer constructor overload.

C#
// Create the instance of the timer which will fire 10 minutes after midnight
MidnightTimer m_MidnightTimer = new MidnightTimer(10);

// Set the Event Handler to be fired when it is midnight
m_MidnightTimer.TimeReached += new TimeReachedEventHandler(this.m_MidnightTimer_TimeReached);

// Start the Midnight Timer
m_MidnightTimer.Start();

Version 2.0 Note

Recently I was involved in a project in which I needed this code again and having read the comments I took them on board and applied them to the code. Thanks to everyone who left constructive feedback, bug fixes and pointed me in the right direction to enhance this small but simple solution.

8 years is a long time! o_0 Happy coding!

Feedback

Feedback is most welcome! In fact I insist on it!

If you have any improvements or ideas on how to improve this code, please speak up and voice your opinion! It's a great way to learn!

History

  • 1.0.0.0 - 30/03/2007 - Initial version
  • 2.0.0.0 31/03/2015 - Bug fixes, Windows Timer Hook, More comments, updated article to reflect code changes

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Archon Gnosis
Australia Australia
Just a developer with a little bit of knowledge, constantly learning.

Comments and Discussions

 
QuestionCode Sollution Pin
fanourios siskakis12-Oct-17 21:28
fanourios siskakis12-Oct-17 21:28 
QuestionBug - Invalid interval exception when tsMidnight.totalMilliseconds = 0 Pin
TNoyce9-Sep-16 3:25
TNoyce9-Sep-16 3:25 
BugRe: Bug - Invalid interval exception when tsMidnight.totalMilliseconds = 0 Pin
DanielBrownAU25-Oct-16 12:57
professionalDanielBrownAU25-Oct-16 12:57 
Questionsmaller and better Pin
nimamoi5-Jul-11 3:51
nimamoi5-Jul-11 3:51 
GeneralException Pin
Member 283973230-Jul-09 19:08
Member 283973230-Jul-09 19:08 
GeneralRe: Exception Pin
Yashar Mortazavi31-May-13 8:07
Yashar Mortazavi31-May-13 8:07 
GeneralExcellent Pin
jrl237@yahoo.com21-Jul-08 9:14
jrl237@yahoo.com21-Jul-08 9:14 
GeneralBug and Suggestion Pin
jerms5530-Aug-07 22:51
jerms5530-Aug-07 22:51 
GeneralSystem.Threading.Timer Pin
Stanislav Simicek2-Apr-07 3:54
Stanislav Simicek2-Apr-07 3:54 
GeneralSource code missing Pin
TBermudez30-Mar-07 4:41
TBermudez30-Mar-07 4:41 
GeneralRe: Source code missing [modified] Pin
DanielBrownAU30-Mar-07 6:44
professionalDanielBrownAU30-Mar-07 6:44 
Hi.

Thanks for pointing this out. All fixed now Smile | :)

Daniel

Daniel Brown
Senior Solutiuons Architect

GeneralVotes Pin
NormDroid30-Mar-07 1:16
professionalNormDroid30-Mar-07 1:16 
GeneralRe: Votes Pin
Nish Nishant30-Mar-07 2:46
sitebuilderNish Nishant30-Mar-07 2:46 
GeneralRe: Votes Pin
DanielBrownAU30-Mar-07 2:47
professionalDanielBrownAU30-Mar-07 2:47 
GeneralRe: Votes Pin
NormDroid30-Mar-07 2:50
professionalNormDroid30-Mar-07 2:50 
GeneralRe: Votes Pin
DanielBrownAU30-Mar-07 6:29
professionalDanielBrownAU30-Mar-07 6:29 
GeneralBug Pin
nicole198229-Mar-07 22:27
nicole198229-Mar-07 22:27 
GeneralRe: Bug [modified] Pin
DanielBrownAU29-Mar-07 22:52
professionalDanielBrownAU29-Mar-07 22:52 
GeneralRe: Bug Pin
aridolan13-May-07 2:59
aridolan13-May-07 2:59 
GeneralRe: Bug Pin
BruceN16-Jun-07 15:41
BruceN16-Jun-07 15:41 
GeneralNice Pin
Zajda8229-Mar-07 21:55
Zajda8229-Mar-07 21:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.