mIRC Home    About    Download    Register    News    Help

Print Thread
Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
So I wrote this script to perform what should be the simple task of triggering a timer every minute, hour and midnight. Also threw in every 15 minutes and half-hour. It does this very well but it's more convoluted than I would hope, and that's because it needs to take in two very rare occurrences into consideration -- daylight savings time change, and system clock adjustments.

The events will always fire at the exact clock event when the second changes over, unless the system is busy due to high CPU load. By this, I mean it triggers at the exact roll-over or first interrupt of the 64 or 100 interrupts there are per second. So this can be very handy for interacting with logged events -- ie, it will trigger at midnight before any other messages arrive at midnight.

Code:
; heartbeat

On *:START: {
  ; Create debug window.
  window -aDeizj10000 @heartbeat
  ; Begin heartbeat.
  heartbeat
}

ALIAS heartbeat { ; by Raccoon 2015
  ; Set $1- to SEC MIN HOUR DAY MONTH YEAR
  tokenize 32 $asctime(ss nn HH dd mm yyyy)

  ; Assurance timer keeps checking in case of daylight saving time change or clock adjustment.
  ; Why 9 seconds?  00, 09, 18, 27, 36, 45, 54, [60], 63.
  .timerheartbeat -oi 0 9 heartbeat

  ; On-The-Minute timer triggers at exactly next 00 seconds. Never 59. Rarely 01 if super lagged.
  ; "$asctime($calc($ctime + 60ish)" will return correctly for daylight savings time change.
  .timer_heartbeat -oi $asctime($calc($ctime + (69 - $1)),HH:nn) 1 0 heartbeat

  ; Do not continue unless minute has changed.
  if (%heartbeat.last == $2-) { return }
  set -u90 %heartbeat.last $2-

  ; Trigger events for current time.
  if ($2-3 == 00 00)       .signal everyday $1-
  if ($2 == 00)            .signal everyhour $1-
  if ($calc($2 % 30) == 0) .signal everythirty $1-  
  if ($calc($2 % 15) == 0) .signal everyfifteen $1-
  .signal everyminute $1-

  ; Debug output.
  if ($window(@heartbeat)) { echo $v1 HEARTBEAT $1- : $right($ticks,3) }
}

On *:SIGNAL:everyminute: {
  ; things to do every minute.

}

On *:SIGNAL:everyfifteen: {
  ; things to do every quarter hour.

}

On *:SIGNAL:everythirty: {
  ; things to do every half hour.

}

On *:SIGNAL:everyhour: {
  ; things to do every hour.

}

On *:SIGNAL:everyday: {
  ; things to do at midnight.
  scon -a echo -stic notify * Day changed to $asctime(dd mmm yyyy) $+ , a $asctime(dddd) $+ .
}


It would be great if all this code could be reduced to a simple timer with parameters, but I can't imagine how, while retaining the ability to detect small adjustments to the system clock or the time changing 1 or 2 hours forward or backward for daylight savings, or timezone changes on laptops.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Jun 2014
Posts: 248
B
Fjord artisan
Offline
Fjord artisan
B
Joined: Jun 2014
Posts: 248
What if you just calculated when the next event should be at the end of an event?

Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
That calculation can change. So, say the time is 07:30 and you calculate the next minute should be 07:31. But you just stepped off the plane and change your timezone so the time becomes 09:30... the timer won't trigger again until the next day at 07:31.

Or what if Windows updates your system clock a couple minutes? Same situation.

Like I said, these are both pretty rare conditions, but they exist in the real world. I wish they were conditions that mIRC handled internally.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Jun 2014
Posts: 248
B
Fjord artisan
Offline
Fjord artisan
B
Joined: Jun 2014
Posts: 248
I'm obv not as savvy as many people here, but couldn't you use $ticks instead of current time?

Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
If you mean setting a timer with just N seconds before it should fire again, that doesn't work very well as it's not very accurate. I've tested even with high resolution timers, and it turns out the best type is an HH:nn timer, but I have to use a secondary timer in case that HH:nn should change in the course of a minute.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Jun 2014
Posts: 248
B
Fjord artisan
Offline
Fjord artisan
B
Joined: Jun 2014
Posts: 248
I was thinking like

check what the current ticks are
calculate what the next ticks should be
check ticks on a timer
fire event when ticks is met.

Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
You don't want to call an alias too aggressively like that or mIRC's CPU usage shoots up. The method I used above only fires 10 times per minute and is hyper accurate. It just seems more complicated than it should be, but it's definitely not as aggressive as checking every millisecond.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Apr 2010
Posts: 969
F
Hoopy frood
Offline
Hoopy frood
F
Joined: Apr 2010
Posts: 969
The issue here is you are trying to mix static timing with dynamic timing.

Intervals, such as every minute, every 15minutes, every 30minutes, etc, are static. The amount of time is always the same between 'heartbeats', for these, you could just set a timer with required interval

Where as set times such as noon, or midnight are arbitrary. They change dependent on system clock, timezone, etc. If you create a timer that says 'trigger at midnight', you can't except it to trigger if the system clock jumps from 11:59 to 12:00.


I am SReject
My Stuff
Joined: Jul 2006
Posts: 4,163
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,163
Quote:
it needs to take in two very rare occurrences into consideration -- daylight savings time change, and system clock adjustments.
That's just one thing: system clock adjustments. But you are over thinking it, you shouldn't be taking this into account, if you are afraid it won't work if the system clock is changed then don't be, it's ridiculous to take that event into account, at best you would have a function triggering when the system clock is changed, and you would readjust your timer there.
That said, your claim are wrong, /timer -h HH:nn is as accurate as you can get, using a timer to get more accuracy because you think the timer itself isn't accurate is.. well, contradictory.
What are you asking for exactly? Using -h is basically your idea of calling an extra timer to check more often if the time elapsed, however this is not done with msl and it's not much more often than your nine seconds.
Assuming mIRC is busy, there is nothing you can do to get your timer to trigger at the specified time, it will always trigger later.
Assuming mIRC isn't busy, a multimedia timer (-h) should trigger with the specified time.
In short, if what you are asking for is a way to get more accurate timer, it already exists and it's using -h, you should use it.

Last edited by Wims; 12/01/15 03:52 PM.

#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
Wow guys. Several problems in both responses. Sorry if that sounds harshly critical off the bat, but I'll explain.

FroggieDaFrog: The intended design is to trigger at clock events and not arbitrarily. Yes: the 'everyfifteen' event is desired to fire at 0,15,30,45 ... and not 7,22,37,52. That's simply what I want. Like a cron.

As such, I'm using HH:nn timers because they are accurate to the second (the top of the minute), and do not trigger somewhere arbitrarily in the middle of the minute. Eg: everyfifteen always triggers at 00:15:00.000 (unless there is heavy CPU load) and not 00:15:49.362. That's simply what I want, and mIRC is quite capable in that area without any craziness. It pairs well with logged events in this way.

The main problem is, you can't just set an HH:nn timer every minute without the chance of the system clock skipping forward or backwards and missing that minute. If that HH:nn never comes, the whole operation halts until the following day. Thus, the secondary assurance timer is necessary to keep the main timer on task in case of time change or clock adjustments.

Ouims: /timer HH:nn 1 0 versus /timer 0 60

When specifying an hour:minute timer, that timer triggers precisely after the clock's minute changes. The -m and -h switches for /timer only specify the resolution of the delay parameter and has no effect on HH:nn 1 0 timers, since there is no delay to speak of. 0 is equivalent to 1ms with or without -h or -m. Adding -h does nothing in your example.

The rest of your post is pretty hung up on this idea about -h and that I'm somehow hung up on more accuracy. I'm not though, I never was. I'm hung up on how HH:nn timers don't have any consideration that HH:nn might, rather will, be skipped over regularly when there are time changes and adjustments to the system clock.

I recommend you try this script before commenting further.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Jul 2006
Posts: 4,163
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,163
I don't need to try the script to see what it's doing, I know how timer work. I can already tell you how to adjust your system clock to get that script to fail, I tested it nonetheless, here is a debug for you:
Quote:
.signal everyminute 00 49 14 13 01 2015
.signal everyminute 43 49 13 13 01 2015
.signal everyminute 00 50 13 13 01 2015
Around 14:49:43, I changed the system clock to be 13:49:43, your script reported that a minute had passed which is incorrect, and that happens because the condition checking the equality of $2- and your variable is not true anymore: you have no event to reset your variable to its correct value, you can only set the timer _heartbeat correctly.
Both our responses were relevant to the thread, you want to use a timer which count time passing, not timer based on the system clock. and for that the most accurate way to do it is to use /timer -h.
We're trying to help and you came back with very unpleasant attitude, do you actually need help with something or are you just here to claim our ideas are wrong when perhaps you're the one with the wrong idea?


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
Well, we had this discussion in the channel before, and the problem I was encountering with high resolution timers is they would occasionally drift away from system time, and so you would get two minute events triggering in the same minute anyway, causing two logged events happening in the same minute (the minute exists twice on paper).

Indeed, I hadn't thought about the scenario you logged where 3 events happen in that 61 second span of time. So basically whether I use a HH:nn or a -h timer, I need to do more checking still to make sure there's only one event per system minute and elapsed minute.

Doesn't using -h cause mIRC's CPU to spike quite a bit?


Well. At least I won lunch.
Good philosophy, see good in bad, I like!
Joined: Jul 2006
Posts: 4,163
W
Hoopy frood
Offline
Hoopy frood
W
Joined: Jul 2006
Posts: 4,163
Multimedia timers just takes a little bit more of your ressources, it doesn't mean mIRC's CPU usage will spike quite a bit, it might if you are using a very small millisecond delay and the associated timer command is doing something heavy, but that wouldn't be your case here.
Something that could be a problem is that it can prevent Windows from going into sleep mode.

You are stuck because you don't want to use /timer -h and count the time that way because it's innacurate and you are right (if each new timer triggers one millisecond later, after 1000 timer you are off by one second) and you don't want to use the TIME parameter of /timer because of the system clock issue.


#mircscripting @ irc.swiftirc.net == the best mIRC help channel
Joined: Feb 2003
Posts: 2,812
Raccoon Offline OP
Hoopy frood
OP Offline
Hoopy frood
Joined: Feb 2003
Posts: 2,812
Well, the nice thing about the TIME parameter of the /timer is that mIRC automatically fires that timer, on its own, at the very instant of clock change. It's like its own internalized /timer -h, doing all the math for you. A TIME timer never fires too early, and tries its damned best to fire On Time Every Time. It's very rarely late by more than 1 processor interrupt. This means your /echo or whatever janitor always occurs before any On Text events in that same minute.

Unless that entire minute is skipped over, which is where problems begin.


Well. At least I won lunch.
Good philosophy, see good in bad, I like!

Link Copied to Clipboard