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()))
127 self
.is_valid_today
= False
131 return ''#str(self.__dict__)
134 #By default, daterange are correct
135 def is_correct(self
):
139 def get_month_id(cls
, month
):
141 return Daterange
.months
[month
]
144 get_month_id
= classmethod(get_month_id
)
148 def get_month_by_id(cls
, id):
150 for key
in Daterange
.months
:
151 if id == Daterange
.months
[key
]:
154 get_month_by_id
= classmethod(get_month_by_id
)
157 def get_weekday_id(cls
, weekday
):
159 return Daterange
.weekdays
[weekday
]
162 get_weekday_id
= classmethod(get_weekday_id
)
165 def get_weekday_by_id(cls
, id):
167 for key
in Daterange
.weekdays
:
168 if id == Daterange
.weekdays
[key
]:
171 get_weekday_by_id
= classmethod(get_weekday_by_id
)
175 def get_start_and_end_time(self
, ref
=None):
176 print "Not implemented"
179 def is_time_valid(self
, t
):
180 if self
.is_time_day_valid(t
):
181 for tr
in self
.timeranges
:
182 if tr
.is_time_valid(t
):
187 def get_min_sec_from_morning(self
):
189 for tr
in self
.timeranges
:
190 mins
.append(tr
.get_sec_from_morning())
194 def get_min_sec_out_from_morning(self
):
196 for tr
in self
.timeranges
:
197 mins
.append(tr
.get_first_sec_out_from_morning())
201 def get_min_from_t(self
, t
):
202 if self
.is_time_valid(t
):
204 t_day_epoch
= get_day(t
)
205 tr_mins
= self
.get_min_sec_from_morning()
206 return t_day_epoch
+ tr_mins
209 def is_time_day_valid(self
, t
):
210 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
211 # print "My class", self.__class__
212 # print "Search for t", time.asctime(time.localtime(start_time))
213 # print "Start time, endtime", time.asctime(time.localtime(start_time)), time.asctime(time.localtime(end_time))
214 if start_time
<= t
<= end_time
:
220 def is_time_day_invalid(self
, t
):
221 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
222 if start_time
<= t
<= end_time
:
228 #def have_future_tiremange_valid(self, t):
230 # for tr in self.timeranges:
231 # tr_start = tr.hstart * 3600 + tr.mstart * 3600
232 # if tr_start >= sec_from_morning:
237 def get_next_future_timerange_valid(self
, t
):
238 sec_from_morning
= get_sec_from_morning(t
)
240 for tr
in self
.timeranges
:
241 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 60
242 if tr_start
>= sec_from_morning
:
243 starts
.append(tr_start
)
250 def get_next_future_timerange_invalid(self
, t
):
251 #print 'Call for get_next_future_timerange_invalid from ', time.asctime(time.localtime(t))
252 sec_from_morning
= get_sec_from_morning(t
)
253 #print 'sec from morning', sec_from_morning
255 for tr
in self
.timeranges
:
256 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 60
257 if tr_start
>= sec_from_morning
:
258 ends
.append(tr_start
)
259 tr_end
= tr
.hend
* 3600 + tr
.mend
* 60
260 if tr_end
>= sec_from_morning
:
263 #Remove the last second of the day for 00->24h"
272 def get_next_valid_day(self
, t
):
273 if self
.get_next_future_timerange_valid(t
) is None:
274 #this day is finish, we check for next period
275 (start_time
, end_time
) = self
.get_start_and_end_time(get_day(t
)+86400)
277 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
279 #print self.__class__
280 #print "Get next valid day start/end for", time.asctime(time.localtime(t))
281 #print "Start", time.asctime(time.localtime(start_time))
282 #print "End", time.asctime(time.localtime(end_time))
285 return get_day(start_time
)
287 if self
.is_time_day_valid(t
):
293 def get_next_valid_time_from_t(self
, t
):
294 #print "DR Get next valid from:", time.asctime(time.localtime(t))
295 #print "DR Get next valid from:", t
296 if self
.is_time_valid(t
):
299 #print "DR Get next valid from:", time.asctime(time.localtime(t))
300 #First we search fot the day of t
301 t_day
= self
.get_next_valid_day(t
)
302 sec_from_morning
= self
.get_min_sec_from_morning()
304 #print "Search for t", time.asctime(time.localtime(t))
305 #print "DR: next day", time.asctime(time.localtime(t_day))
306 #print "DR: sec from morning", time.asctime(time.localtime(sec_from_morning))
308 #We search for the min of all tr.start > sec_from_morning
310 for tr
in self
.timeranges
:
311 tr_start
= tr
.hstart
* 3600 + tr
.mstart
* 3600
312 if tr_start
>= sec_from_morning
:
313 starts
.append(tr_start
)
315 #tr can't be valid, or it will be return at the begining
316 sec_from_morning
= self
.get_next_future_timerange_valid(t
)
317 #print "DR: sec from morning", time.asctime(time.localtime(sec_from_morning))
318 #print "Sec from morning", t_day
319 if sec_from_morning
is not None:
320 if t_day
is not None and sec_from_morning
is not None:
321 return t_day
+ sec_from_morning
323 #Then we search for the next day of t
324 #The sec will be the min of the day
326 t_day2
= self
.get_next_valid_day(t
)
327 sec_from_morning
= self
.get_next_future_timerange_valid(t_day2
)
328 if t_day2
is not None and sec_from_morning
is not None:
329 return t_day2
+ sec_from_morning
331 #I'm not find any valid time
335 def get_next_invalid_day(self
, t
):
336 #print 'DR: get_next_invalid_day for', time.asctime(time.localtime(t))
337 if self
.is_time_day_invalid(t
):
340 next_future_timerange_invalid
= self
.get_next_future_timerange_invalid(t
)
341 #print "next_future_timerange_invalid:", next_future_timerange_invalid
343 #If today there is no more unavalable timerange, search the next day
344 if next_future_timerange_invalid
is None:
345 #print 'DR: get_next_future_timerange_invalid is None'
346 #this day is finish, we check for next period
347 (start_time
, end_time
) = self
.get_start_and_end_time(get_day(t
)+86400)
349 #print 'DR: get_next_future_timerange_invalid is', time.asctime(time.localtime(next_future_timerange_invalid))
350 (start_time
, end_time
) = self
.get_start_and_end_time(t
)
351 #res = get_day(t) + next_future_timerange_invalid
352 #print "Early return"
355 #print 'DR:Start:', time.asctime(time.localtime(start_time))
356 #print 'DR:End:', time.asctime(time.localtime(end_time))
357 #The next invalid day can be t day if there a possible
358 #invalid time range (timerange is not 00->24
359 if next_future_timerange_invalid
!= None:
360 if start_time
<= t
<= end_time
:
361 #print "Early Return next invalid day:", time.asctime(time.localtime(get_day(t)))
364 return get_day(start_time
)
365 else:#Else, there is no possibility than in our start_time<->end_time we got
366 #any invalid time (full period out). So it's end_time+1 sec (tomorow of end_time)
367 #print "Full period out, got end_time", time.asctime(time.localtime(get_day(end_time +1)))
368 return get_day(end_time
+1)
373 def get_next_invalid_time_from_t(self
, t
):
374 #print 'DR:get_next_invalid_time_from_t', time.asctime(time.localtime(t))
375 if not self
.is_time_valid(t
):
376 #print "DR: cool, t is invalid", time.asctime(time.localtime(t))
379 # print "DR: Arg, t is valid", time.asctime(time.localtime(t))
381 #First we search fot the day of t
382 t_day
= self
.get_next_invalid_day(t
)
383 #print "Get next invalid day:", time.asctime(time.localtime(t_day))
384 #print "Is valid day?", self.is_time_valid(t_day)
386 #We search for the min of all tr.start > sec_from_morning
388 #for tr in self.timeranges:
389 # tr_start = tr.hstart * 3600 + tr.mstart * 3600
390 # if tr_start >= sec_from_morning:
391 # starts.append(tr_start)
393 #tr can't be valid, or it will be return at the begining
394 sec_from_morning
= self
.get_next_future_timerange_invalid(t
)
395 #print "TOTO sec_from_morning:", sec_from_morning
396 #Ok we've got a next invalid day and a invalid possibility in
397 #timerange, so the next invalid is this day+sec_from_morning
398 #print "T_day", t_day, "Sec from morning", sec_from_morning
399 if t_day
is not None and sec_from_morning
is not None:
400 return t_day
+ sec_from_morning
+ 1
402 #We've got a day but no sec_from_morning : the timerange is full (0->24h)
403 #so the next invalid is this day at the day_start
404 if t_day
is not None and sec_from_morning
== None:
407 #Then we search for the next day of t
408 #The sec will be the min of the day
410 t_day2
= self
.get_next_invalid_day(t
)
411 sec_from_morning
= self
.get_next_future_timerange_invalid(t_day2
)
412 if t_day2
is not None and sec_from_morning
is not None:
413 return t_day2
+ sec_from_morning
+ 1
415 if t_day2
is not None and sec_from_morning
== None:
418 #I'm not find any valid time
424 #ex: 2007-01-01 - 2008-02-01
425 class CalendarDaterange(Daterange
):
426 def get_start_and_end_time(self
, ref
=None):
427 start_time
= get_start_of_day(self
.syear
, int(self
.smon
), self
.smday
)
428 end_time
= get_end_of_day(self
.eyear
, int(self
.emon
), self
.emday
)
429 return (start_time
, end_time
)
433 #Like tuesday 00:00-24:00
434 class StandardDaterange(Daterange
):
435 def __init__(self
, day
, other
):
439 for timeinterval
in other
.split(','):
440 self
.timeranges
.append(Timerange(timeinterval
.strip()))
442 self
.is_valid_today
= False
445 #It's correct only if the weekday (sunday, etc) is a valid one
446 def is_correct(self
):
447 b
= self
.day
in Daterange
.weekdays
449 print "Error : %s is not a valid day" % self
.day
453 def get_start_and_end_time(self
, ref
=None):
454 now
= time
.localtime(ref
)
455 self
.syear
= now
.tm_year
456 self
.month
= now
.tm_mon
457 #month_start_id = now.tm_mon
458 #month_start = Daterange.get_month_by_id(month_start_id)
459 self
.wday
= now
.tm_wday
460 day_id
= Daterange
.get_weekday_id(self
.day
)
461 today_morning
= get_start_of_day(now
.tm_year
, now
.tm_mon
, now
.tm_mday
)
462 tonight
= get_end_of_day(now
.tm_year
, now
.tm_mon
, now
.tm_mday
)
463 day_diff
= (day_id
- now
.tm_wday
) % 7
464 return (today_morning
+ day_diff
*86400, tonight
+ day_diff
*86400)
467 class MonthWeekDayDaterange(Daterange
):
468 #It's correct only if the weekday (sunday, etc) is a valid one
469 def is_correct(self
):
471 b
&= self
.swday
in Daterange
.weekdays
473 print "Error : %s is not a valid day" % self
.swday
475 b
&= self
.ewday
in Daterange
.weekdays
477 print "Error : %s is not a valid day" % self
.ewday
482 def get_start_and_end_time(self
, ref
=None):
483 now
= time
.localtime(ref
)
486 self
.syear
= now
.tm_year
487 month_id
= Daterange
.get_month_id(self
.smon
)
488 day_start
= find_day_by_weekday_offset(self
.syear
, self
.smon
, self
.swday
, self
.swday_offset
)
489 start_time
= get_start_of_day(self
.syear
, month_id
, day_start
)
492 self
.eyear
= now
.tm_year
493 month_end_id
= Daterange
.get_month_id(self
.emon
)
494 day_end
= find_day_by_weekday_offset(self
.eyear
, self
.emon
, self
.ewday
, self
.ewday_offset
)
495 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
497 now_epoch
= time
.mktime(now
)
498 if start_time
> end_time
: #the period is between years
499 if now_epoch
> end_time
:#check for next year
500 day_end
= find_day_by_weekday_offset(self
.eyear
+ 1, self
.emon
, self
.ewday
, self
.ewday_offset
)
501 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
502 else:#it s just that start was the last year
503 day_start
= find_day_by_weekday_offset(self
.syear
- 1, self
.smon
, self
.swday
, self
.swday_offset
)
504 start_time
= get_start_of_day(self
.syear
- 1, month_id
, day_start
)
506 if now_epoch
> end_time
:#just have to check for next year if necessery
507 day_start
= find_day_by_weekday_offset(self
.syear
+ 1, self
.smon
, self
.swday
, self
.swday_offset
)
508 start_time
= get_start_of_day(self
.syear
+ 1, month_id
, day_start
)
509 day_end
= find_day_by_weekday_offset(self
.eyear
+ 1, self
.emon
, self
.ewday
, self
.ewday_offset
)
510 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
512 return (start_time
, end_time
)
516 class MonthDateDaterange(Daterange
):
517 def get_start_and_end_time(self
, ref
=None):
518 now
= time
.localtime(ref
)
520 self
.syear
= now
.tm_year
521 month_start_id
= Daterange
.get_month_id(self
.smon
)
522 day_start
= find_day_by_offset(self
.syear
, self
.smon
, self
.smday
)
523 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
526 self
.eyear
= now
.tm_year
527 month_end_id
= Daterange
.get_month_id(self
.emon
)
528 day_end
= find_day_by_offset(self
.eyear
, self
.emon
, self
.emday
)
529 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
531 now_epoch
= time
.mktime(now
)
532 if start_time
> end_time
: #the period is between years
533 if now_epoch
> end_time
:#check for next year
534 day_end
= find_day_by_offset(self
.eyear
+ 1, self
.emon
, self
.emday
)
535 end_time
= get_end_of_day(self
.eyear
+ 1, month_end_id
, day_end
)
536 else:#it s just that start was the last year
537 day_start
= find_day_by_offset(self
.syear
-1, self
.smon
, self
.emday
)
538 start_time
= get_start_of_day(self
.syear
-1, month_start_id
, day_start
)
540 if now_epoch
> end_time
:#just have to check for next year if necessery
541 day_start
= find_day_by_offset(self
.syear
+1, self
.smon
, self
.emday
)
542 start_time
= get_start_of_day(self
.syear
+1, month_start_id
, day_start
)
543 day_end
= find_day_by_offset(self
.eyear
+1, self
.emon
, self
.emday
)
544 end_time
= get_end_of_day(self
.eyear
+1, month_end_id
, day_end
)
546 return (start_time
, end_time
)
549 class WeekDayDaterange(Daterange
):
550 def get_start_and_end_time(self
, ref
=None):
551 now
= time
.localtime(ref
)
553 #If no year, it's our year
555 self
.syear
= now
.tm_year
556 month_start_id
= now
.tm_mon
557 month_start
= Daterange
.get_month_by_id(month_start_id
)
558 day_start
= find_day_by_weekday_offset(self
.syear
, month_start
, self
.swday
, self
.swday_offset
)
559 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
563 self
.eyear
= now
.tm_year
564 month_end_id
= now
.tm_mon
565 month_end
= Daterange
.get_month_by_id(month_end_id
)
566 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
567 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
569 #Maybe end_time is before start. So look for the
571 if start_time
> end_time
:
572 month_end_id
= month_end_id
+ 1
573 if month_end_id
> 12:
576 month_end
= Daterange
.get_month_by_id(month_end_id
)
577 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
578 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
580 now_epoch
= time
.mktime(now
)
581 #But maybe we look not ethouth far. We should add a month
582 if end_time
< now_epoch
:
583 month_end_id
= month_end_id
+ 1
584 month_start_id
= month_start_id
+ 1
585 if month_end_id
> 12:
588 if month_start_id
> 12:
592 month_start
= Daterange
.get_month_by_id(month_start_id
)
593 day_start
= find_day_by_weekday_offset(self
.syear
, month_start
, self
.swday
, self
.swday_offset
)
594 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
596 month_end
= Daterange
.get_month_by_id(month_end_id
)
597 day_end
= find_day_by_weekday_offset(self
.eyear
, month_end
, self
.ewday
, self
.ewday_offset
)
598 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
600 return (start_time
, end_time
)
603 class MonthDayDaterange(Daterange
):
604 def get_start_and_end_time(self
, ref
=None):
605 now
= time
.localtime(ref
)
607 self
.syear
= now
.tm_year
608 month_start_id
= now
.tm_mon
609 month_start
= Daterange
.get_month_by_id(month_start_id
)
610 day_start
= find_day_by_offset(self
.syear
, month_start
, self
.smday
)
611 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
614 self
.eyear
= now
.tm_year
615 month_end_id
= now
.tm_mon
616 month_end
= Daterange
.get_month_by_id(month_end_id
)
617 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
618 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
620 now_epoch
= time
.mktime(now
)
622 if start_time
> end_time
:
623 month_end_id
= month_end_id
+ 1
624 if month_end_id
> 12:
627 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
628 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
630 if end_time
< now_epoch
:
631 month_end_id
= month_end_id
+ 1
632 month_start_id
= month_start_id
+ 1
633 if month_end_id
> 12:
636 if month_start_id
> 12:
641 month_start
= Daterange
.get_month_by_id(month_start_id
)
642 day_start
= find_day_by_offset(self
.syear
, month_start
, self
.smday
)
643 start_time
= get_start_of_day(self
.syear
, month_start_id
, day_start
)
646 month_end
= Daterange
.get_month_by_id(month_end_id
)
647 day_end
= find_day_by_offset(self
.eyear
, month_end
, self
.emday
)
648 end_time
= get_end_of_day(self
.eyear
, month_end_id
, day_end
)
650 return (start_time
, end_time
)