Я получил 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 Предпочитаемое представление времени на основе локали без даты
Постскриптум Предпочитаемая дата %x
работает корректно, отображая дд.мм.гггг для России и мм / дд / гггг для США.
То же самое во 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
).
Возможные решения:
обработать этот конкретный случай:
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 Кажется, что X_fmt
ценится до %I:%M:%S %p
в хобот а также 11-СТАБИЛЬНЫЙ
Обновить:
X_fmt
было вернулся так как (т.е. во FreeBSD> = 11, X_fmt
по-прежнему определяется как %H:%M:%S
)Выдержка из /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, чтобы подтвердить эту точку зрения.