我有一个DateTime对象,我目前正在通过格式化它
$mytime->format("D d.m.Y")
这正是我需要的格式:
2012年3月3日星期二
唯一缺少的是正确的语言。我需要Tue
(Tuesday
)的德语翻译,也就是Die
(Dienstag
)。
这为我提供了正确的区域设置
Locale::getDefault()
但我不知道如何告诉DateTime::format
使用它。
难道没有办法做这样的事情吗:
$mytime->format("D d.m.Y", 'Locale::getDefault());
您可以使用Intl扩展名来格式化日期。它将根据所选的区域设置日期/时间的格式,或者您可以用IntlDateFormatter::setPattern()
覆盖它。
对于您想要的输出格式,使用自定义模式的快速示例可能如下所示。
$dt = new DateTime;
$formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::SHORT, IntlDateFormatter::SHORT);
$formatter->setPattern('E d.M.yyyy');
echo $formatter->format($dt);
它输出以下内容(至少在今天)。
Di。4.6.2013
这是因为format
不关注区域设置。您应该使用strftime
。
例如:
setlocale(LC_TIME, "de_DE"); //only necessary if the locale isn't already set
$formatted_time = strftime("%a %e.%l.%Y", $mytime->getTimestamp())
IntlDateFormatter是目前的方法(2023)。
<?php
$formatter = new IntlDateFormatter(
$locale, // the locale to use, e.g. 'en_GB'
$dateFormat, // how the date should be formatted, e.g. IntlDateFormatter::FULL
$timeFormat, // how the time should be formatted, e.g. IntlDateFormatter::FULL
'Europe/Berlin' // the time should be returned in which timezone?
);
echo $formatter->format(time());
将给出不同的输出,具体取决于传递为$locale
的内容以及日期和时间格式。我想添加一些样品以备将来参考。注意,CCD_ 10和CCD_ 11是可交换的。
Locale: en_US
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, August 5, 2022 at 3:26:37 PM Central European Summer Time
IntlDateFormatter::LONG August 5, 2022 at 3:26:37 PM GMT+2
IntlDateFormatter::MEDIUM Aug 5, 2022, 3:26:37 PM
IntlDateFormatter::SHORT 8/5/22, 3:26 PM
Locale: en_GB
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, 5 August 2022 at 15:26:37 Central European Summer Time
IntlDateFormatter::LONG 5 August 2022 at 15:26:37 CEST
IntlDateFormatter::MEDIUM 5 Aug 2022, 15:26:37
IntlDateFormatter::SHORT 05/08/2022, 15:26
Locale: de_DE
Format for Date & Time: Results in:
IntlDateFormatter::FULL Freitag, 5. August 2022 um 15:26:37 Mitteleuropäische Sommerzeit
IntlDateFormatter::LONG 5. August 2022 um 15:26:37 MESZ
IntlDateFormatter::MEDIUM 05.08.2022, 15:26:37
IntlDateFormatter::SHORT 05.08.22, 15:26
Locale: fr_FR
Format for Date & Time: Results in:
IntlDateFormatter::FULL vendredi 5 août 2022 à 15:26:37 heure d’été d’Europe centrale
IntlDateFormatter::LONG 5 août 2022 à 15:26:37 UTC+2
IntlDateFormatter::MEDIUM 5 août 2022 à 15:26:37
IntlDateFormatter::SHORT 05/08/2022 15:26
正如salath已经说过的,如果需要,您还可以使用$formatter->setPattern
来进一步自定义输出。
虽然setlocale()
是正确的答案,仍然有效,但现在已经过时了。
strftime自PHP 8.1.0起已弃用。强烈反对依赖此函数。
和提到的Intl扩展工作得很好,但并不总是方便。
使用日期和时间的最简单方法之一是使用Carbon2、CakePHP Chronos或类似的库。它为所有日期的操作、格式化和计算提供了一个单一的接口。如果你经常使用日期,我建议你使用Carbon,然后做一些类似的事情
$date = Carbon::now()->locale('fr_FR');
echo $date->isoFormat('dd DD.MM.YYYY');
请注意,格式与date()
不同。完整列表见Carbon文档,但提到的D d.m.Y
可能类似于dd DD.MM.YYYY
。
如果您的项目接受第三方库,那么这确实是一条不错的道路。此外,如果您正在使用该框架,请检查,可能已经包含Carbon(或其包装)。
我做了一些这样的事情,因为除了strftime
之外,似乎没有任何简单的在线解决方案,这是非常不推荐的!
我的解决方案用国际月份和日期名称扩展了DateTime::format()
,不需要安装一堆模块,也不需要学习新的日期格式化方法等。
在包含下面提供的类之后,您可以按如下方式使用它。代替
$date = new DateTime("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
结果:Friday (Fri) 2010-Jan-01 (January)
您现在可以使用
$date = new DateTimeIntl("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
结果:vrijdag (vr) 2010-jan.-01 (januari)
(荷兰语言环境)。
如果需要,可以动态更改$datetime->locale
。
$date = new DateTimeIntl("2010-01-01 1:23");
$date->locale = "it_IT" ;
echo $date->format("l (D) Y-M-d (F)");
结果:venerdì (ven) 2010-gen-01 (gennaio)
包括:
class DateTimePatternReplace {
function __construct(public string $DateTimeCode,
public string $IntDateFormatterCode,
public string $tempDateTimePlaceHolder) {}
}
trait addIntlDate {
public string $locale="nl_NL" ; // REPLACE BY YOUR FAVORITE LOCALE
private function getIntResult(string $pattern) {
if ( ! isset($this->formatter) || $this->formatter->getLocale(Locale::VALID_LOCALE) != $this->locale ) {
$this->formatter = new IntlDateFormatter($this->locale);
$this->locale = $this->formatter->getLocale(Locale::VALID_LOCALE); // store the valid version of the locale
}
this->formatter->setPattern($pattern);
return $this->formatter->format($this);
}
function format(string $pattern): string {
// The third parameter can NOT contain normal latin letters, these are random,
// distinctive codes not likely to be in a date format string
$replacePatterns = [/*weekdays*/new DateTimePatternReplace('l', 'EEEE', '[*ł*]'),
new DateTimePatternReplace('D', 'EEE', '[*Đ*]'),
/*month*/ new DateTimePatternReplace('F', 'MMMM', '[*ƒ*]'),
new DateTimePatternReplace('M', 'MMM', '[*μ*]'),
// add new replacements here if needed
] ;
$codesFound=[] ;
foreach($replacePatterns as $p) {
if ( str_contains($pattern, $p->DateTimeCode)) {
// replace codes not prepended by a backslash.
// known bug: codes prepended by double backslashes will not be translated. Whatever.
$pattern = preg_replace('/(?<!''')'.preg_quote($p->DateTimeCode)."/", $p->tempDateTimePlaceHolder, $pattern);
$codesFound[] = $p ;
}
}
$result = parent::format($pattern) ;
foreach($codesFound as $p) {
$code = $this->getIntResult($p->IntDateFormatterCode);
$result = str_replace($p->tempDateTimePlaceHolder, $code, $result);
}
return $result ;
}
}
// you can remove this str_contains addition in PHP 8 or higher
if (!function_exists('str_contains')) {
function str_contains($haystack, $needle) {
return $needle !== '' && mb_strpos($haystack, $needle) !== false;
}
}
// end str_contains addition
class DateTimeIntl extends DateTime {
use addIntlDate;
}
class DateTimeImmutableIntl extends DateTimeImmutable {
use addIntlDate;
}
此代码扩展了DateTime和DateTimeImmutable,并使用区域设置扩展了它们的正常格式。因此,这使得一切都非常简单
如果需要,可以通过向数组中添加代码来添加要翻译的新模式:DateTime::format()
语法中的格式模式、IntlDateFormatter::format
语法中的相应格式模式,以及DateTime::format
中要使用的占位符,该占位符不包含将被DateTime::format
方法使用/替换的字母/代码/模式。请参阅当前四个不使用ASCII中低于128个字母的字母的代码作为示例。(他们使用波兰语、希腊语、荷兰语和斯洛伐克语字母只是为了好玩。)
在PHP 8.1中构建并测试。对于某些旧版本的PHP,您必须将第一个类更改为
class DateTimePatternReplace {
public string $DateTimeCode;
public string $IntDateFormatterCode;
public string $tempDateTimePlaceHolder;
function __construct(string $DateTimeCode, string $IntDateFormatterCode, string $tempDateTimePlaceHolder) {
$this->DateTimeCode = $DateTimeCode;
$this->IntDateFormatterCode = $IntDateFormatterCode;
$this->tempDateTimePlaceHolder = $tempDateTimePlaceHolder;
}
}
这就是我结合DateTime和strftime()功能解决问题的方法。
第一个允许我们使用奇怪的日期格式来管理字符串,例如";Ymd";(从日期选择器存储在数据库中)。第二个允许我们用某种语言翻译日期字符串。
例如,我们从一个值"0"开始;20201129";,我们希望以意大利语可读的日期结尾,日期和月份的名称,还有第一个大写字母:"Domenica 2020年11月29日";。
// for example we start from a variable like this
$yyyymmdd = '20201129';
// set the local time to italian
date_default_timezone_set('Europe/Rome');
setlocale(LC_ALL, 'it_IT.utf8');
// convert the variable $yyyymmdd to a real date with DateTime
$truedate = DateTime::createFromFormat('Ymd', $yyyymmdd);
// check if the result is a date (true) else do nothing
if($truedate){
// output the date using strftime
// note the value passed using format->('U'), it is a conversion to timestamp
echo ucfirst(strftime('%A %d %B %Y', $truedate->format('U')));
}
// final result: Domenica 29 novembre 2020