Php strftime():中文、俄文和匈牙利文的编码错误
我想做的很简单:我想用中文(或俄文)打印一个日期(时间戳) 对于我使用的所有语言Php strftime():中文、俄文和匈牙利文的编码错误,php,encoding,utf-8,chinese-locale,Php,Encoding,Utf 8,Chinese Locale,我想做的很简单:我想用中文(或俄文)打印一个日期(时间戳) 对于我使用的所有语言 setlocale(LC_TIME, 'hu_HU.utf8', 'hu_HU.UTF-8', 'hu_HU', 'hr'); $date = strftime('%a %e %b %Y, %H:%M'); $date = utf8_encode($date); 即使没有utf8\u encode(),也会返回UTF-8字符串。一切都很好。现在,当我对'zh\CN.utf8'locale(或'zh\u CN.U
setlocale(LC_TIME, 'hu_HU.utf8', 'hu_HU.UTF-8', 'hu_HU', 'hr');
$date = strftime('%a %e %b %Y, %H:%M');
$date = utf8_encode($date);
即使没有utf8\u encode()
,也会返回UTF-8字符串。一切都很好。现在,当我对'zh\CN.utf8'
locale(或'zh\u CN.UTF-8'
,'zh\u CN'
或'zh'
)执行相同操作时,这不会返回正确的日期。无论是否使用utf8\u encode()
这将返回
'2018å¹?mæ?#dæ?'
我不会说中文,但这显然是错误的。我发现它应该返回类似”的内容年'代码>。此字符采用UTF-8十六进制编码E5 B9 B4
,但当我查看返回的字符串时,十六进制值错误。有(2018年后)C3 A5 C2 B9 3F 6D C3 A6…
当我用mb\u detect\u encoding()
检查返回字符串的编码时,它总是返回UTF-8。我希望如此,因为我使用的是将编码设置为UTF-8的'zh\u CN.utf8'
语言环境
我环顾四周好长一段时间后才发现。他建议使用“%Y”格式年%M月%E日'在strftime()函数中的code>。当我使用它时,我得到了与以前相同的结果
这让我想到编码是错误的。但这是真的吗?编码错误吗?如何将结果转换为正确的编码
对于俄语,我有更多更少的相同问题。解决方案
我花了几个小时,找到了正确的编码strftime()
是不是UTF-8
字符串。有关详细信息,请查看此答案的底部。我最终得到了一个formatTime()
函数,它以正确的编码为我提供了正确的时间(UTF-8
)
(*):
千里迢迢
我检查了特定语言的strftime(“%B”)
结果。这是完整的月份名称。我检查了我语言的翻译,然后查找翻译中不同字母的UTF-8
十六进制值
现在我正在迭代php支持的所有编码。我将strftime()
给出的结果从当前迭代编码转换为UTF-8
。现在,我可以将转换为UTF-8
的strftime()
的结果与手动翻译的十六进制值进行比较,手动翻译的十六进制值也是UTF-8
的十六进制值。如果它们与strftime()
的结果匹配,则具有当前交互编码的编码
我选择十六进制值是因为它们在防御上是相同的,并且不依赖于内部编码,因为它们是ASCII字符串(甚至是php中的数字)
这给了我以下输出,代码发布如下:
检测strftime()的字体编码
匈牙利语
strftime()
匈牙利语三月版。预期十六进制:6fc5be756a616b
,将预期十六进制转换为字符串:ožujak
初始返回值
奥贾克
6f9e756a616b
提供正确结果的编码:
Windows-1252
奥祖贾克
6fc5be756a616b
中国人
strftime()。预期十六进制:e58d81e4ba8ce69c88
,已将预期十六进制转换为字符串:十二月代码>
初始返回值
ʮՂ
caaeb6fed4c2
提供正确结果的编码:
EUC-CN
十二月
e58d81e4ba8ce69c88
CP936
十二月
e58d81e4ba8ce69c88
GB18030
十二月
e58d81e4ba8ce69c88
俄语
strftime()。预期的十六进制:d0b4d095d099d0aed090d09fd0ad
,将预期的十六进制转换为字符串:
初始返回值
ť롡停止使用utf8\u encode()
这不是魔法,事实上它会更频繁地破坏您的输入。这同样适用于utf8\u decode()
。另外,mb\u detect\u encoding()
应该被称为mb\u guess\u encoding()
,因为它就是这么做的。如果使用“Peter”建议的内容不起作用,那么我怀疑您没有在页面、浏览器或任何用于查看输出的内容中正确指定显示编码@Sammitch我很抱歉,但这对我没有帮助。我正在将返回的内容写入纯文本文件。没有给出浏览器页面编码。这就是为什么我能够检查十六进制编码。我在浏览器输出中没有这样做。我还尝试添加了一些BOM
s,这样也许我可以幸运地发现strftime()
编码提供了什么。我还知道mb\u detect\u encoding()
只是猜测。但是我还能做些什么来获得编码呢?我也在猜测。谷歌“如何在$editor中查看UTF8”,因为这可能仍然是你的问题。@Sammitch谢谢你的帮助。下周我回来做这个项目时,我会试试这个。但我不太自信。我正在用另一个设置为UTF-8编码作为输入的程序处理文本文件。当我添加strftime()
的结果时,该程序抛出错误。这个我
function formatTime($format, $language = null, $timestamp = null){
switch($language){
case 'chinese':
$locale = setlocale(LC_TIME, 'zh_CN.utf8', 'zh_CN.UTF-8', 'zh_CN', 'zh');
break;
case 'hungarian':
$locale = setlocale(LC_TIME, 'hu_HU.utf8', 'hu_HU.UTF-8', 'hu_HU', 'hr');
break;
case 'russian':
$locale = setlocale(LC_TIME, 'ru_RU.utf8', 'ru_RU.UTF-8', 'ru_RU', 'ru');
break;
case 'german':
$locale = setlocale(LC_TIME, 'de_DE.utf8', 'de_DE.UTF-8', 'de_DE', 'de');
break;
case 'french':
$locale = setlocale(LC_TIME, 'fr_FR.utf8', 'fr_FR.UTF-8', 'fr_FR', 'fr');
break;
case 'polish':
$locale = setlocale(LC_TIME, 'pl_PL.utf8', 'pl_PL.UTF-8', 'pl_PL', 'pl');
break;
case 'turkish':
$locale = setlocale(LC_TIME, 'tr_TR.utf8', 'tr_TR.UTF-8', 'tr_TR', 'tr');
break;
case 'english':
$locale = setlocale(LC_TIME, 'en_GB.utf8', 'en_GB.UTF-8', 'en_GB', 'en');
break;
// ...
default: break;
}
if(!is_numeric($timestamp)){
$datetime = strftime($format);
}
else{
$datetime = strftime($format, $timestamp);
}
$current_locale = strtolower(setlocale(LC_TIME, 0));
if(($pos = strpos("utf", $current_locale)) === false || strpos("8", $current_locale, $pos) === false){
// UTF-8 locale is not used, the encodings are found out with the code shown below
$locale_default_encodings = array(
"german" => "ISO-8859-1",
"french" => "ISO-8859-1",
"polish" => "ISO-8859-2",
"turkish" => "ISO-8859-9",
// Testing hungarian results in "Windows-1252", but php.net recommends to
// use ISO-8859-2, in fact Windows-1252 is based on ISO-8859-2 so it should
// (hopefully) work with both (*)
"hungarian" => "ISO-8859-2",
"chinese" => "CP936",
"russian" => "KOI8-R"
);
$target_encoding = mb_internal_encoding(); // or "UTF-8" or whatever
if(isset($locale_default_encodings[$language])){
$datetime = mb_convert_encoding(
$datetime,
$target_encoding,
$locale_default_encodings[$language]
);
}
else{
// try to avoid this case
$datetime = mb_convert_encoding($datetime, $target_encoding);
}
}
setlocale(LC_TIME, $locale);
return $datetime;
}