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;
}