资讯详情 Pendulum Interval 完全指南:理解两个 DateTime 之间的时间区间
📅 2026/10/7 16:10:31
后端【免费下载链接】pendulumPython datetimes made easy项目地址https://gitcode.com/gh_mirrors/pe/pendulum点击查看免费下载导读Interval是 Pendulum 中表示两个日期时间实例之间固定时间区间的核心类型。当你用两个DateTime相减或调用diff()方法时得到的并不是普通的timedelta而是一个Interval——它继承自Duration并额外保留生成它的起止实例从而能提供按年、月、周、日等单位精确拆解的能力同时对 DST夏令时切换天然感知。读完本文你将掌握Interval的实例化方式、全部核心属性、range()区间迭代、in成员判断以及其底层实现与Duration/timedelta的区别。什么是 Interval当你从一个DateTime实例中减去另一个DateTime或使用diff()方法时Pendulum 会返回一个Interval实例 import pendulum start pendulum.datetime(2000, 11, 20) end pendulum.datetime(2016, 11, 5) interval end - start interval.years 15 interval.months 11 interval.in_years() 15 interval.in_months() 191Interval继承自 Duration 类其额外优势在于它知道是哪些实例生成了自己因此可以访问更多方法和属性比如按日历单位拆解出years、months或者获取起止点start/end。在源码中Interval被定义为class Interval(Duration, Generic[_T])其中_T约束为date类型表示它可以同时基于日期与日期时间构建见 src/pendulum/interval.py。与 Duration 的关键差异weeks 属性由于Interval记录的是两个具体日期之间按日历感知的差值它的weeks属性与Duration的计算口径不同# 注意weeks 属性与 Duration 类的计算口径不同 interval.weeks 2 # Duration 类中该值为 832 # 但 days 属性保持一致以兼容 timedelta 类 interval.days 5829这里weeks的差异是刻意的设计Interval.weeks基于精确日历差值PreciseDiff中的days字段除以 7 取整abs(self._delta.days) // 7 * self._sign(self._delta.days)见 src/pendulum/interval.py而Duration.weeks是基于总秒数换算。days属性则保持与timedelta完全一致确保任何期待timedelta行为的代码都能无缝工作。属性一览兼容 timedelta 的属性与Duration一样Interval在属性层面完全兼容timedelta可直接读取days、seconds、microseconds等标准字段。同时它还会暴露total_seconds()、in_days()、in_hours()等换算方法。DST 感知的自定义属性Interval的自定义属性如remaining_days、hours、minutes、remaining_seconds会感知两次日期之间可能发生的 DST 切换并自动调整。以跨夏令时的场景为例 import pendulum start pendulum.datetime(2017, 3, 7, tzAmerica/Toronto) end start.add(days6) interval end - start # timedelta 属性受 DST 影响少了一个小时 interval.days 5 interval.seconds 82800 # interval 属性按日历天数感知 DST interval.remaining_days 6 interval.hours 0 interval.remaining_seconds 0在这个例子中America/Toronto时区在 2017 年 3 月 12 日凌晨发生了 DST 切换时钟拨快一小时因此两个相隔 6 个日历日的时刻其真实时间差只有 5 天 23 小时——timedelta视角的days5, seconds82800如实反映了这一点而Interval的日历视角则认为跨过了 6 个自然日remaining_days6。这正是固定时长与日历日数两种口径的本质区别。上述行为在测试 tests/interval/test_construct.py 中有完整断言interval.days 5、interval.seconds 82800、interval.remaining_days 6、interval.in_days() 6、interval.in_hours() 5 * 24 23。类似的 DST 场景还有欧洲巴黎时区见同文件 tests/interval/test_construct.py同一天 1:30 到次日 1:30in_words()返回1 day而in_hours() 23。重要警告算术运算返回 Duration由于Interval的本质是两个日期时间之间的固定时长大多数算术运算加、减、乘、除、取模等都会返回一个Duration而不是Interval import pendulum dt1 pendulum.datetime(2016, 8, 7, 12, 34, 56) dt2 dt1.add(days6, seconds34) interval pendulum.interval(dt1, dt2) interval * 2 Duration(weeks1, days5, minutes1, seconds8)从源码可以清晰看到这一设计意图Interval的__add__、__sub__、__mul__、__truediv__、__floordiv__、__mod__、__divmod__等方法全部先调用as_duration()将自身转换为Duration再执行运算见 src/pendulum/interval.py。例如interval * 2实际执行的是self.as_duration().__mul__(other)。as_duration()的实现仅保留总秒数def as_duration(self) - Duration: Return the Interval as a Duration. return Duration(secondsself.total_seconds())实例化Instantiation你可以使用pendulum.interval()辅助函数创建一个Interval实例 import pendulum start pendulum.datetime(2000, 1, 1) end pendulum.datetime(2000, 1, 31) interval pendulum.interval(start, end)pendulum.interval()是包级工厂函数签名与Interval构造函数一致interval(start, end, absoluteFalse)见 src/pendulum/init.py。倒置区间inverted interval你也可以创建倒置的区间起点晚于终点此时相关属性会变成负值 interval pendulum.interval(end, start) interval.remaining_days -2如果传入的日期是倒置的但你希望区间始终为正可以设置absoluteTrue关键字参数 interval pendulum.interval(end, start, absoluteTrue) interval.remaining_days 2从源码看absoluteTrue时__new__会直接交换start与endif absolute and start end: end, start start, end见 src/pendulum/interval.py因此构造出的区间起点必然早于终点。构造时的类型校验Interval.__new__在构造时会做两类严格校验见 src/pendulum/interval.py如果起点和终点类型不一致一个是datetime、另一个是date抛出ValueError: Both start and end of an Interval must have the same type如果一个是带时区aware的datetime、另一个是不带时区naive的datetime抛出TypeError: cant compare offset-naive and offset-aware datetimes。测试 tests/interval/test_construct.py 还验证了传入原生datetime对象时interval.start/interval.end会被自动转换为pendulum.DateTime传入倒置参数并开启absolute后start与end会被正确交换。区间迭代range() 方法如果要在区间上迭代可以使用range()方法 import pendulum start pendulum.datetime(2000, 1, 1) end pendulum.datetime(2000, 1, 10) interval pendulum.interval(start, end) for dt in interval.range(days): print(dt) 2000-01-01T00:00:0000:00 2000-01-02T00:00:0000:00 2000-01-03T00:00:0000:00 2000-01-04T00:00:0000:00 2000-01-05T00:00:0000:00 2000-01-06T00:00:0000:00 2000-01-07T00:00:0000:00 2000-01-08T00:00:0000:00 2000-01-09T00:00:0000:00 2000-01-10T00:00:0000:00!!! noterange()支持的迭代单位为years、months、weeks、days、hours、minutes、seconds和microseconds。控制步长amount 参数可以为传入的单位指定一个amount控制每次迭代的间隔长度 for dt in interval.range(days, 2): print(dt) 2000-01-01T00:00:0000:00 2000-01-03T00:00:0000:00 2000-01-05T00:00:0000:00 2000-01-07T00:00:0000:00 2000-01-09T00:00:0000:00range(unit, amount1)的默认amount为 1。从源码看src/pendulum/interval.py迭代器以start为起点反复调用self.start的add或倒置区间时的subtract方法叠加步长直到越过end为止非绝对模式下若区间倒置则改用减法并反向比较。测试 tests/interval/test_range.py 验证了按天迭代正好覆盖起止两端31 天跨 DST 的迭代测试同文件 tests/interval/test_range.py则展示了迭代结果对时区偏移同样敏感。直接迭代 Interval你也可以直接对Interval实例进行迭代此时单位固定为days for dt in interval: print(dt)这得益于Interval.__iter__的实现return self.range(days)见 src/pendulum/interval.py。测试 tests/interval/test_range.py 验证了直接迭代 31 天区间会产出 31 个pendulum.DateTime。成员判断in 关键字可以用in关键字检查一个DateTime实例是否位于区间内部 dt pendulum.datetime(2000, 1, 4) dt in interval TrueInterval.__contains__的实现是一个简单的区间比较return self.start item self.end见 src/pendulum/interval.py。注意边界语义起点与终点本身都包含在区间内。测试 tests/interval/test_range.py 验证了区间内的时刻返回True而早于起点 1 小时的时刻返回False。进阶源码级原理精确日历差值PreciseDiffInterval的核心数据来自precise_diff(_start, _end)返回的PreciseDiff结构见 src/pendulum/interval.py它同时保留了按日历单位年、月、日的精确拆解和按总秒数的拆解。years、months、hours、minutes等属性直接取自_delta而remaining_days取的是_delta.days对 7 取模的结果——这就是它能跨 DST 正确反映过了几个自然日的原因。precise_diff的底层实现位于 rust/src/python/types/precise_diff.rs由 Rust 扩展或纯 Python 回退实现src/pendulum/_helpers.py提供见 src/pendulum/helpers.py 的导入逻辑。相等性、哈希与序列化Interval与另一个Interval比较相等时比较的是(start, end, absolute)三元组与timedelta等其它对象比较时则回退到as_duration()后的时长比较见 src/pendulum/interval.py。因此interval timedelta(days2)是合法的测试 tests/interval/test_behavior.py 对此有断言。__hash__基于(start, end, absolute)支持作为字典键或放入集合。通过__reduce_ex__/_getstate支持pickle序列化且copy.deepcopy会深度复制起止实例见 src/pendulum/interval.py对应测试 tests/interval/test_behavior.py。取反与取绝对值Interval还支持一元运算-interval会返回一个起止互换的新Interval__neg__abs(interval)会返回以absoluteTrue构造的新Interval__abs__二者都保留了类型本身。人类可读输出in_words()Interval继承了Duration的in_words(localeNone, separator )方法可将区间翻译为当前语言环境下的自然语言描述如法语的6 jours 23 heures 58 minutes。它按年、月、周、剩余天、时、分、秒的顺序组装并支持通过pendulum.set_locale()切换语言当所有单位都为零时会回退到0 microseconds之类的表达见 src/pendulum/interval.py。在 tests/interval/test_in_words.py 中有大量多语言断言语料。总结Interval是 Pendulum 中连接日历感知与固定时长两种时间观的桥梁日历视角years、months、remaining_days、weeks等属性精确反映两个日期之间跨过了多少自然年、月、日时长视角days、seconds、total_seconds()、in_*()系列方法与timedelta完全兼容可无缝用于任何期望标准timedelta的代码DST 感知自定义属性会自动补偿夏令时切换带来的少一小时或多一小时偏差迭代与判断range(unit, amount)、直接迭代、in成员判断让区间成为可消费的数据结构。需要注意的是任何算术运算、-、*、/、%等都会将结果降级为Duration因为运算结果不再是两个具体时刻之间的区间而只是一个时长。理解了这一设计取舍你就能在日程排期、跨时区统计、日历跨度计算等场景中正确地选择Interval或Duration。相关参考完整的 API 定义见 src/pendulum/interval.pyinterval()工厂函数见 src/pendulum/init.py配套测试位于 tests/interval/ 目录构造、行为、迭代、算术、哈希与多语言输出共六个测试文件。赞分享后端【免费下载链接】pendulumPython datetimes made easy项目地址https://gitcode.com/gh_mirrors/pe/pendulum点击查看免费下载相关推荐深度解析LightRAG构建高效知识图谱增强检索系统的架构实践深度解析LightRAG构建高效知识图谱增强检索系统的架构实践 在当今信息爆炸的时代传统检索系统面临语义理解不足、上下文关联缺失等挑战。LightRAG作为人工智能RAG大模型知识图谱本地部署Pendulum Interval类终极指南掌握时间区间操作的5个核心技巧Pendulum Interval类终极指南掌握时间区间操作的5个核心技巧 Pendulum是一个强大的Python日期时间库它的Interval类让时间区后端Pendulum时间戳转换终极指南从Unix时间到DateTime的完整教程Pendulum时间戳转换终极指南从Unix时间到DateTime的完整教程 在处理时间数据时Unix时间戳转换是Python开发者经常遇到的挑战。Pend后端上一篇RESTful API版本演进终极指南10个向后兼容与平滑升级策略下一篇ni项目安全最佳实践如何避免常见的安全隐患创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考