Finding the amount of time for overlapping values

I struggled with this issue for a couple of days. I have one machine that may have errors. In the database, I have a start and end time (in unix time) when the error occurred, and the type of error (number from 5 to 12). The problem that I am facing is that at the same time several errors may occur (and overlap).

My table looks like this:

id| type | from | to 1| 6 | 1417179933 | 1417180006 2| 6 | 1417180035 | 1417180065 3| 9 | 1417180304 | 1417180409 4| 6 | 1417180662 | 1417184364 5| 8 | 1417180662 | 1417186832 6| 9 | 1417180662 | 1417184364 7| 12 | 1417180662 | 1417184364 8| 6 | 1417184364 | 1417186832 9| 9 | 1417184364 | 1417188054 

I need to find the total error duration for this machine. I can’t summarize all the differences from the above table, since it is possible that two or more errors appeared during the same period of time. Entries are sorted in ascending order.

My assumption was to compare each record (start and end time) with the previous one, and then find the difference in seconds. However, this table can grow over time, and the problem is finding it.

Is there a smart way in PHP or MySQL to find the total time when the machine was not working, perhaps in a matter of minutes?

+5
source share
3 answers

Here, the general approach to summing intervals, taking into account potential overlaps involving intervals, is sorted by their lower value.

2 time intervals

When you add two intervals [a,b] and [c,d] , thus (dc) + (ba) you count their overlap twice.

  • If the overlap is nonzero, then its value is min(b,d) - max(a,c) . Since you sorted the items at the beginning of the interval, you know that max(a,c) == c .

  • If the overlap is 0 , a <= b <= c <= d , so min(b,d) == b , max(a,c) == c and min(b,d) - max(a,c) == b - c <= 0 . However, you want to remove 0 .

Thus, the general formula dc + ba - max(0,min(b,d)-c)

Generalization to more intervals

To generalize to more intervals than two, just think that when you add a new interval [c,d] to any number of previous intervals, you add (dc) , and a match that counts twice is between [c,d] and combining all the previous intervals.

Since you sort the intervals by their starting values, you only need to consider the last continuous interval of this union, so for you the last continuous period of inactivity.

If [a,b] is your previous last continuous interval, and you just added [c,d] :

  • If [a,b] and [c,d] overlap , your last continuous interval becomes [a, max(b,d)] because it is the union of [a,b] and [c,d]
  • If [a,b] and [c,d] do not overlap , your last continuous interval becomes [c, d] (NB: we have max(b,d) == b )

Since a < c due to sorted intervals, the intervals overlap iff c < b

In code

This is probably easier to implement in php than in mysql. In pseudocode, assuming that each line returns the error interval (start, end), and [a,b] is your last known continuous interval:

 (a,b) = get_first_row(); downtime = ba; while( (c,d) = get_next_row() ) { downtime += dc - max(0, min(d,b)-c); a = c < b ? a : c; b = max(b,d); } 

You can see how this code works successfully here: https://3v4l.org/Q2phs

+3
source

Theft of ideas from Peterm Calculate total time, excluding overlapping time and breaks in MySQL

  SELECT SUM(seconds) total FROM ( SELECT MAX(to_date) - MIN(from_date) seconds FROM ( SELECT from_date, to_date, @g := IF(@e BETWEEN from_date AND to_date OR to_date <= @e, @g, @g + 1) g, @e := to_date FROM my_table CROSS JOIN ( SELECT @g := 0, @e := NULL ) i ORDER BY from_date, to_date ) q GROUP BY g ) q; 
+1
source

Approach without a database. Perhaps it can be modified for databases.

  Start Finish 10 13 12 15 16 18 

Combine both start and end times in a single sorted list or array with the start flag.

  Time IsStart 10 Yes 12 Yes 13 No 15 No 16 Yes .... 

Make ActiveCounter = 0, view the list.
Add ActiveCounter if IsStart, reduce otherwise

When ActiveCounter becomes> 0, the error interval begins,
when ActiveCounter becomes = 0, the error interval ends.

 Time ActCnt 10 1 //error state begins 12 2 //it continues 13 1 //still continues 15 0 //the end! T = 15-10 = 5 16 1 //new error state begins 
0
source

Source: https://habr.com/ru/post/1208060/


All Articles