You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在string.Template模板中为datetime对象应用自定义格式?

问题原因

string.Template的默认占位符语法不支持在占位符内部嵌入格式说明符。它只能识别简单的占位符名称(比如${dt}),而你写的${dt:%a, %d.%m.%Y at %H:%M}会被解析成一个包含冒号的无效占位符,这就是为什么会抛出ValueError: Invalid placeholder in string的原因。

下面给你两种实用的解决方案:


方案1:提前格式化datetime对象(最简单)

如果场景比较简单,你可以先把datetime对象格式化为字符串,再传入substitute方法:

from datetime import datetime as dt
import string

# 先格式化datetime
current_time = dt.now()
formatted_time = current_time.strftime("%a, %d.%m.%Y at %H:%M")

# 用模板替换
print(string.Template("Current time: ${dt}").substitute({"dt": formatted_time}))

这种方法的优点是零额外复杂度,直接利用Python内置的strftime完成格式化,适合只需要一次格式化的场景。


方案2:自定义Template子类(更灵活)

如果你需要在模板中直接写格式说明符(就像你最初期望的那样),可以自定义string.Template的子类,扩展它的占位符语法,支持${变量名:格式字符串}的写法:

from datetime import datetime as dt
import string
import re

class FormattedTemplate(string.Template):
    # 重写正则模式,允许占位符后跟随:和格式字符串
    pattern = r"""
    \$(?:
        (?P<escaped>\$) |
        (?P<named>[_a-z][_a-z0-9]*) |
        {(?P<braced>[_a-z][_a-z0-9]*)(?::(?P<format>[^}]+))?} |
        (?P<invalid>)
    )
    """

    def substitute(self, mapping=None, **kwds):
        # 合并映射和关键字参数
        mapping = dict(mapping or {}, **kwds)

        def replace_match(match):
            # 处理转义的$
            if match.group('escaped'):
                return match.group('escaped')
            # 处理普通命名占位符(如$dt)
            if match.group('named'):
                return str(mapping[match.group('named')])
            # 处理带格式的大括号占位符
            braced_name = match.group('braced')
            if braced_name:
                value = mapping[braced_name]
                format_str = match.group('format')
                if format_str:
                    # 对datetime对象用strftime,其他对象用format格式化
                    if hasattr(value, 'strftime'):
                        return value.strftime(format_str)
                    else:
                        return format(value, format_str)
                return str(value)
            # 处理无效占位符
            raise ValueError(f"Invalid placeholder: {match.group(0)}")
        
        return re.sub(self.pattern, replace_match, self.template)

# 使用示例
print(FormattedTemplate("Current time: ${dt:%a, %d.%m.%Y at %H:%M}").substitute({"dt": dt.now()}))
# 还能格式化其他类型,比如数字
print(FormattedTemplate("Pi: ${pi:.2f}").substitute({"pi": 3.1415926}))

这个自定义类不仅支持datetime的格式化,还能处理其他可格式化的类型(比如浮点数、整数),适合需要在模板中频繁使用自定义格式的场景。


内容的提问来源于stack exchange,提问作者Moritz 'e1mo' Fromm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 18:48:13