Groovy Time Math

I am trying to log the time between two events. No problems with minutes or seconds but the hour is off. Here is the code

	def cur =new Date(now()-atomicState.lastTime).format('HH:mm:ss',location.timeZone)
	msg="$msg Time Elapsed since last Event: $cur"

The hour results are always off. If the event occurred during the same hour the results of the above will look similar to 19:14:20 the minute:second portion (14:20) is correct. If the event spans one or more hour the results will be similar to 20:02:01 The hour portion is at least 20.
If I change the above to

	def cur =new Date(now()-atomicState.lastTime).format('mm:ss',location.timeZone)
	msg="$msg Time Elapsed since last Event: $cur"

The minutes:Seconds will always be correct but the event may have occurred several hours ago. For example
Event 1 at 12:15:30 PM
Event 2 at 4:45:45 PM

The result of $cur will be :30:15

How do I get the above to display 04:30:15

You are creating a Date that is X time after the epoch and then using format to convert to you current timezone, which probably is a few hours off of GMT.

Just to be clear, your problem is that you treat the difference between two dates as a new date. This only works in a small corner case where the difference is less than 24 hours and you happen to be in the GMT timezone. Anything outside of that will mess up.

As you get 19:mm:ss I’ll venture a guess and say you’re based in New York or thereabouts. What happens is that you get say a 5 seconds difference and wrongly turn that into a date. Since time 0(zero) in computers is 00:00:00 January 1. 1970 you get 00:00:05 January 1. 1970. But since you’re 5 hours behind GMT we subtract 5 hours from that and end up in 19:00:05 December 31. 1969.

I’d skip the date-formatting and stick with the milliseconds you get from now(), and then pretty-print it ala
secs = diff/1000; // Milliseconds to seconds
printf("%02d:%02d:02d", (int) (secs/3600), (int)(secs % 3600/60), (int)(secs % 60))

Still have to think about how to consider values above 25 hours unless you’re okay with 25:mm:ss etc


1 Like

I really hate groovy. Simplest things (normally) turn out to become a nightmare. I tried your approach within groovy and I get error

UnsupportedOperationException: Cannot use mod() on this number type: java.math.BigDecimal with value

for the following

 def m = secs % 3600/60
  def s = secs % 60

The divide by 1000 probably turned the integer milliseconds into a decimal seconds, try casting it to int and see what happens: def secs = (int) (now() / 1000)

Note I only have a couple of weeks with groovy myself, so don’t know all the idiosyncrasies. :slight_smile:


1 Like

Here’s how I solved this. YMMV depending on what you’re trying to accomplish.

This is from a Windows Server Monitor DTH I’m working on for myself.
vitals.Uptime could easily be your atomicState.lastTime variable, but make sure you write it as atomicState.lastTime.toDouble() so it’s properly converted.

This does the simple math, but not duration.

  		def ts = now() - (vitals.Uptime.toDouble() * 1000)
		def lastBoot = new Date(ts.round()).format("MM-dd-yy h:mm:ss a", location.timeZone)

For duration, use TimeCategory.
This should work but I’ve not tested specifically as I am traveling today.

def start_t = new Date() // Set your Date object accordingly.
def end_t = new Date() // Set your Date object accordingly.

    import groovy.time.TimeCategory
        	def dur = end_t - start_t
        	def days = dur.days
        	def hours = dur.hours
        	def minutes - dur.minutes