apppublic/aidocs/timeUtils.md
2025-10-05 11:23:33 +08:00

521 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 日期与时间处理工具库技术文档
本模块提供了一系列用于日期、时间处理和格式转换的实用函数,支持日期计算、字符串与时间对象互转、模式匹配等功能,适用于数据分析、任务调度、日志处理等场景。
---
## 目录
- [1. 导入依赖](#1-导入依赖)
- [2. 全局变量](#2-全局变量)
- [3. 核心功能函数](#3-核心功能函数)
- [3.1 时间差计算](#31-days_betweendate_str1-date_str2)
- [3.2 当前时间相关](#32-monthfirstday--curdatetime--curdatestring--curtimestring--timestampstr)
- [3.3 判断类函数](#33-ismonthlastday--isleapyear--is_monthend)
- [3.4 时间戳操作](#34-timestamp--timestampsecond--timestampadd--timestampsub--timestamp2dt)
- [3.5 日期加减运算](#35-addseconds--addmonths--addyears--dateadd--strdate_add)
- [3.6 日期格式化与解析](#36-date2str--time2str--str2date--str2datetime--str2date)
- [3.7 特殊日期计算](#37-firstsunday)
- [3.8 时间对齐StepedTimestamp](#38-steppedtimestamp)
- [3.9 周/季度辅助函数](#39-date_weekinyear--date_season)
- [3.10 模式匹配](#310-is_match_pattern)
---
## 1. 导入依赖
```python
import os, sys
import time
from datetime import date, timedelta, datetime
```
> **说明**
> - `os`, `sys`:保留接口扩展性。
> - `time`:用于时间戳和结构化时间处理。
> - `datetime`:核心日期时间处理模块。
---
## 2. 全局变量
### `leapMonthDays`, `unleapMonthDays`
```python
leapMonthDays = [0,31,29,31,30,31,30,31,31,30,31,30,31] # 闰年各月天数索引从1开始
unleapMonthDays = [0,31,28,31,30,31,30,31,31,30,31,30,31] # 平年各月天数
```
> **用途**:快速查询某月最大天数,结合 `isLeapYear()` 使用。
---
## 3. 核心功能函数
### 3.1 `days_between(date_str1, date_str2)`
计算两个日期字符串之间的天数差(绝对值)。
#### 参数
| 参数 | 类型 | 描述 |
|-------------|--------|--------------------------|
| `date_str1` | str | 起始日期,格式 `'YYYY-MM-DD'` |
| `date_str2` | str | 结束日期,格式 `'YYYY-MM-DD'` |
#### 返回值
- `int`:相差的天数(非负整数)
#### 示例
```python
days_between("2023-01-01", "2023-01-10") # 返回 9
```
---
### 3.2 `monthfirstday()`
获取当前月份的第一天。
#### 返回值
- `str`:格式为 `'YYYY-MM-01'`
#### 示例
```python
monthfirstday() # 如 '2025-04-01'
```
---
### 3.3 `curDatetime()`
获取当前精确时间的 `datetime` 对象。
#### 返回值
- `datetime.datetime`:当前系统时间
---
### 3.4 `curDateString()`
获取当前日期字符串。
#### 返回值
- `str`:格式 `'YYYY-MM-DD'`
---
### 3.5 `curTimeString()`
获取当前时间字符串(时分秒)。
#### 返回值
- `str`:格式 `'HH:MM:SS'`
---
### 3.6 `timestampstr()`
生成带毫秒的完整时间戳字符串。
#### 返回值
- `str`:格式 `'YYYY-MM-DD HH:MM:SS.fff'`
#### 示例
```python
timestampstr() # 如 '2025-04-05 14:30:22.123'
```
---
### 3.7 `isMonthLastDay(d)`
判断给定 `datetime` 是否是当月最后一天。
#### 参数
| 参数 | 类型 | 描述 |
|------|----------------|------------------|
| `d` | `datetime` | 待判断的时间对象 |
#### 返回值
- `bool`:若是月末返回 `True`
#### 原理
通过加一天后判断月份是否变化。
---
### 3.8 `isLeapYear(year)`
判断是否为闰年。
> ⚠️ **注意**:原代码逻辑有误!
#### 错误分析
```python
if year % 4 == 0 and year % 100 == 0 and not (year % 400 == 0):
```
此条件仅在“能被100整除但不能被400整除”时返回 `True`,即把**平年**判为闰年。
#### 正确应为:
```python
def isLeapYear(year):
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
```
> ✅ 建议修复该函数!
---
### 3.9 `timestamp(dt)` 和 `timeStampSecond(dt)`
`datetime` 转换为 Unix 时间戳。
| 函数名 | 精度 | 说明 |
|-------------------|------------|------------------------------|
| `timestamp(dt)` | 微秒级 | 包含 `.microsecond` |
| `timeStampSecond(dt)` | 秒级 | 忽略微秒部分 |
#### 参数
- `dt`: `datetime` 对象
#### 返回值
- `int`:自 1970-01-01 UTC 起的秒数
---
### 3.10 `addSeconds(dt, s)`
给时间对象增加若干秒。
#### 参数
| 参数 | 类型 | 说明 |
|------|--------------|--------------------|
| `dt` | `datetime` | 原始时间 |
| `s` | `int` | 要增加的秒数 |
#### 返回值
- `datetime`:新的时间对象
---
### 3.11 `monthMaxDay(y, m)`
获取指定年份某月的最大天数(考虑闰年)。
#### 参数
| 参数 | 类型 | 说明 |
|------|-------|------------|
| `y` | int | 年份 |
| `m` | int | 月份1~12|
#### 返回值
- `int`:该月最多多少天
---
### 3.12 `date2str(dt=None)`
`datetime` 转为 `'YYYY-MM-DD'` 字符串。
#### 参数
- `dt`: 可选 `datetime` 对象;若未传则使用当前时间
#### 返回值
- `str`:格式化日期字符串
---
### 3.13 `time2str(dt)`
⚠️ **存在 Bug**
```python
return '%02d:%02d:%02d' % (dt.hour, dt, minute, dt.second)
```
错误使用了 `dt,minute`(语法错误),应为 `dt.minute`
#### 修正版本
```python
def time2str(dt):
return '%02d:%02d:%02d' % (dt.hour, dt.minute, dt.second)
```
---
### 3.14 `str2Date(dstr)` 和 `str2Datetime(dstr)`
#### `str2Date(dstr)`
尝试解析形如 `'YYYY-MM-DD [HH:MM:SS]'` 的字符串为 `datetime` 对象。
> **警告**:内部调用了不存在的 `ymdDate(...)` 函数前就执行拆分,且异常处理打印但不中断。
##### 改进建议:
- 统一使用标准库 `datetime.strptime`
- 移除冗余中间步骤
#### `str2Datetime(dstr)`
更稳健的实现,推荐使用。
##### 支持格式
- `'YYYY-MM-DD'`
- `'YYYY-MM-DD HH:MM:SS'`
##### 返回值
- `datetime` 对象
---
### 3.15 `ymdDate(y, m, d, H=0, M=0, S=0)`
构造 `datetime` 实例的快捷方式。
#### 参数
年、月、日、时、分、秒均可指定默认为0。
#### 示例
```python
ymdDate(2025, 4, 5, 10, 30) # 2025-04-05 10:30:00
```
---
### 3.16 `strdate_add(date_str, days=0, months=0, years=0)`
对日期字符串进行加减操作并返回新字符串。
#### 参数
支持同时添加天、月、年。
#### 执行顺序
1.`days`
2.`months`
3.`years`
> 自动处理跨月/跨年边界,并确保不会出现非法日期(如 2月30日
#### 示例
```python
strdate_add("2024-01-31", months=1) # 返回 "2024-02-29"(自动调整到月底)
```
---
### 3.17 `addMonths(dt, months)` 和 `addYears(dt, years)`
#### `addMonths(dt, months)`
安全地增加月份,自动修正超出范围的日期(如 1月31日 +1月 → 2月29日或28日
#### `addYears(dt, years)`
同理考虑闰年导致2月可能只有28天。
---
### 3.18 `dateAdd(dt, days=0, months=0, years=0)`
综合日期加法入口函数,按顺序应用增量。
---
### 3.19 `firstSunday(dt)`
返回大于等于输入日期的第一个周日。
> 注意Python 中 `weekday()` 返回 0~6 表示周一至周日。
> 因此 `(7 - weekday()) % 7` 更准确。
当前实现假设 `weekday()==6` 是周六?实际应为周日。
#### 存疑逻辑
```python
f = dt.weekday()
if f < 6:
return dt + timedelta(7 - f)
else:
return dt
```
这表示:
- 若不是周日(即 0~5则加 `(7-f)`
- 若是周日6直接返回
✅ 实际上这是正确的:`weekday()` 返回 0=周一 ... 6=周日
所以当 `f=6`(周日)时无需移动。
✔️ 此函数逻辑正确。
---
### 3.20 时间格式常量与函数
```python
DTFORMAT = '%Y%m%d %H%M%S'
```
#### `getCurrentTimeStamp()`
获取当前时间按 `DTFORMAT` 格式的字符串。
#### `TimeStamp(t)`
`struct_time` 格式化为上述格式。
#### `timestampAdd(ts1, ts2)`
将两个时间字符串相加(`ts2` 可为秒数或时间字符串)
> ❌ 存在类型判断错误:
```python
if type(ts2)=='' :
```
应改为:
```python
if isinstance(ts2, str):
```
否则会出错。
#### `timestampSub(ts1, ts2)`
计算两个 `DTFORMAT` 时间之间的秒数差。
---
### 3.21 `StepedTimestamp(baseTs, ts, step)`
将时间 `ts` 对齐到以 `baseTs` 为起点、步长为 `step` 秒的时间网格。
#### 应用场景
- 数据采样对齐
- 定时任务触发点归一化
#### 参数
| 参数 | 类型 | 说明 |
|----------|--------|------------------------|
| `baseTs` | str | 基准时间DTFORMAT |
| `ts` | str | 当前时间 |
| `step` | int | 步长(秒) |
#### 返回值
- 最近的对齐时间点(向上或向下取整)
---
### 3.22 `timestamp2dt(t)`
将 Unix 时间戳(秒)转为 `datetime` 对象。
---
### 3.23 `date_weekinyear(date_str)`
获取日期所在年的第几周ISO 周编号)。
#### 返回值
- `str``'YYYY-W'` 形式,其中 `W` 为两位周数
> 使用 `%W`(基于周一开始的周),而非 ISO 标准 `%U` 或 `isocalendar()`
---
### 3.24 `date_season(date_str)`
根据月份划分季节:
| 月份 | 季度 |
|----------|------|
| 13 | 1 |
| 46 | 2 |
| 79 | 3 |
| 1012 | 4 |
#### 返回值
- `str``'YYYYQ'`,如 `'20251'` 表示2025年第1季度
---
### 3.25 `str2date(sd)`
`'YYYY-MM-DD'` 字符串转为 `date` 对象。
#### 示例
```python
str2date("2025-04-05") # 返回 date(2025, 4, 5)
```
---
### 3.26 `is_monthend(dt)`
判断日期是否为月末。
#### 参数
- `dt`: `str``date` 对象
#### 方法
+1天后看月份是否改变。
---
### 3.27 `is_match_pattern(pattern, strdate)`
判断某日期是否符合特定调度模式。
#### 支持的模式
| 模式 | 含义 | 示例 |
|--------------|----------------------------------|-------------------------|
| `'D'` | 每日触发 | `'D'` |
| `'W[0-6]'` | 每周星期X0=周一...6=周日) | `'W0'`=每周一 |
| `'M0'` | 每月最后一天 | `'M0'` |
| `'Mdd'` | 每月第dd天 | `'M15'`=每月15日 |
| `'Sx-dd'` | 每季度第x月第dd天 | `'S1-01'`=季初第一天 |
| `'Ym-dd'` | 每年m月dd日 | `'Y12-25'`=每年12月25日 |
#### 返回值
- `bool`:是否匹配
#### 注意事项
- `Sx-dd``x %= 4`即循环每4个月视为一个季度
- 调试信息 `print(f'{m=}-{d=}, ...')` 建议移除生产环境
---
## 4. 已知问题汇总(建议修复)
| 函数名 | 问题描述 | 建议修改 |
|----------------|------------------------------------------------|----------|
| `isLeapYear` | 条件反向,导致逻辑错误 | ✅ 重写 |
| `time2str` | 引用 `dt,minute` 报语法错误 | ✅ 修复拼写 |
| `timestampAdd` | `type(ts2)==''` 永远为假 | ✅ 改为 `isinstance(ts2, str)` |
| `str2Date` | 使用未定义函数 `ymdDate` 在 try 外部可能发生错误 | ✅ 重构或删除冗余逻辑 |
| `str2Datetime` | 不支持毫秒 | ✅ 可拓展支持 |
---
## 5. 使用示例
```python
# 计算间隔
print(days_between("2023-01-01", "2023-12-31")) # 364
# 获取今天
print(curDateString()) # 2025-04-05
# 加一个月
print(strdate_add("2024-01-31", months=1)) # 2024-02-29
# 判断是否为月末
print(is_monthend("2025-04-30")) # True
# 匹配每周五
print(is_match_pattern("W4", "2025-04-11")) # True假设是周五
```
---
## 6. 总结
本工具包提供了丰富的日期时间操作能力,适合嵌入数据处理流水线或定时任务系统中。尽管存在少量 bug 和可优化空间,整体设计清晰、功能完整。
> 📌 推荐在正式使用前进行单元测试,并优先修复已知缺陷。
---
**版本**: v1.0
**作者**: Auto-generated Documentation
**更新时间**: 2025-04-05