php 格式化DateTime对象,遵循区域设置::getDefault()

tyu7yeag  于 2022-12-10  发布在  PHP
关注(0)|答案(6)|浏览(172)

我有一个DateTime对象,我目前正在通过

$mytime->format("D d.m.Y")

这正好给了我所需要的格式:
2012年3月5日星期二
唯一缺少的一点是正确的语言。我需要德语翻译的TueTuesday),这是DieDienstag)。
这将为我提供正确的区域设置

Locale::getDefault()

但是我不知道如何告诉DateTime::format使用它。
难道没有一种方法可以做这样的事情:

$mytime->format("D d.m.Y", \Locale::getDefault());
oipij1gg

oipij1gg1#

您可以使用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);

它输出以下内容(至少今天是这样)。
2013年6月4日

pnwntuvh

pnwntuvh2#

这是因为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())
kqqjbcuj

kqqjbcuj3#

IntlDateFormatter是目前(2022年)要走的路。

<?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以及日期和时间格式。我想添加一些示例以供将来参考。注意IntlDateFormatter::GREGORIANIntlDateFormatter::LONG是可互换的。

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::GREGORIAN      August 5, 2022 at 3:26:37 PM GMT+2 
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::GREGORIAN      5 August 2022 at 15:26:37 CEST 
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::GREGORIAN      5. August 2022 um 15:26:37 MESZ 
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::GREGORIAN      5 août 2022 à 15:26:37 UTC+2 
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

正如salathe已经说过的,如果需要,还可以使用$formatter->setPattern进一步定制输出。

rta7y2nd

rta7y2nd4#

虽然setlocale()是正确的答案,仍然会工作,但现在已经过时了。
strftime自PHP 8.1.0起已被弃用,强烈建议不要依赖此函数。
而且提到的Intl扩展工作得很完美,但并不总是得心应手。
处理日期和时间最简单的方法之一是使用Carbon2CakePHP 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(或其 Package 器)已经包含在内了。

8gsdolmq

8gsdolmq5#

我做了一些东西,只是这样做,因为似乎不存在一个简单的解决方案在任何地方在线,除了与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;
    }
}
z9ju0rcb

z9ju0rcb6#

这就是我如何结合DateTime和**strftime()**的特性来解决的。
第一个允许我们管理带有奇怪日期格式的字符串,例如“Ymd”(从日期选择器存储在数据库中);第二个允许我们将日期字符串翻译成某种语言。
例如,我们从值“20201129”开始,并希望以意大利语可读日期结束,日期名称为day和month,第一个字母也是大写: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

相关问题