php strftime函数的详细用法

📅 发布时间:2026/10/8 17:20:37
php strftime函数的详细用法
前言strftime()是 PHP 里按本地化格式输出时间的函数它根据当前设置的区域locale把日期时间格式化成2026年10月6日 星期二或者Tuesday, 6 October 2026这样的形式。它和date()的分工是date()只输出英文和固定格式strftime()会跟随 locale 变化星期名、月份名、日期顺序都会变。但必须先把最关键的一条讲清楚strftime()和gmstrftime()在 PHP 8.1.0 中已被废弃deprecated计划在 PHP 9.0 移除。在 PHP 8.1 及以上调用它会产生E_DEPRECATED通知。官方给出的迁移方向是不依赖区域的就换成date()或DateTime::format()需要本地化的就换成IntlDateFormatter::format()需要intl扩展。也就是说这个函数现在只有两类读者一是在 PHP 8.0 及更早版本上维护老项目的开发者二是正在把老代码迁移出去的人。本文既讲它的完整用法——因为老项目还得看懂、还得改对——也讲迁移的目标写法。另外要澄清一个常见误解strftime()的输出不是 PHP 自己实现的而是直接调用 C 库的strftime()。所以同一段格式串在不同操作系统上结果可能不一样这是它的固有缺陷也正是它被废弃的原因之一。官方手册明确说明并非所有转换说明符都被各种 C 库支持不被支持的那些在 PHP 里也不可用。一、基本用法与 locale 设置函数签名的形状是strftime($format, $timestamp null)第一个参数是格式串第二个是可选的 Unix 时间戳省略时用当前时间。gmstrftime()参数完全一样区别只在于它按 UTC 解释时间戳而strftime()按本地时区。?php // 适用于 PHP 7.0 ~ 8.0PHP 8.1 起本函数已废弃$ts mktime(15, 30, 0, 10, 6, 2026);echo strftime(%Y-%m-%d %H:%M:%S, $ts), PHP_EOL;echo gmstrftime(%Y-%m-%d %H:%M:%S, $ts), PHP_EOL; // 按 UTC 输出要让输出真的本地化必须先设置区域而且必须指定LC_TIME这个类别?php // 适用于 PHP 7.0 ~ 8.0PHP 8.1 起本函数已废弃$ts mktime(0, 0, 0, 10, 6, 2026);// setlocale 成功返回新的 locale 字符串失败返回 false$old setlocale(LC_TIME, 0); // 先记下当前设置$ok setlocale(LC_TIME, zh_CN.UTF-8); // Linux 上的中文区域名if ($ok false) {// Windows 上的区域名格式不同常见写法有 chs、Chinese_China.936$ok setlocale(LC_TIME, chs);}if ($ok false) {echo 区域设置失败将退回英文输出, PHP_EOL;}echo strftime(%Y年%m月%d日 %A, $ts), PHP_EOL;setlocale(LC_TIME, $old); // 用完恢复避免影响后续逻辑setlocale()的返回值一定要检查——区域设置失败时它返回false而strftime()仍然会正常输出只是输出的是默认的英文。这是最典型的代码没报错但结果不对的情形。另外区域名在不同系统上差异很大Linux 上是zh_CN.UTF-8这种形式Windows 上是chs、Chinese_China.936之类而且服务器上没装对应的 locale 包时精简版 Docker 镜像尤其常见zh_CN.UTF-8会直接失败。这也是为什么依赖strftime()做本地化在生产环境里非常脆弱。二、转换说明符全表strftime()的转换说明符来自 C 标准以百分号开头大部分字母的含义和date()完全不同例如%m是月份而不是分钟分钟是%M照date()的习惯往里填必错。说明符含义示例输出%a星期缩写Tue%A星期全称Tuesday%b/%h月份缩写Oct%B月份全称October%c首选的日期时间表示Tue Oct 6 15:30:00 2026%C世纪两位20%d月内第几天两位补零06%e月内第几天空格补位6%H小时24 小时制两位15%I小时12 小时制两位03%j年内第几天三位补零279%m月份两位10%M分钟两位30%p上下午标记PM%S秒两位00%uISO 星期几1 到 7周一为 12%w星期几0 到 6周日为 02%U年内周数以周日为一周开始40%VISO 8601 周数41%W年内周数以周一为一周开始40%x首选日期表示10/06/26%X首选时间表示15:30:00%y两位年份26%Y四位年份2026%z与 UTC 的偏移0800%Z时区名或缩写CST%n/%t换行 / 制表符—%%字面量百分号%用一张表就能看出几个容易搞混的点%m是月、%M是分%d是日、%D在部分 C 库里是%m/%d/%y的简写并不是日的另一种写法%U和%W的区别只在于一周从周日还是周一开始而%V才是 ISO 8601 周数跨年附近三者结果可能差一周。一个实测脚本用固定时间戳把常见说明符一次性打出来注意%e、%T、%R、%D等在 Windows 上不受支持官方手册已明确说明这一点所以在 Windows 上跑这段会看到原样输出或异常结果?php // 适用于 PHP 7.0 ~ 8.0PHP 8.1 起本函数已废弃$ts mktime(15, 30, 0, 10, 6, 2026); // 2026-10-06 15:30:00$specs [%Y, %y, %m, %d, %H, %M, %S, %A, %a, %B,%j, %u, %w, %U, %V, %W, %z, %Z, %%];foreach ($specs as $s) {printf(%-4s %s\n, $s, strftime($s, $ts));}三、迁移到date()与IntlDateFormatter官方给出的迁移路径分成两条判断标准只有一句话输出要不要跟随语言环境。不需要本地化只用数字、或者英文缩写就够的直接换成DateTime::format()格式字符沿用date()的那一套strftime()date()/DateTime::format()说明%Y-%m-%dY-m-d最常用的日期%H:%M:%SH:i:s注意分钟从%M变成i%Y%m%d%H%M%SYmdHis拼文件名、时间戳串%Al英文星期全称%aD英文星期缩写%BF英文月名%jz加 1date(z)从 0 开始需注意差一%pAAM / PM%zO与 UTC 的偏移%ZT时区缩写e是时区标识符?php // 适用于 PHP 8.0$dt new DateTimeImmutable(2026-10-06 15:30:00);echo $dt-format(Y-m-d H:i:s), PHP_EOL; // 2026-10-06 15:30:00echo $dt-format(l, j F Y), PHP_EOL; // Tuesday, 6 October 2026英文需要真正本地化中文月份名、中文星期、按区域习惯排列的日期的用IntlDateFormatter它由 ICU 驱动不依赖操作系统的 locale 安装情况这也是它比strftime()可靠的地方?php // 适用于 PHP 8.0需要 intl 扩展$ts (new DateTimeImmutable(2026-10-06 15:30:00))-getTimestamp();$fmt new IntlDateFormatter(zh_CN, // 区域IntlDateFormatter::LONG, // 日期样式IntlDateFormatter::SHORT, // 时间样式Asia/Shanghai, // 时区IntlDateFormatter::GREGORIAN);echo $fmt-format($ts), PHP_EOL; // 2026年10月6日 15:30随 ICU 版本略有差异// 也可以用自定义模式串符号含义与 strftime 不同$fmt2 new IntlDateFormatter(zh_CN, IntlDateFormatter::NONE,IntlDateFormatter::NONE, Asia/Shanghai, IntlDateFormatter::GREGORIAN,yyyy年MM月dd日 EEEE);echo $fmt2-format($ts), PHP_EOL;注意IntlDateFormatter的模式串符号yyyy、MM、dd、EEEE用的是 ICU 的语法和strftime()的%Y、%m完全是两套东西别混着写。ICU 的输出在不同 ICU 版本间可能有细微差别所以对格式有严格断言的地方比如测试用例要预期到这种差异。如果你的运行环境实在装不了intl还有一个折中办法把中文星期、中文月份做成常量数组用date(w)、date(n)去查表。这样做的好处是完全可控、不依赖任何扩展和系统 locale代价是要自己维护且只有你支持的那几种语言。常见坑点❌ 在 PHP 8.1 及以上的项目里继续调用strftime()然后被E_DEPRECATED通知刷屏✅ 迁到date()/DateTime::format()或IntlDateFormatterstrftime()计划在 PHP 9.0 移除。❌ 把date()的格式字符直接塞给strftime()✅ 两套符号完全不同strftime(%m)是月份date(m)也是月份但strftime(%M)是分钟而date(M)却是月份缩写——必须逐个对照。❌ 调了setlocale()但不检查返回值也不设LC_TIME✅ 只设LC_TIME检查返回值是否为false失败时要有降级方案。❌ 依赖%e、%T、%R、%D这类说明符做跨平台输出或者用strftime()处理 1970 年之前的时间✅ 官方手册说明并非所有说明符都被各平台 C 库支持%e、%T、%R、%D等在 Windows 上不受支持负时间戳1970 年之前在 Windows 和部分系统上同样不被支持。跨平台一律改用date()体系。❌ 用%U或%W当 ISO 周数✅ ISO 8601 周数是%V%U周日起与%W周一起在跨年附近可能与%V相差一周。❌ 用strftime()输出当前时间戳或做时间运算✅ 时间运算用DateTime系列做加减modify()、add()格式化和运算是两件事。❌ 以为strftime()输出的一定是本地语言✅ 区域设置失败时它会安静地输出默认英文服务器缺 locale 包精简 Docker 镜像常见时会直接命中这个情况。❌ 在同一个请求里到处setlocale()却不恢复✅setlocale()改的是进程级设置用完恢复原值否则会把同一请求里其他模块的格式化输出一起改掉。总结维度结论语言支持strftime()已废弃PHP 8.1 起产生E_DEPRECATED计划 PHP 9.0 移除配套函数gmstrftime()同样已废弃差别只在于按 UTC 解释时间戳本地化前提必须先setlocale(LC_TIME, ...)并检查返回值平台差异实现直接来自 C 库说明符支持情况随平台变化Windows 缺若干说明符输出格式百分号说明符与date()的格式字符完全不是一套不本地化的替代date()/DateTime::format()要本地化的替代IntlDateFormatter需intl扩展由 ICU 驱动最隐蔽的坑区域设置失败时静默输出英文没报错但结果不对如果你手上是 PHP 8.1 及以上的项目结论很干脆不要再用strftime()也别引第三方兼容包去续命——那些包用 ICU 重实现输出和原来的 C 库版本本来就有差异不如一次性迁到IntlDateFormatter或date()。如果是 PHP 8.0 及更早的老项目要长期维护那么至少做到两件事所有setlocale()都检查返回值所有平台特定的说明符都不要用——这样等你要迁移的时候工作量会小得多。