strftime() возвращает неправильный предпочтительный формат времени
Я получил PHP 7.0.8 (FPM), работающий на FreeBSD 10.1 и nginx. Мне нужно отображать время в предпочитаемом формате в зависимости от страны, где проживает пользователь.
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-8
а также en_US.UTF-8
,
echo setlocale(LC_ALL, "en_US.UTF-8")
возвращает правильный язык
Специальная конфигурация не применяется.
Пожалуйста, помогите мне решить эту проблему. Благодарю.
% X Предпочитаемое представление времени на основе локали без даты
PS Предпочитаемая дата %x
работает правильно, отображая дд.мм.гггг для России и мм / дд / гггг для США
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
).
Возможные решения:
заполнить отчет об ошибке, если вы считаете, что это актуально и / или1 патч файла выше, а затем восстановить мир (я думаю)обработать этот конкретный случай:
echo strftime(0 === strpos(setlocale(LC_ALL, '0'), 'en_US') ? '%r' : '%X');
предпочитают использовать http://php.net/IntlDateFormatter, который не зависит от системных локалей (предполагается библиотекой ICU). Например:
$timefmt = new IntlDateFormatter('en_US', IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM); $timefmt->format(date_create());
1 кажется, что X_fmt
ценится до %I:%M:%S %p
в багажнике и 11-СТАБИЛЬНО
Обновить:
- изменение коммита
X_fmt
был отменен с тех пор (т.е. во FreeBSD >= 11,X_fmt
по-прежнему определяется как%H:%M:%S
) - в FreeBSD 11 файл, определяющий форматы времени, имеет вид /usr/src/share/timedef/en_US.UTF-8.src (символическая ссылка на локаль en_US.ISO8859-1 пропала)
Выдержка из /usr/share/i18n/locales/en_US
на Ubuntu 12.04:
% 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>"
Пожалуйста, обратите внимание %I
в дату AM/PM для%r.
%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
locale (например, если там нет файла locale)
Теперь для setlocale
, он вернет false только в случае, если вы дадите неверную переменную (т.е. LCAL
вместо LCALL
) но вернет то, что система возвращает для других случаев:
Примечание. Возвращаемое значение setlocale() зависит от системы, в которой работает PHP. Он возвращает именно то, что возвращает системная функция setlocale.
На "linux" setlocale
возвращается NULL
который не всегда воспринимается как ложный (см. здесь), что может быть источником вашей проблемы, я не могу поклясться, поскольку у меня нет FreeBSD, чтобы подтвердить это.