2 #Copyright (C) 2009-2010 :
3 # Gabes Jean, naparuba@gmail.com
4 # Gerhard Lausser, Gerhard.Lausser@consol.de
6 #This file is part of Shinken.
8 #Shinken is free software: you can redistribute it and/or modify
9 #it under the terms of the GNU Affero General Public License as published by
10 #the Free Software Foundation, either version 3 of the License, or
11 #(at your option) any later version.
13 #Shinken is distributed in the hope that it will be useful,
14 #but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 #GNU Affero General Public License for more details.
18 #You should have received a copy of the GNU Affero General Public License
19 #along with Shinken. If not, see <http://www.gnu.org/licenses/>.
21 from shinken
.util
import *
24 #Get the day number (like 27 in July tuesday 27 2010 for call:
25 #2010, july, tuesday, -1 (last tuesday of july 2010)
26 def find_day_by_weekday_offset(year
, month
, weekday
, offset
):
27 #et the id if teh weekday (1 for tuesday)
28 weekday_id
= Daterange
.get_weekday_id(weekday
)
29 if weekday_id
is None:
33 month_id
= Daterange
.get_month_id(month
)
38 cal
= calendar
.monthcalendar(year
, month_id
)
40 #If we ask for a -1 day, just reverse cal
48 for i
in xrange(0, offset
+ 1):
49 #in cal 0 mean "there are no day here :)"
50 if cal
[i
][weekday_id
] != 0:
52 if nb_found
== offset
:
53 return cal
[i
][weekday_id
]
59 def find_day_by_offset(year
, month
, offset
):
60 month_id
= Daterange
.get_month_id(month
)
63 (tmp
, days_in_month
) = calendar
.monthrange(year
, month_id
)
65 return min(offset
, days_in_month
)
67 return max(1, days_in_month
+ offset
+ 1)
71 #entry is like 00:00-24:00
72 def __init__(self
, entry
):
73 entries
= entry
.split('-')
76 sentries
= start
.split(':')
77 self
.hstart
= int(sentries
[0])
78 self
.mstart
= int(sentries
[1])
79 eentries
= end
.split(':')
80 self
.hend
= int(eentries
[0])
81 self
.mend
= int(eentries
[1])
84 return str(self
.__dict
__)
86 def get_sec_from_morning(self
):
87 return self
.hstart
*3600 + self
.mstart
*60
90 def get_first_sec_out_from_morning(self
):
91 #If start at 0:0, the min out is the end
92 if self
.hstart
== 0 and self
.mstart
== 0:
93 return self
.hend
*3600 + self
.mend
*60
97 def is_time_valid(self
, t
):
98 sec_from_morning
= get_sec_from_morning(t
)
99 return self
.hstart
*3600 + self
.mstart
* 60 <= sec_from_morning
<= self
.hend
*3600 + self
.mend
* 60
104 weekdays
= {'monday' : 0, 'tuesday' : 1, 'wednesday' : 2, 'thursday' : 3, \
105 'friday' : 4, 'saturday' : 5, 'sunday': 6 }
106 months
= {'january' : 1, 'february': 2, 'march' : 3, 'april' : 4, 'may' : 5, \
107 'june' : 6, 'july' : 7, 'august' : 8, 'september' : 9, \
108 'october' : 10, 'november' : 11, 'december' : 12}
109 def __init__(self
, syear
, smon
, smday
, swday
, swday_offset
,
110 eyear
, emon
, emday
, ewday
, ewday_offset
, skip_interval
, other
):
111 self
.syear
= int(syear
)
113 self
.smday
= int(smday
)
115 self
.swday_offset
= int(swday_offset
)
116 self
.eyear
= int(eyear
)
118 self
.emday
= int(emday
)
120 self
.ewday_offset
= int(ewday_offset
)
121 self
.skip_interval
= int(skip_interval
)
125 for timeinterval
in other
.split(','):
126 self
.timeranges
.append(Timerange(timeinterval
.strip()))
130 return ''#str(self.__dict__)
133 #By default, daterange are correct
134 def is_correct(self
):
138 def get_month_id(cls
, month
):
140 return Daterange
.months
[month
]
143 get_month_id
= classmethod(get_month_id
)
147 def get_month_by_id(cls
, id):
149 for key
in Daterange
.months
:
150 if id == Daterange
.months
[key
]:
153 get_month_by_id
= classmethod(get_month_by_id
)
156 def get_weekday_id(cls
, weekday
):
158 return Daterange
.weekdays
[weekday
]
161 get_weekday_id
= classmethod(get_weekday_id
)
164 def get_weekday_by_id(cls
, id):
166 for key
in Daterange
.weekdays
:
167 if id == Daterange
.weekdays
[key
]:
170 get_weekday_by_id
= classmethod(get_weekday_by_id
)
174 def get_start_and_end_time(self
, ref
=None):
175 print "Not implemented"
178 def is_time_valid(self
, t
):
179 if self
.is_time_day_valid(t
):
180 for tr
in self
.timeranges
:
181 if tr
.is_time_valid(t
):
186 def get_min_sec_from_morning(self
):
188 for tr
in self
.timeranges
:
189 mins
.append(tr
.get_sec_from_morning())
193 def get_min_sec_out_from_morning(self
):
195 for tr
in self
.timeranges
:
196 mins
.append(tr
.get_first_sec_out_from_morning())
200 def get_min_from_t(self
, t
):
201 if self
.is_time_valid(t
):
203 t_day_epoch
= get_day(t
)
204 tr_mins
= self
.get_min_sec_from_morning()
205 return t_day_epoch
+ tr_mins
208 def is_time_day_valid(self
, t
):
209 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
210 # print "My class", self.__class__
211 # print "Search for t", time.asctime(time.localtime(start_time))
212 # print "Start time, endtime", time.asctime(time.localtime(start_time)), time.asctime(time.localtime(end_time))
213 if start_time
<= t
<= end_time
:
219 def is_time_day_invalid(self
, t
):
220 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
221 if start_time
<= t
<= end_time
:
227 #def have_future_tiremange_valid(self, t):
229 # for tr in self.timeranges:
230 # tr_start = tr.hstart * 3600 + tr.mstart * 3600
231 # if tr_start >= sec_from_morning:
236 def get_next_future_timerange_valid(self
, t
):
237 sec_from_morning
= get_sec_from_morning(t
)
239 for tr
in self
.timeranges
:
240 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 60
241 if tr_start
>= sec_from_morning
:
242 starts
.append(tr_start
)
249 def get_next_future_timerange_invalid(self
, t
):
250 #print 'Call for get_next_future_timerange_invalid from ', time.asctime(time.localtime(t))
251 sec_from_morning
= get_sec_from_morning(t
)
252 #print 'sec from morning', sec_from_morning
254 for tr
in self
.timeranges
:
255 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 60
256 if tr_start
>= sec_from_morning
:
257 ends
.append(tr_start
)
258 tr_end
= tr
.hend
* 3600 + tr
.mend
* 60
259 if tr_end
>= sec_from_morning
:
262 #Remove the last second of the day for 00->24h"
271 def get_next_valid_day(self
, t
):
272 if self
.get_next_future_timerange_valid(t
) is None:
273 #this day is finish, we check for next period
274 (start_time
, end_time
) = self
.get_start_and_end_time(get_day(t
)+86400)
276 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
278 #print self.__class__
279 #print "Get next valid day start/end for", time.asctime(time.localtime(t))
280 #print "Start", time.asctime(time.localtime(start_time))
281 #print "End", time.asctime(time.localtime(end_time))
284 return get_day(start_time
)
286 if self
.is_time_day_valid(t
):
292 def get_next_valid_time_from_t(self
, t
):
293 #print "DR Get next valid from:", time.asctime(time.localtime(t))
294 #print "DR Get next valid from:", t
295 if self
.is_time_valid(t
):
298 #print "DR Get next valid from:", time.asctime(time.localtime(t))
299 #First we search fot the day of t
300 t_day
= self
.get_next_valid_day(t
)
301 sec_from_morning
= self
.get_min_sec_from_morning()
303 #print "Search for t", time.asctime(time.localtime(t))
304 #print "DR: next day", time.asctime(time.localtime(t_day))
305 #print "DR: sec from morning", time.asctime(time.localtime(sec_from_morning))
307 #We search for the min of all tr.start > sec_from_morning
309 for tr
in self
.timeranges
:
310 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 3600
311 if tr_start
>= sec_from_morning
:
312 starts
.append(tr_start
)
314 #tr can't be valid, or it will be return at the begining
315 sec_from_morning
= self
.get_next_future_timerange_valid(t
)
316 #print "DR: sec from morning", time.asctime(time.localtime(sec_from_morning))
317 #print "Sec from morning", t_day
318 if sec_from_morning
is not None:
319 if t_day
is not None and sec_from_morning
is not None:
320 return t_day
+ sec_from_morning
322 #Then we search for the next day of t
323 #The sec will be the min of the day
325 t_day2
= self
.get_next_valid_day(t
)
326 sec_from_morning
= self
.get_next_future_timerange_valid(t_day2
)
327 if t_day2
is not None and sec_from_morning
is not None:
328 return t_day2
+ sec_from_morning
330 #I'm not find any valid time
334 def get_next_invalid_day(self
, t
):
335 #print 'DR: get_next_invalid_day for', time.asctime(time.localtime(t))
336 if self
.is_time_day_invalid(t
):
339 next_future_timerange_invalid
= self
.get_next_future_timerange_invalid(t
)
340 #print "next_future_timerange_invalid:", next_future_timerange_invalid
342 #If today there is no more unavalable timerange, search the next day
343 if next_future_timerange_invalid
is None:
344 #print 'DR: get_next_future_timerange_invalid is None'
345 #this day is finish, we check for next period
346 (start_time
, end_time
) = self
.get_start_and_end_time(get_day(t
)+86400)
348 #print 'DR: get_next_future_timerange_invalid is', time.asctime(time.localtime(next_future_timerange_invalid))
349 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
350 #res = get_day(t) + next_future_timerange_invalid
351 #print "Early return"
354 #print 'DR:Start:', time.asctime(time.localtime(start_time))
355 #print 'DR:End:', time.asctime(time.localtime(end_time))
356 #The next invalid day can be t day if there a possible
357 #invalid time range (timerange is not 00->24
358 if next_future_timerange_invalid
!= None:
359 if start_time
<= t
<= end_time
:
360 #print "Early Return next invalid day:", time.asctime(time.localtime(get_day(t)))
363 return get_day(start_time
)
364 else:#Else, there is no possibility than in our start_time<->end_time we got
365 #any invalid time (full period out). So it's end_time+1 sec (tomorow of end_time)
366 #print "Full period out, got end_time", time.asctime(time.localtime(get_day(end_time +1)))
367 return get_day(end_time
+1)
372 def get_next_invalid_time_from_t(self
, t
):
373 #print 'DR:get_next_invalid_time_from_t', time.asctime(time.localtime(t))
374 if not self
.is_time_valid(t
):
375 #print "DR: cool, t is invalid", time.asctime(time.localtime(t))
378 # print "DR: Arg, t is valid", time.asctime(time.localtime(t))
380 #First we search fot the day of t
381 t_day
= self
.get_next_invalid_day(t
)
382 #print "Get next invalid day:", time.asctime(time.localtime(t_day))
383 #print "Is valid day?", self.is_time_valid(t_day)
385 #We search for the min of all tr.start > sec_from_morning
387 #for tr in self.timeranges:
388 # tr_start = tr.hstart * 3600 + tr.mstart * 3600
389 # if tr_start >= sec_from_morning:
390 # starts.append(tr_start)
392 #tr can't be valid, or it will be return at the begining
393 sec_from_morning
= self
.get_next_future_timerange_invalid(t
)
394 #print "TOTO sec_from_morning:", sec_from_morning
395 #Ok we've got a next invalid day and a invalid possibility in
396 #timerange, so the next invalid is this day+sec_from_morning
397 #print "T_day", t_day, "Sec from morning", sec_from_morning
398 if t_day
is not None and sec_from_morning
is not None:
399 return t_day
+ sec_from_morning
+ 1
401 #We've got a day but no sec_from_morning : the timerange is full (0->24h)
402 #so the next invalid is this day at the day_start
403 if t_day
is not None and sec_from_morning
== None:
406 #Then we search for the next day of t
407 #The sec will be the min of the day
409 t_day2
= self
.get_next_invalid_day(t
)
410 sec_from_morning
= self
.get_next_future_timerange_invalid(t_day2
)
411 if t_day2
is not None and sec_from_morning
is not None:
412 return t_day2
+ sec_from_morning
+ 1
414 if t_day2
is not None and sec_from_morning
== None:
417 #I'm not find any valid time
423 #ex: 2007-01-01 - 2008-02-01
424 class CalendarDaterange(Daterange
):
425 def get_start_and_end_time(self
, ref
=None):
426 start_time
= get_start_of_day(self
.syear
, int(self
.smon
), self
.smday
)
427 end_time
= get_end_of_day(self
.eyear
, int(self
.emon
), self
.emday
)
428 return (start_time
, end_time
)
432 #Like tuesday 00:00-24:00
433 class StandardDaterange(Daterange
):
434 def __init__(self
, day
, other
):
438 for timeinterval
in other
.split(','):
439 self
.timeranges
.append(Timerange(timeinterval
.strip()))
443 #It's correct only if the weekday (sunday, etc) is a valid one
444 def is_correct(self
):
445 b
= self
.day
in Daterange
.weekdays
447 print "Error : %s is not a valid day" % self
.day
451 def get_start_and_end_time(self
, ref
=None):
452 now
= time
.localtime(ref
)
453 self
.syear
= now
.tm_year
454 self
.month
= now
.tm_mon
455 #month_start_id = now.tm_mon
456 #month_start = Daterange.get_month_by_id(month_start_id)
457 self
.wday
= now
.tm_wday
458 day_id
= Daterange
.get_weekday_id(self
.day
)
459 today_morning
= get_start_of_day(now
.tm_year
, now
.tm_mon
, now
.tm_mday
)
460 tonight
= get_end_of_day(now
.tm_year
, now
.tm_mon
, now
.tm_mday
)
461 day_diff
= (day_id
- now
.tm_wday
) % 7
462 return (today_morning
+ day_diff
*86400, tonight
+ day_diff
*86400)
465 class MonthWeekDayDaterange(Daterange
):
466 #It's correct only if the weekday (sunday, etc) is a valid one
467 def is_correct(self
):
469 b
&= self
.swday
in Daterange
.weekdays
471 print "Error : %s is not a valid day" % self
.swday
473 b
&= self
.ewday
in Daterange
.weekdays
475 print "Error : %s is not a valid day" % self
.ewday
480 def get_start_and_end_time(self
, ref
=None):
481 now
= time
.localtime(ref
)
484 self
.syear
= now
.tm_year
485 month_id
= Daterange
.get_month_id(self
.smon
)
486 day_start
= find_day_by_weekday_offset(self
.syear
, self
.smon
, self
.swday
, self
.swday_offset
)
487 start_time
= get_start_of_day(self
.syear
, month_id
, day_start
)
490 self
.eyear
= now
.tm_year
491 month_end_id
= Daterange
.get_month_id(self
.emon
)
492 day_end
= find_day_by_weekday_offset(self
.eyear
, self
.emon
, self
.ewday
, self
.ewday_offset
)
493 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
495 now_epoch
= time
.mktime(now
)
496 if start_time
> end_time
: #the period is between years
497 if now_epoch
> end_time
:#check for next year
498 day_end
= find_day_by_weekday_offset(self
.eyear
+ 1, self
.emon
, self
.ewday
, self
.ewday_offset
)
499 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
500 else:#it s just that start was the last year
501 day_start
= find_day_by_weekday_offset(self
.syear
- 1, self
.smon
, self
.swday
, self
.swday_offset
)
502 start_time
= get_start_of_day(self
.syear
- 1, month_id
, day_start
)
504 if now_epoch
> end_time
:#just have to check for next year if necessery
505 day_start
= find_day_by_weekday_offset(self
.syear
+ 1, self
.smon
, self
.swday
, self
.swday_offset
)
506 start_time
= get_start_of_day(self
.syear
+ 1, month_id
, day_start
)
507 day_end
= find_day_by_weekday_offset(self
.eyear
+ 1, self
.emon
, self
.ewday
, self
.ewday_offset
)
508 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
510 return (start_time
, end_time
)
514 class MonthDateDaterange(Daterange
):
515 def get_start_and_end_time(self
, ref
=None):
516 now
= time
.localtime(ref
)
518 self
.syear
= now
.tm_year
519 month_start_id
= Daterange
.get_month_id(self
.smon
)
520 day_start
= find_day_by_offset(self
.syear
, self
.smon
, self
.smday
)
521 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
524 self
.eyear
= now
.tm_year
525 month_end_id
= Daterange
.get_month_id(self
.emon
)
526 day_end
= find_day_by_offset(self
.eyear
, self
.emon
, self
.emday
)
527 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
529 now_epoch
= time
.mktime(now
)
530 if start_time
> end_time
: #the period is between years
531 if now_epoch
> end_time
:#check for next year
532 day_end
= find_day_by_offset(self
.eyear
+ 1, self
.emon
, self
.emday
)
533 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
534 else:#it s just that start was the last year
535 day_start
= find_day_by_offset(self
.syear
-1, self
.smon
, self
.emday
)
536 start_time
= get_start_of_day(self
.syear
-1, month_start_id
, day_start
)
538 if now_epoch
> end_time
:#just have to check for next year if necessery
539 day_start
= find_day_by_offset(self
.syear
+1, self
.smon
, self
.emday
)
540 start_time
= get_start_of_day(self
.syear
+1, month_start_id
, day_start
)
541 day_end
= find_day_by_offset(self
.eyear
+1, self
.emon
, self
.emday
)
542 end_time
= get_end_of_day(self
.eyear
+1, month_end_id
, day_end
)
544 return (start_time
, end_time
)
547 class WeekDayDaterange(Daterange
):
548 def get_start_and_end_time(self
, ref
=None):
549 now
= time
.localtime(ref
)
551 #If no year, it's our year
553 self
.syear
= now
.tm_year
554 month_start_id
= now
.tm_mon
555 month_start
= Daterange
.get_month_by_id(month_start_id
)
556 day_start
= find_day_by_weekday_offset(self
.syear
, month_start
, self
.swday
, self
.swday_offset
)
557 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
561 self
.eyear
= now
.tm_year
562 month_end_id
= now
.tm_mon
563 month_end
= Daterange
.get_month_by_id(month_end_id
)
564 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
565 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
567 #Maybe end_time is before start. So look for the
569 if start_time
> end_time
:
570 month_end_id
= month_end_id
+ 1
571 if month_end_id
> 12:
574 month_end
= Daterange
.get_month_by_id(month_end_id
)
575 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
576 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
578 now_epoch
= time
.mktime(now
)
579 #But maybe we look not ethouth far. We should add a month
580 if end_time
< now_epoch
:
581 month_end_id
= month_end_id
+ 1
582 month_start_id
= month_start_id
+ 1
583 if month_end_id
> 12:
586 if month_start_id
> 12:
590 month_start
= Daterange
.get_month_by_id(month_start_id
)
591 day_start
= find_day_by_weekday_offset(self
.syear
, month_start
, self
.swday
, self
.swday_offset
)
592 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
594 month_end
= Daterange
.get_month_by_id(month_end_id
)
595 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
596 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
598 return (start_time
, end_time
)
601 class MonthDayDaterange(Daterange
):
602 def get_start_and_end_time(self
, ref
=None):
603 now
= time
.localtime(ref
)
605 self
.syear
= now
.tm_year
606 month_start_id
= now
.tm_mon
607 month_start
= Daterange
.get_month_by_id(month_start_id
)
608 day_start
= find_day_by_offset(self
.syear
, month_start
, self
.smday
)
609 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
612 self
.eyear
= now
.tm_year
613 month_end_id
= now
.tm_mon
614 month_end
= Daterange
.get_month_by_id(month_end_id
)
615 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
616 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
618 now_epoch
= time
.mktime(now
)
620 if start_time
> end_time
:
621 month_end_id
= month_end_id
+ 1
622 if month_end_id
> 12:
625 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
626 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
628 if end_time
< now_epoch
:
629 month_end_id
= month_end_id
+ 1
630 month_start_id
= month_start_id
+ 1
631 if month_end_id
> 12:
634 if month_start_id
> 12:
639 month_start
= Daterange
.get_month_by_id(month_start_id
)
640 day_start
= find_day_by_offset(self
.syear
, month_start
, self
.smday
)
641 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
644 month_end
= Daterange
.get_month_by_id(month_end_id
)
645 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
646 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
648 return (start_time
, end_time
)