strftime()返回错误的首选时间格式

时间:2016-07-04 01:34:43

标签: php locale freebsd strftime

我在FreeBSD 10.1和nginx上运行了PHP 7.0.8(FPM)。我需要按用户所在的国家/地区的首选格式显示时间。

setlocale(LC_ALL, "ru_RU.UTF-8");
date_default_timezone_set("Europe/Moscow");
echo strftime('%X', time());
// Returns 21:23:12 (correct) because 24-hr format is preferred in Russia.

setlocale(LC_ALL, "en_US.UTF-8");
date_default_timezone_set("America/New_York");
echo strftime('%X', time());
// Returns 21:23:12 (incorrect) must return 9:23:12 pm as preferred format in U.S.

这看起来像我的服务器或PHP版本的问题,因为 其他用户获得了正确的结果。

locale -a返回包含ru_RU.UTF-8en_US.UTF-8

echo setlocale(LC_ALL, "en_US.UTF-8")会返回正确的区域设置。

未应用任何特殊配置。

请帮我解决这个问题。感谢。

  

%X基于区域设置的首选时间表示,没有日期

P.S。首选日期%x正常显示俄罗斯的dd.mm.yyyy和美国的mm / dd / yyyy。

2 个答案:

答案 0 :(得分:2)

在FreeBSD 10.3上也是如此:

php -r 'date_default_timezone_set("Europe/Paris"); var_dump(setlocale(LC_ALL, "en_US.UTF-8"), strftime("%X", time()));'
string(11) "en_US.UTF-8"
string(8) "15:03:07"

首先,ls -l /usr/share/locale/en_US.UTF-8/LC_TIME返回:

/usr/share/locale/en_US.UTF-8/LC_TIME@ -> ../en_US.ISO8859-1/LC_TIME

所以en_US.UTF-8实际上是en_US.ISO8859-1的符号链接。

然后,如果我们查看/usr/src/share/timedef/en_US.ISO8859-1.src(您需要安装源代码),我们会发现:

#
# X_fmt
#
%H:%M:%S

这可以解释您期望%I:%M:%S %p(或%r)时的实际结果。

可能的解决方案:

  • fill a bug report如果您认为它是相关的和/或 1 修补上面的文件然后重建世界(我猜)
  • 处理这个具体案例:

    echo strftime(0 === strpos(setlocale(LC_ALL, '0'), 'en_US') ? '%r' : '%X');
    
  • 更喜欢使用不依赖于系统区域设置的IntlDateFormatter(由ICU库假设)。例如:

    $timefmt = new IntlDateFormatter('en_US', IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM);
    $timefmt->format(date_create());
    

1 trunk11-STABLE

似乎X_fmt的价值为%I:%M:%S %p

更新

  • 提交更改X_fmtreverted,因为(即在FreeBSD> = 11,X_fmt仍被定义为%H:%M:%S
  • 在FreeBSD 11上,定义时间格式的文件是/usr/src/share/timedef/en_US.UTF-8.src(en_US.ISO8859-1语言环境的符号链接消失了)

答案 1 :(得分:0)

摘自ubuntu 12.04上的/usr/share/i18n/locales/en_US

% Appropriate time representation (%X)
%       "%r"
t_fmt   "<U0025><U0072>"
%
% Appropriate AM/PM time representation (%r)
%       "%I:%M:%S %p"
t_fmt_ampm "<U0025><U0049><U003A><U0025><U004D><U003A><U0025><U0053><U0020>/
<U0025><U0070>"

请注意%r的上午/下午的%I

unicode中的%X为25 70,即%P

来自man date(为简单而剥离):

%H     hour (00..23)

%I     hour (01..12)

%p     locale's equivalent of either AM or PM; blank if not known

%P     like %p, but lower case

%r     locale's 12-hour clock time (e.g., 11:11:04 PM)

%R     24-hour hour and minute; same as %H:%M

%x     locale's date representation (e.g., 12/31/99)

%X     locale's time representation (e.g., 23:13:48)

读取所有这个文件,它应该按预期工作,所以我怀疑你的设置使用不同的语言环境文件或回退到C语言环境(如果语言环境文件不在那里)

现在对于setlocale,只有在你给出一个错误的变量(即LCAL而不是LCALL)时它才会返回false,但是会返回系统为其他情况返回的内容:< / p>

  

注意:setlocale()的返回值取决于PHP的系统   在跑。它准确返回系统setlocale函数   回报。

在“linuxes”setlocale上返回NULL并不总是被视为错误(请参阅here),这可能是您问题的根源,我不能发誓,因为我'没有运行FreeBSD来证实这一点。