如何定义Hypothesis策略生成兼容datetime.strptime的随机日期时间格式?
构建兼容datetime.strptime的Hypothesis日期时间格式生成策略
核心前提
我们需要生成的格式字符串fmt必须满足:用当前时间执行strftime(fmt)得到的字符串,能被strptime用同一个fmt正确解析且无报错。这意味着要避开那些仅在strftime中可用但strptime不支持的格式符,同时确保组合后的格式不会触发解析异常。
步骤1:定义安全的格式符与预定义片段
先列出strftime和strptime双向兼容的格式符,并组合成经过验证的常用片段,减少无效格式的生成:
from hypothesis import strategies as st import datetime as dt # 预定义日期格式片段:涵盖主流日期表示方式 date_fragments = st.sampled_from([ "%Y-%m-%d", "%d/%m/%Y", "%m/%d/%Y", "%b %d, %Y", "%B %d, %Y", "%Y/%m/%d", "%d-%m-%Y", ]) # 预定义时间格式片段:覆盖24小时制、12小时制等场景 time_fragments = st.sampled_from([ "%H:%M:%S", "%H:%M", "%I:%M %p", "%I:%M:%S %p", "%H.%M.%S", ])
步骤2:构建灵活的随机格式生成策略
如果需要更具随机性的格式(而非仅预定义片段),可以组合单个格式符与合法分隔符:
# 单个日期格式符(双向兼容) date_tokens = st.sampled_from(["%Y", "%m", "%d", "%b", "%B", "%a", "%A"]) # 单个时间格式符(双向兼容) time_tokens = st.sampled_from(["%H", "%I", "%M", "%S", "%p"]) # 合法分隔符:避免与格式符冲突 separators = st.sampled_from(["-", "/", ":", ".", " ", ", "]) # 生成随机日期格式:确保是「格式符+分隔符+格式符」的交替结构 random_date_format = st.builds( lambda parts: "".join(parts), st.lists( st.one_of(date_tokens, separators), min_size=3, max_size=7, unique_by=lambda x: x in date_tokens # 防止连续出现分隔符 ) ) # 生成随机时间格式:逻辑同随机日期格式 random_time_format = st.builds( lambda parts: "".join(parts), st.lists( st.one_of(time_tokens, separators), min_size=3, max_size=7, unique_by=lambda x: x in time_tokens ) ) # 组合日期、时间格式,支持单独日期/时间或两者结合 datetime_format = st.one_of( date_fragments, time_fragments, st.builds( lambda d, sep, t: f"{d}{sep}{t}", date_fragments, st.sampled_from([" ", " at ", " "]), time_fragments ), st.builds( lambda d, sep, t: f"{d}{sep}{t}", random_date_format, st.sampled_from([" ", " at ", " "]), random_time_format ) )
步骤3:过滤不兼容格式
即使基于安全格式符生成的格式,也可能存在个别无效组合(比如%p未搭配%I使用)。通过过滤函数验证格式的双向兼容性:
def is_compatible_format(fmt): try: now = dt.datetime.now() formatted_str = now.strftime(fmt) dt.datetime.strptime(formatted_str, fmt) return True except (ValueError, TypeError): return False # 最终的兼容格式策略 compatible_datetime_formats = datetime_format.filter(is_compatible_format)
使用示例
可以直接用该策略生成测试用例,验证格式的有效性:
@st.composite def datetime_with_valid_format(draw): fmt = draw(compatible_datetime_formats) now = dt.datetime.now() formatted_str = now.strftime(fmt) parsed_dt = dt.datetime.strptime(formatted_str, fmt) return (fmt, now, formatted_str, parsed_dt) # 生成5个示例验证 for _ in range(5): fmt, original, formatted, parsed = datetime_with_valid_format().example() print(f"格式: {fmt}") print(f"原时间: {original}") print(f"格式化后: {formatted}") print(f"解析后: {parsed}") print("---")
关键注意事项
- 避免使用
%c、%x、%X这类依赖系统区域设置的格式符,不同环境下解析规则不一致,易触发兼容性问题。 %p必须搭配%I(12小时制小时)使用,否则strptime会报错,过滤函数会自动排除这类无效组合。- 若需扩展格式范围,新增格式符前务必确认其在
strftime和strptime中均受支持。
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

