0

Using System.Windows.Form.Timer the interval is an int, which gives a maximum interval limit of around 25 days. I know I could create some arbitrary algorithm to start another timer once the limit is reached, but that's just daft.

MISLEADING-IGNORE-->So if I want to set it to around 29 days (2619609112.7228003) milliseconds?<--MISLEADING-IGNORE

EDIT:

The real question here is how can I set System.Windows.Form.Timer to a value higher than maxInt?

The purpose is that I need to set an interval from whenever to the first day of the next month, so it could be 28,29,30 or 31 days, and when that interval expires, calculate the interval to the next first day of the month.

(Basically a Crystal Report is to be run on the 1st day of the month and printed (around 500 pages), because of the length of the reports it is to be run out of hours so it doesn't tie up the printer.)

e.g. run it today (today is 1/12/15), 1/1/16 is next 'first day of the month' so set the interval to the milliseconds between now and then.

1/1/16 comes around so the timer ticks, then calculate and set the interval for 1/2/2016 (the next first day of the month).

@SeeSharp - I did see that question, but I am working on a legacy app and am unsure of the implications of changing the timer, but if I can't get this timer to work I may look at the threading one, thanks.

EDIT2: Thanks for all of your suggestions, I've opted for a 3rd party plugin called FluentScheduler

Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
  • 1
    Do you have to use `Windows.Form.Timer` as it appears `Threading.Timer` might solve it for you? http://stackoverflow.com/questions/1624789/maximum-timer-interval – SeeSharp Dec 02 '15 at 16:28
  • What is it that you want to have happen every 29 days? – Richard Ev Dec 02 '15 at 16:29
  • 2
    @PaulZahra what is the actual question here...? – MethodMan Dec 02 '15 at 16:29
  • 1
    `System.Threading.Timer` or `System.Timers.Timer` both seem to accept 64 bit intervals, though beware that they have different behaviors from a winforms timer. – Glorin Oakenfoot Dec 02 '15 at 16:30
  • 1
    Rather than having a timer waiting 29 days (time during which the application would have to be running non-stop), wouldn't it be better to base the time variations upon external resources (e.g., file, database, registry, etc.) which might be regularly check (e.g., every second with a timer)? Example: in the file time_to_got.txt, the application stores a down counter with the number of pending days; this file is updated/checked regularly (every min./sec/ms). As a general rule, if your algorithm needs to hit the max./min. value of a control (type, etc.), you are most likely not using it right. – varocarbas Dec 02 '15 at 16:39
  • Short answer: no. The interval is an int, so you can set it larger than `MaxValue`. Longer answer is that you probably have something very wrong with your design if you need a `System.Windows.Form.Timer` to time for that long. It's not what it was designed or intended for. @vacorcarbas suggestion is much better. Check the system time at some smaller interval. – Matt Burland Dec 02 '15 at 16:43
  • 3
    This is the wrong tool for the job. The forms timer is for triggering events on the order of seconds in the future, not weeks. If you need to trigger some event to happen on the first of the month, use workflow software specifically designed to solve that problem. – Eric Lippert Dec 03 '15 at 05:48

3 Answers3

1

Set the timer interval to one day (say) and use it to count the number of days up to 29.

Edit

Set the timer to half a day (say) and use it to check that the date is the first of the month.

Graham
  • 799
  • 2
  • 5
  • 14
1

How about a Month timer - This will fire close to midnight when the month changes. May be that suits your requirement better ? If we have to consider day-light saving too, then perhaps the timer should fire at 2:00 AM on the 1st day of month so I'll make it configurable.

Here is a code to explain my idea -

   public class MonthTimer : IDisposable
{

    public event EventHandler<MonthChangedEventArgs> MonthChanged;

    DateTime mLastTimerDate;
    Timer mTimer;

    public MonthTimer(TimeSpan timeOfFirstDay)
        : this(DateTime.Now, timeOfFirstDay)
    {
    }

    public MonthTimer(DateTime currentDate, TimeSpan timeOfFirstDay)
    {
        mLastTimerDate = currentDate.Date;
        var milliSecondsInDay = new TimeSpan(1, 0, 0, 0).TotalMilliseconds;

        Contract.Assert(timeOfFirstDay.TotalMilliseconds <= milliSecondsInDay); // time within 1st day of month            
        DateTime currentDateLastSecond = currentDate.Date.AddDays(1).AddTicks(-1);  // one tick before midnight 
        TimeSpan timeSpanInCurrentDate = currentDateLastSecond.Subtract(currentDate); // remaining time till today ends

        // I want the timer to check every day at specifed time (as in timeOfFirstDay) if the month has changed 
        // therefore at first I would like timer's timeout to be until the same time, following day
        var milliSecondsTillTomorrow = (timeSpanInCurrentDate + timeOfFirstDay).TotalMilliseconds;
        // since out milliseconds will never exceed - . Its okay to convert them to int32
        mTimer = new Timer(TimerTick, null, Convert.ToInt32(milliSecondsTillTomorrow), Convert.ToInt32(milliSecondsInDay));
    }

    private void TimerTick(object state)
    {
        if(DateTime.Now.Month != mLastTimerDate.Month)
        {
            if (MonthChanged != null)
                MonthChanged(this, new MonthChangedEventArgs(mLastTimerDate, DateTime.Now.Date));
        }
        mLastTimerDate = DateTime.Now.Date;
    }


    public void Dispose()
    {
        mTimer.Dispose();
    }
}

public class MonthChangedEventArgs : EventArgs
{
   public MonthChangedEventArgs(DateTime previousMonth, DateTime currentMonth)
    {
        CurrentMonth = currentMonth;
        PreviousMonth = previousMonth;
    }

   public DateTime CurrentMonth
    {
        get;
        private set;
    }

   public DateTime PreviousMonth
   {
       get;
       private set;
   }
}

client code

    // Check the new month around 2 AM on 1st day
        mMonthTimer = new MonthTimer(new TimeSpan(2, 0, 0));
        mMonthTimer.MonthChanged += mMonthTimer_MonthChanged;

One thing I'm not using System.Threading.Timer, therefor the even handler will be called on a separate thread & not UI thread as incase of System.Windows.Forms.Timer if this is an issue in yr case do let me know.

Also do write me a comment if it serves yr purpose or any if any issues

Kapoor
  • 1,388
  • 11
  • 21
1

Try Microsoft's Reactive Framework (NuGet "Rx-Main").

You can write this:

Observable
    .Timer(DateTimeOffset.Now.AddDays(29.0))
    .Subscribe(x =>
    {
        /* 29 Days Later */
    });
Paul Zahra
  • 9,522
  • 8
  • 54
  • 76
Enigmativity
  • 113,464
  • 11
  • 89
  • 172