def test_validate_time_window(self): ts1 = ku.kts(2021, 1, 2, 3, 4, 5) ts2 = ku.kts(2021, 1, 3, 4, 5, 6) dt1 = kdate(2021, 1, 2) t1, msg = ktw.validate_time_window(window_start=ts1, window_end=ts2, window_date=dt1) self.assertFalse(t1) t2, msg = ktw.validate_time_window(window_start=ts1, window_end=ts2, days=2) self.assertFalse(t2) t3a, msg = ktw.validate_time_window(window_start=ts2, window_end=ts1) self.assertFalse(t3a) t3b, msg = ktw.validate_time_window(window_start=ts1, window_end=ts2) self.assertEqual((t3b, msg), (True, '')) t4, msg = ktw.validate_time_window(window_start=ts1, days=5) self.assertEqual((t4, msg), (True, ''))
def decode_time_window_limits(window_start: Optional[kdatelike] = None, window_end: Optional[kdatelike] = None, window_date: Optional[kdate] = None, auto_window: Optional[str] = None, days: Optional[int] = None, year: Optional[int] = None, # weekdays: Optional[List[str]] = None, # last_weekday: Optional[str] = None, filename: Optional[str] = None, frequency: Optional[str] = None, tz=pytz.utc, time_type: str = 'datetime') \ -> Union[Tuple[kdatetime, kdatetime], Tuple[kdate, kdate]]: # window_end is always exclusive (i.e., not included) assert time_type in ['datetime', 'date'] assert frequency in valid_frequency or frequency is None assert auto_window in valid_auto_window or auto_window is None # helper today = ku.to_tz_aware(ku.today(tz), tz) w_start = ku.to_tz_aware(window_start, tz) w_end = ku.to_tz_aware(window_end, tz) if window_start and window_end: pass # nothing to do # elif auto_window in ['bookmark', 'leftover']: # w_start, w_end = decode_auto_window_bookmarks(w_start, frequency, auto_window, cooling, tz, # bookmark_group=bookmark_group, # bookmark_name=bookmark_name) elif window_date: w_start = ku.dt_to_ts(window_date, tz=tz) w_end = w_start + timedelta(days=1) elif auto_window: w_start, w_end = decode_auto_window(auto_window, tz=tz, days=days, filename=filename) elif window_start and days: w_end = w_start + timedelta(days=days) elif window_end and days: w_start = w_end - timedelta(days=days) elif days: w_end = today w_start = w_end - timedelta(days=days) elif year: w_start = ku.kts(year, 1, 1, tz=tz) w_end = ku.kts(year+1, 1, 1, tz=tz) if today < w_end: w_end = today else: raise ku.KarnakException('not enough parameters to determine time window limits.') _w_start = ku.ts_to_dt(w_start) if time_type == 'date' else w_start _w_end = ku.ts_to_dt_end_of_day(w_end) if time_type == 'date' else w_end return _w_start, _w_end
def decode_auto_window(auto_window: str, tz=pytz.utc, days: Optional[int] = None, filename: Optional[str] = None) \ -> Tuple[Optional[kdatetime], Optional[kdatetime]]: # this does not handle bookmarks assert auto_window in valid_auto_window_basic # date windows are inclusive in start, exclusive (not included) in end # that means: if window_end is today, than the last day included in window is yesterday # helpers today = ku.dt_to_ts(ku.today(tz), tz=tz) tomorrow = ku.dt_to_ts(ku.today(tz), tz=tz) + timedelta(days=1) yesterday = ku.dt_to_ts(ku.yesterday(tz), tz=tz) current_year = today.year current_month = today.month previous_month = current_month - 1 previous_month_year = current_year if previous_month == 0: previous_month = 12 previous_month_year = current_year - 1 if auto_window == 'full': start_date = None end_date = None elif auto_window == 'last-year': start_date = ku.kts(current_year - 1, 1, 1, tz=tz) end_date = ku.kts(current_year, 1, 1, tz=tz) elif auto_window == 'ytd': start_date = ku.kts(current_year, 1, 1, tz=tz) end_date = today elif auto_window == 'last-month': start_date = ku.kts(previous_month_year, previous_month, 1, tz=tz) end_date = ku.kts(current_year, current_month, 1, tz=tz) elif auto_window == 'mtd': start_date = ku.kts(current_year, current_month, 1, tz=tz) end_date = today elif auto_window in ['yesterday', 'today']: if auto_window == 'today': end_date = tomorrow elif auto_window == 'yesterday': end_date = today else: assert False _days = 1 if days is None else days start_date = end_date - timedelta(days=_days) elif auto_window == 'filename' and filename is not None: filename_ts = ku.parse_filename_timestamp(filename, tz) return filename_ts, None else: assert False return start_date, end_date
def slice_time_window(window_start: Optional[kdatelike] = None, window_end: Optional[kdatelike] = None, weekdays: Optional[List[str]] = None, last_weekday: Optional[str] = None, frequency: Optional[str] = None, tz=pytz.utc, time_type: str = 'datetime') \ -> List[Tuple[kdatelike, kdatelike]]: def filter_weekdays(lst: List[Tuple[kdatetime, kdatetime]]) \ -> List[Tuple[kdatetime, kdatetime]]: if (weekdays is None and last_weekday is None) or frequency != 'day': return lst weekdays_included_str = weekdays if weekdays is not None else [last_weekday] weekdays_included = [ku.weekday_str_to_int(d) for d in weekdays_included_str] filtered_lst = [t for t in lst if t[0].weekday() in weekdays_included] if last_weekday is not None: dt_start_list = [ku.ts_to_dt(t1) for (t1, t2) in filtered_lst] max_date = max(dt_start_list) double_filtered_lst = [t for t in filtered_lst if ku.ts_to_dt(t[0]) == max_date] return double_filtered_lst else: return filtered_lst def format_result(lst: List[Tuple[kdatetime, kdatetime]]) \ -> List[Tuple[kdatelike, kdatelike]]: ret = filter_weekdays(lst) if time_type == 'date': ret = [(ku.ts_to_dt(xs), ku.ts_to_dt_end_of_day(xe)) for (xs, xe) in ret] return ret w_start = window_start w_end = window_end if w_start is None and w_end is None: # empty window. in this case, both limits should be None return [] assert w_start is not None and w_end is not None w_end_adj = w_end - timedelta(milliseconds=1) if w_start >= w_end: # start > end return [] # window start and window end must be both defined or both undefined # overlapping frequencies have a single window if frequency in valid_overlapping_frequency or frequency is None: # or auto_window == 'leftover': return format_result([(w_start, w_end)]) # non-overlapping frequencies start here elif frequency == 'year': # always whole years, from first to last day first = w_start.year last = w_end_adj.year slices = [] for y in range(first, last+1): year_start = ku.kts(y, 1, 1, tz=tz) year_end = ku.kts(y+1, 1, 1, tz=tz) slices.append((year_start, year_end)) return format_result(slices) elif frequency == 'month': # always whole months, from first to last day first = kdate(w_start.year, w_start.month, 1) last = kdate(w_end_adj.year, w_end_adj.month, 1) slices = [] m = first while m <= last: month_start = ku.kts(m.year, m.month, 1, tz=tz) month_end = ku.dt_to_ts(ku.dt_next_month(month_start), tz) slices.append((month_start, month_end)) m = ku.dt_next_month(m) return format_result(slices) elif frequency == 'day': first_date = w_start.date() last = kdate(w_end_adj.year, w_end_adj.month, w_end_adj.day) slices = [] dt = first_date while dt <= last: next_dt = dt + timedelta(days=1) ts = ku.dt_to_ts(dt, tz) next_ts = ku.dt_to_ts(next_dt, tz) slices.append((ts, next_ts)) dt = next_dt return format_result(slices) elif frequency == 'hour': first = ku.kts(w_start.year, w_start.month, w_start.day, w_start.hour, tz=tz) last = ku.kts(w_end_adj.year, w_end_adj.month, w_end_adj.day, w_end_adj.hour, tz=tz) slices = [] ts = first while ts <= last: next_ts = ts + timedelta(hours=1) slices.append((ts, next_ts)) ts = next_ts return format_result(slices) elif frequency == 'minute': first = ku.kts(w_start.year, w_start.month, w_start.day, w_start.hour, w_start.minute, tz=tz) last = ku.kts(w_end_adj.year, w_end_adj.month, w_end_adj.day, w_end_adj.hour, w_end_adj.minute, tz=tz) slices = [] ts = first while ts <= last: next_ts = ts + timedelta(minutes=1) slices.append((ts, next_ts)) ts = next_ts return format_result(slices) elif frequency in ['5min', '15min', '20min', '30min']: x_min = int(frequency.replace('min', '')) first = ku.kts(w_start.year, w_start.month, w_start.day, w_start.hour, w_start.minute, tz=tz) last = ku.kts(w_end_adj.year, w_end_adj.month, w_end_adj.day, w_end_adj.hour, w_end_adj.minute, tz=tz) slices = [] ts = first while ts <= last: next_ts = ts + timedelta(minutes=x_min) slices.append((ts, next_ts)) ts = next_ts return format_result(slices) else: assert False
def test_decode_time_window_slices(self): tz = pytz.utc ts1 = ku.kts(2022, 1, 1, 0, 0, 0, tz=tz) ts1b = ku.kts(2022, 1, 1, 12, 0, 0, tz=tz) ts2 = ku.kts(2022, 1, 2, 0, 0, 0, tz=tz) ts3 = ku.kts(2022, 1, 3, 0, 0, 0, tz=tz) ts3b = ku.kts(2022, 1, 3, 12, 0, 0, tz=tz) dt1_1 = kdate(2022, 1, 1) dt1_2 = kdate(2022, 1, 2) dt1_3 = kdate(2022, 1, 3) dt1_4 = kdate(2022, 1, 4) dt1_15 = kdate(2022, 1, 15) dt1_16 = kdate(2022, 1, 16) dt1_17 = kdate(2022, 1, 17) dt2_16 = kdate(2022, 2, 16) today_dt = ku.today(tz=tz) today_ts = ku.dt_to_ts(today_dt, tz=tz) tomorrow_dt = today_dt + timedelta(days=1) tomorrow_ts = today_ts + timedelta(days=1) yesterday_dt = today_dt - timedelta(days=1) yesterday_ts = today_ts - timedelta(days=1) current_year = today_dt.year current_month_start = kdate(today_dt.year, today_dt.month, 1) next_month_start = (current_month_start + timedelta(days=32)).replace(day=1) previous_month_start = (current_month_start - timedelta(days=1)).replace(day=1) # window_start and window_end t1a = ktw.decode_time_window_slices(window_start=ts1, window_end=ts2) self.assertEqual([(ts1, ts2)], t1a) t1b = ktw.decode_time_window_slices(window_start=ts1, window_end=ts2, time_type='date') self.assertEqual([(dt1_1, dt1_2)], t1b) t1c = ktw.decode_time_window_slices(window_start=dt1_1, window_end=dt1_2, time_type='date') self.assertEqual([(dt1_1, dt1_2)], t1c) tx = ktw.decode_time_window_slices(window_start=ts1, window_end=ts3b, time_type='date') self.assertEqual([(dt1_1, dt1_4)], tx) tx = ktw.decode_time_window_slices(window_start=ts1, window_end=ts3b, time_type='date', frequency='day') self.assertEqual([(dt1_1, dt1_2), (dt1_2, dt1_3), (dt1_3, dt1_4)], tx) # test days tx = ktw.decode_time_window_slices(window_start=ts1, days=2, time_type='date', frequency='day') self.assertEqual([(dt1_1, dt1_2), (dt1_2, dt1_3)], tx) tx = ktw.decode_time_window_slices(window_end=dt1_3, days=2, time_type='date') self.assertEqual([(dt1_1, dt1_3)], tx) tx = ktw.decode_time_window_slices(window_end=ts3, days=2, time_type='date') self.assertEqual([(dt1_1, dt1_3)], tx) tx = ktw.decode_time_window_slices(window_end=ts3b, days=2, time_type='date') # in this case, rounding up get 3 days. we believe this is the right thing. self.assertEqual([(dt1_1, dt1_4)], tx) tx = ktw.decode_time_window_slices(window_end=ts3b, days=2, time_type='datetime') self.assertEqual([(ts1b, ts3b)], tx) # test year tx = ktw.decode_time_window_slices(year=2021, time_type='date') self.assertEqual([(kdate(2021, 1, 1), kdate(2022, 1, 1))], tx) # test window_date tx = ktw.decode_time_window_slices(window_date=dt1_2, time_type='datetime') self.assertEqual([(ts2, ts3)], tx) # test weekdays tx = ktw.decode_time_window_slices(window_start=dt1_1, window_end=dt1_17, weekdays=['sun', 'tue'], time_type='date', frequency='day') txs = ktw.time_window_slices_start(tx) self.assertEqual([dt1_2, dt1_4, kdate(2022, 1, 9), kdate(2022, 1, 11), dt1_16], txs) # test last_weekday tx = ktw.decode_time_window_slices(window_start=dt1_1, window_end=dt1_16, last_weekday='sun', time_type='date', frequency='day') txs = ktw.time_window_slices_start(tx) self.assertEqual([kdate(2022, 1, 9)], txs) tx = ktw.decode_time_window_slices(window_start=dt1_1, window_end=dt1_17, last_weekday='sun', time_type='date', frequency='day') txs = ktw.time_window_slices_start(tx) self.assertEqual([dt1_16], txs) # # test auto_window # # today tx = ktw.decode_time_window_slices(auto_window='today', time_type='date') self.assertEqual([(today_dt, tomorrow_dt)], tx) tx = ktw.decode_time_window_slices(auto_window='today', time_type='datetime') self.assertEqual([(today_ts, tomorrow_ts)], tx) tx = ktw.decode_time_window_slices(auto_window='today', days=2, time_type='date') self.assertEqual([(yesterday_dt, tomorrow_dt)], tx) # yesterday with days tx = ktw.decode_time_window_slices(auto_window='yesterday', time_type='date') self.assertEqual([(yesterday_dt, today_dt)], tx) tx = ktw.decode_time_window_slices(auto_window='yesterday', time_type='datetime') self.assertEqual([(yesterday_ts, today_ts)], tx) tx = ktw.decode_time_window_slices(auto_window='yesterday', days=2, time_type='date') self.assertEqual([(yesterday_dt - timedelta(days=1), today_dt)], tx) # full tx = ktw.decode_time_window_slices(auto_window='full', time_type='datetime') self.assertEqual([], tx) # last-year tx = ktw.decode_time_window_slices(auto_window='last-year', time_type='date') self.assertEqual([(kdate(current_year-1, 1, 1), kdate(current_year, 1, 1))], tx) # ytd tx = ktw.decode_time_window_slices(auto_window='ytd', time_type='date') self.assertEqual([(kdate(current_year, 1, 1), today_dt)], tx) # last-month tx = ktw.decode_time_window_slices(auto_window='last-month', time_type='date') self.assertEqual([(previous_month_start, current_month_start)], tx) # mtd tx = ktw.decode_time_window_slices(auto_window='mtd', time_type='date') self.assertEqual([(current_month_start, today_dt)], tx) # filename tx = ktw.decode_time_window_slices(auto_window='filename', time_type='date', filename='xpto-file-20220102-ypt.xxx') self.assertEqual([(dt1_2, dt1_3)], tx)