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, ''))
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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)