22

Using C#, how may I get the time remaining (before the elapse event will occur) from a System.Timers.Timer object?

In other words, let say I set the timer interval to 6 hours, but 3 hours later, I want to know how much time is remaining. How would I get the timer object to reveal this time remaining?

stop-cran
  • 4,229
  • 2
  • 30
  • 47
Lonnie Best
  • 9,936
  • 10
  • 57
  • 97

3 Answers3

37

The built-in timer doesn't provide the time remaining until elapse. You'll need to create your own class which wraps a timer and exposes this info.

Something like this should work.

public class TimerPlus : IDisposable
{
    private readonly TimerCallback _realCallback;
    private readonly Timer _timer;
    private TimeSpan _period;
    private DateTime _next;

    public TimerPlus(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
    {
        _timer = new Timer(Callback, state, dueTime, period);
        _realCallback = callback;
        _period = period;
        _next = DateTime.Now.Add(dueTime);
    }

    private void Callback(object state)
    {
        _next = DateTime.Now.Add(_period);
        _realCallback(state);
    }

    public TimeSpan Period => _period;
    public DateTime Next => _next;
    public TimeSpan DueTime => _next - DateTime.Now;

    public bool Change(TimeSpan dueTime, TimeSpan period)
    {
        _period = period;
        _next = DateTime.Now.Add(dueTime);
        return _timer.Change(dueTime, period);
    }

    public void Dispose() => _timer.Dispose();
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
  • Above and beyond the call, but checked you for your efforts. Thanks, you are very kind. I already have a method that will calculate how much time should be remaining, but wanted to confirm it with output from the actual timer object itself. To bad it isn't inherently provided. – Lonnie Best Feb 17 '10 at 06:26
  • 3
    Yeah, he wrote that fast too. Impressive. – Lonnie Best Feb 17 '10 at 06:34
  • Samuel, could you provide the usage of this class? I am unsure how to pass in the parameters to your constructor. – Hesein Burg Jun 24 '16 at 00:50
  • @HeseinBurg `TimerPlus` is a drop-in replacement for `Timer` (meaning you can use `TimerPlus` as-is wherever you use `Timer`). It has the same functionality and API. The addition is the `Next` property which will always return the `DateTime` that it will next be triggered. – Samuel Neff Jun 26 '16 at 00:56
  • Wouldn't this result in a bug in case the user would change the system time while the timer is running? – Tohnmeister Apr 06 '23 at 00:53
  • @Tohnmeister Yes. The timer will not actually fire at the wrong time but `Next` and `DueTime` will both be wrong until the next timer tick. – Samuel Neff Apr 13 '23 at 23:53
22

I am aware, that the topic is more than 3 years old. However I came across it while tackling exactly the same problem.

Inspired by Samuel Neff, I came up with a WinForms-less solution by extending the standard System.Timers.Timer class:

public class TimerPlus : System.Timers.Timer
{
    private DateTime m_dueTime;

    public TimerPlus() : base() => this.Elapsed += this.ElapsedAction;

    protected new void Dispose()
    {
        this.Elapsed -= this.ElapsedAction;
        base.Dispose();
    }

    public double TimeLeft => (this.m_dueTime - DateTime.Now).TotalMilliseconds;
    public new void Start()
    {
        this.m_dueTime = DateTime.Now.AddMilliseconds(this.Interval);
        base.Start();
    }

    private void ElapsedAction(object sender, System.Timers.ElapsedEventArgs e)
    {
        if (this.AutoReset)
            this.m_dueTime = DateTime.Now.AddMilliseconds(this.Interval);
    }
}

I hope it helps.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
Mike
  • 1,225
  • 10
  • 21
17

I guess the best method is to hold the start time in a variable and then calculate the elapsed time as

TimeSpan t = DateTime.Now - StartTime;
anaconda
  • 1,065
  • 10
  • 20