填补Python中的时间空白

填补Python中的时间空白,python,Python,在给定端点和它们之间的一些点的情况下,是否有更优雅的方法来确定排他/穷举间隔 下面的测试以一个月的计费周期和该月内的几个点或间隔分区来描述场景。我想得到一个成对的列表,详细说明由给定边界产生的各个间隔 def test_fill_time_gaps(self): bill_period = (localtz_parse('2018-03-01'), localtz_parse('2018-03-31')) # test fill first gap periods =

在给定端点和它们之间的一些点的情况下,是否有更优雅的方法来确定排他/穷举间隔

下面的测试以一个月的计费周期和该月内的几个点或间隔分区来描述场景。我想得到一个成对的列表,详细说明由给定边界产生的各个间隔

def test_fill_time_gaps(self):
    bill_period = (localtz_parse('2018-03-01'), localtz_parse('2018-03-31'))

    # test fill first gap
    periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-31'))])
    self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
                               (localtz_parse('2018-03-04'), localtz_parse('2018-03-31'))])

    periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                                                           (localtz_parse('2018-03-05'), localtz_parse('2018-03-31'))])
    self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
                               (localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                               (localtz_parse('2018-03-05'), localtz_parse('2018-03-31'))])

    # test fill first and last gap
    periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-15'))])
    self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
                               (localtz_parse('2018-03-04'), localtz_parse('2018-03-15')),
                               (localtz_parse('2018-03-15'), localtz_parse('2018-03-31'))])

    # test fill first gap and gap in between
    periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                                                           (localtz_parse('2018-03-08'), localtz_parse('2018-03-31'))])
    self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
                               (localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                               (localtz_parse('2018-03-05'), localtz_parse('2018-03-08')),
                               (localtz_parse('2018-03-08'), localtz_parse('2018-03-31'))])

    # test fill first gap and gap in between and last gap
    periods = fill_time_gaps(bill_period, [(localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                                                           (localtz_parse('2018-03-08'), localtz_parse('2018-03-15'))])
    self.assertEqual(periods, [(localtz_parse('2018-03-01'), localtz_parse('2018-03-04')),
                               (localtz_parse('2018-03-04'), localtz_parse('2018-03-05')),
                               (localtz_parse('2018-03-05'), localtz_parse('2018-03-08')),
                               (localtz_parse('2018-03-08'), localtz_parse('2018-03-15')),
                               (localtz_parse('2018-03-15'), localtz_parse('2018-03-31'))])
以下是我的初步尝试:

def fill_time_gaps(boundary, periods):
    """
    Given a period boundary, fill in gaps within given periods
    Assuming periods are in seqential order
    :param boundary: period boundry
    :param periods: sequence of periods, should contain at least one period
    :return: sequence of periods with filled gaps
    """
    if not len(periods):
        raise Exception('periods should contain at least one period')

    # works by stepping through the periods and compare the against the way-point
    # to determine if there is a gap
    result = []
    bound_start, bound_end = boundary
    way_point = bound_start

    for period in periods:
        period_start, period_end = period

        if period_start > way_point:
            gap = (way_point, period_start)
            result.append(gap)

        result.append(period)
        way_point = period_end

    # fill the last gap
    if way_point < bound_end:
        result.append((way_point, bound_end))

    return result
def填充时间间隔(边界、时段):
"""
给定周期边界,在给定周期内填充间隙
假设周期按顺序排列
:参数边界:周期边界
:param periods:期间序列,应至少包含一个期间
:return:填充间隙的时段序列
"""
如果不是len(周期):
引发异常('期间应至少包含一个期间')
#通过逐步完成周期并与路径点进行比较来工作
#确定是否存在间隙
结果=[]
绑定\u开始,绑定\u结束=边界
路\点=绑定\起点
对于期间中的期间:
时段\开始,时段\结束=时段
如果周期开始>方向点:
差距=(方向点,周期点)
结果追加(gap)
结果.追加(句号)
路\点=周期\结束
#填补最后的空白
如果路径点<边界点:
result.append((方式\点,绑定\结束))
返回结果
但这似乎有点“愚蠢”(有时哑代码是好代码,但在本例中不确定),我不确定这是否也是防弹的,但它通过了我现有的测试


我很想知道是否有更好的方法来解决这个问题?

由于填充逻辑实际上并不依赖于日期时间表示,为了便于理解,我将其缩减为日数

  • 获取计费端点并包括提供的内部周期 分隔器
  • 创建一组此项以删除重复项(计费端点) 并对生成的“栅栏柱”进行排序
  • 逐步完成此序列,并从相邻日期开始构建周期
  • 将该列表返回给调用者
代码:

输出:

((1, 2), (2, 3), (3, 31))
((1, 8), (8, 31))
((1, 10), (10, 31))
((1, 4), (4, 5), (5, 12), (12, 31))

对于上一个案例
(4,5,12)
,句点总是以(开始,结束)元组的形式出现,您的函数在本案例中是否工作
(4,5)、(5,12)
否,因为我只显示了关键逻辑。处理元组输入是将任何输入元组展平到其组成边界的单步处理细节。这部分可以在两端完成。我明白了,谢谢你的投入,我会给它一点时间看看是否还有更多的答案。
((1, 2), (2, 3), (3, 31))
((1, 8), (8, 31))
((1, 10), (10, 31))
((1, 4), (4, 5), (5, 12), (12, 31))