#如何使用DateTime类(处理转换,格式,时差和时区)

时间:2019-01-17 23:32:04

标签: php datetime timestamp timezone datetime-format

每个人都必须在编程的某个时候处理日期/时间格式,时区,怪异的时间格式等。 PHP很少有解决这些问题的方法,其中最著名的是PHP内置于DateTime类中。这是因为DateTime类充当了所有这些问题的一体解决方案。

但是,DateTime类有一个缺陷:如果您还不熟悉它,可能会令人困惑。

这篇文章旨在帮助那些想进一步了解DateTime类和/或发现自己问以下问题之一的人:

  1. 如何将字符串转换为可修改的日期/时间?
  2. 如何格式化日期/时间字符串?
  3. 我如何获得2次之间的差额?
  4. 如何计算时区?

请注意:

本文不会讨论date()time()strtotime()或其任何相关功能的用法。这篇文章纯粹是为了解释DateTime及其在PHP中相关类的正确用法。尽管许多答案也可以通过date()及其相关功能来实现,但DateTime会将所有功能包装到几个干净的类中。这样可以更容易地整体理解。

1 个答案:

答案 0 :(得分:1)

以下大多数信息可以从PHP's documentation of the DateTime class的各个部分获得。但是,此答案的格式应能回答 most 个关于DateTime类的人的问题,并应适用于 most 个用例。

如果您尝试使用日期/时间进行更高级的操作,例如创建DateTime包装器,使用不可变的DateTime实例或其他特定于您的应用程序的需求,我强烈建议您结帐完整的Date and Time documentation


1。如何将字符串转换为可修改的日期/时间?

编程中最困难的事情之一就是尝试使最终用户输入变得可用。但是,在日期和时间方面,DateTime类实际上是儿童游戏。

方法

DateTime的构造函数使用功能强大的解析器,该解析器接受最广为人知的格式,包括相对格式。

$datetime = new DateTime($datetime_string);

从那里,您可以使用以下任何一种方法来修改时间:

要查看DateTime::__construct()支持的格式的完整列表,请检出:Supported Date and Time Formats

示例-解释最终用户输入

让我们说您有一个表格,允许用户说出他们想约会的日期,但是此输入不是强制格式的日期选择器,而是纯文本输入。

典型的最终用户将在输入中添加类似内容,并且典型的程序员在被要求提供支持时将以以下方式做出响应:

  • 12/31/2000-“确定”
  • 2000-12-31-“确定”
  • Today-“嗯,我想我们可以支持?”
  • Tomorrow-“我想我们也应该支持。”
  • wednesday next week-“否”

过一会儿,您要么强制使用一种特定格式(无论如何都应该这样做),要么为您不良的表单设计而哭泣。但是,DateTime允许所有这些作为有效输入,并且可以完美地解释它们。

// 2000-12-31 00:00:00.000000
new DateTime('12/31/2000');

// 2000-12-31 00:00:00.000000
new DateTime('2000-12-31');

// 2000-12-31 00:00:00.000000
new DateTime('Today');

// 2001-01-01 00:00:00.000000
new DateTime('Tomorrow');

// 2001-01-03 00:00:00.000000
new DateTime('wednesday next week');

但是,像大多数事物一样,DateTime类也不是完美的,并且不支持每种格式。这就是为什么您应该始终将DateTimetry ... catch一起使用并与最终用户确认您解释的日期正是最终用户想要的日期。欧洲日期格式就是一个很好的例子:

try {
    new DateTime('31/12/2000');
} catch (Exception $e) {
    echo $e->getMessage();
}

输出:

DateTime::__construct(): Failed to parse time string (31/12/2000) at position 0 (3): Unexpected character

示例-修改日期/时间

您可以使用$datetime->modify()方法轻松调整任何日期/时间:

$datetime = new DateTime('2001-01-01');

// 2001-01-04 00:00:00.000000
$datetime->modify('+3 days');

// 2001-02-04 00:00:00.000000
$datetime->modify('+1 month');

// 2001-02-03 23:59:00.000000
$datetime->modify('-60 seconds');

// 2001-02-02 00:00:00.000000
$datetime->modify('yesterday');

// 2001-02-02 18:00:00.000000
$datetime->modify('6pm');

$datetime->modify()方法是修改DateTime的任何实例的最简单方法。

但是,由于解析,它效率低下。如果您要修改1000个日期/时间,并且需要更好的性能,请使用add()sub()setDate()setISODate()setTime()和{{ 3}},而不是modify()

$datetime = new DateTime('2001-01-01');

// 2001-06-01 00:00:00.000000
$datetime->setDate(2001, 6, 1);

// 2001-06-01 06:30:00.000000
$datetime->setTime(6, 30, 0);

// No sane person should ever do the below when they could just add 10,000
// seconds, but it's a good way to test how fast your system will handle
// updating DateTime.
$timestamp = $datetime->getTimestamp();
foreach (range(1, 10000) as $i) {
    $timestamp++;
    $datetime->setTimestamp($timestamp);
}
// 2001-06-01 09:16:40.000000

2。如何格式化日期/时间字符串?

通常,您需要获取1个日期/时间字符串并将其格式化为另一个日期/时间字符串,甚至只需获取现有的日期/时间并对其进行更新。 DateTime类也使这一过程变得简单。

方法

DateTime具有方法setTimestamp(),该方法以格式化字符串的形式返回日期/时间。

$datetime = new DateTime;
$format   = 'Y-m-d H:i:s';
echo $datetime->format($format);

我们将仅使用这些示例中可用格式设置的一小部分,因此强烈建议您查看format()formatting dates/times上的文档。

注意:请注意,如果尝试转义可能是PHP字符串转义字符的字符,则可能会得到意外的结果。

结果不正确

// output: Da   e 2000-12-31
echo $datetime->format("\D\a\t\e\: Y-m-d").PHP_EOL;

更正结果

// output: Date 2000-12-31
echo $datetime->format("\D\a\\t\e\: Y-m-d").PHP_EOL;

// output: Date 2000-12-31
echo $datetime->format('\D\a\t\e\: Y-m-d').PHP_EOL;

示例

这些是您可能需要的一些常见格式:

SQL日期/时间

// output: 2000-12-31
echo $datetime->format('Y-m-d').PHP_EOL;

// output: 23:59:59
echo $datetime->format('H:i:s').PHP_EOL;

// output: 2000-12-31 23:59:59
echo $datetime->format('Y-m-d H:i:s').PHP_EOL;

最终用户可读日期/时间

// output: 12/31/2000
echo $datetime->format('n/j/Y').PHP_EOL;

// output: 11:59pm
echo $datetime->format('g:ia').PHP_EOL;

// output: 12/31/2000 at 11:59pm
echo $datetime->format('n/j/Y \a\t g:ia').PHP_EOL;

// output: Sunday the 31st of December 2000 at 11:59:59 PM
echo $datetime->format('l \t\h\e jS \o\f F Y \a\t g:i:s A').PHP_EOL;

带时区的日期/时间

date_default_timezone_set('America/New_York');
$datetime = new DateTime('2000-12-31 23:59:59');

// output: 2000-12-31 23:59:59 America/New_York
echo $datetime->format('Y-m-d H:i:s e').PHP_EOL;

// output: 2000-12-31 23:59:59 EST
echo $datetime->format('Y-m-d H:i:s T').PHP_EOL;

// output: 2000-12-31 23:59:59 -0500
echo $datetime->format('Y-m-d H:i:s O').PHP_EOL;

3。如何获得2次之间的差额?

通常需要知道2个日期/时间之间的时间差。使用DateTime实际上有3种不同的方法来实现这一目标,而您将要使用哪种取决于您的需求。

操作方式(带有示例)

方案1:您只需要知道$datetime1是否大于,小于或等于$datetime2

在这种情况下,您可以直接比较DateTime的实例。

$datetime1 = new DateTime;
sleep(1);
$datetime2 = new DateTime;

var_dump($datetime1 > $datetime2); // FALSE
var_dump($datetime1 < $datetime2); // TRUE
var_dump($datetime1 == $datetime2); // FALSE

方案2:您需要将$datetime1$datetime2之间的差异表示为细分的年/月/日/等。

这在大多数情况下都适用,但是您从predefined DateTime constants返回的DateInterval实例具有其自己的“陷阱”,可能不适用于您的特定用例。

$datetime1 = new DateTime('2000-01-01 00:00:00.000000');
$datetime2 = new DateTime('2001-02-03 04:05:06.789012');
$diff      = $datetime1->diff($datetime2);

// output: 1 Years, 1 Months, 2 Days, 4 Hours, 5 Minutes, 6 Seconds
echo $diff->format('%y Years, %m Months, %d Days, %h Hours, %i Minutes, %s Seconds');

方案3:您需要用另一种方式表示$datetime1$datetime2之间的区别。

这将在任何情况下都起作用,但需要花费一些额外的代码。

$interval   = 60 * 60 * 24; // 1 day in seconds
$datetime1  = new DateTime('2000-01-01');
$datetime2  = new DateTime;
$diff       = $datetime2->getTimestamp() - $datetime1->getTimestamp();

// output: It has been 6956 days since 2000-01-01!
printf('It has been %s days since %s!', floor($diff / $interval), $datetime1->format('Y-m-d'));

4。如何计算时区?

在编程中要处理时间时,到目前为止,最糟糕的部分是处理时区。幸运的是,DateTime类可以优雅地处理其他事情。

方法

$datetime->diff()允许您在日期/时间字符串或第二参数中指定源时区。之后,只需使用DateTime's constructor设置新时区,然后DateTime就会处理其余的时间。

// These 2 lines are functionally identical
$datetime = new DateTime('2001-01-01 00:00:00', new DateTimeZone('UTC')); // recommended, may be faster
$datetime = new DateTime('2001-01-01 00:00:00 UTC');

$datetime->setTimezone(new DateTimeZone('EST'));

我建议查看$datetime->setTimezone()的完整列表以及PHP's supported time zones上的文档。

示例

假设您想向最终用户显示客户支持行在其时区中打开的时间。使用DateTime时,代码将如下所示:

$support_opens      = new DateTime('08:00:00', new DateTimeZone('America/New_York'));
$customer_timezones = array('America/New_York', 'America/Chicago', 'America/Denver', 'America/Phoenix', 'America/Los_Angeles', 'America/Anchorage', 'America/Adak', 'Pacific/Honolulu');

echo "Today we open at the following times:".PHP_EOL;
foreach ($customer_timezones as $timezone) {
    $support_opens->setTimezone(new DateTimeZone($timezone));
    echo '* '.$support_opens->format('g:ia \f\o\r \t\h\e e').' time zone'.PHP_EOL;
}

输出:

Today we open at the following times:
* 8:00am for the America/New_York time zone
* 7:00am for the America/Chicago time zone
* 6:00am for the America/Denver time zone
* 6:00am for the America/Phoenix time zone
* 5:00am for the America/Los_Angeles time zone
* 4:00am for the America/Anchorage time zone
* 3:00am for the America/Adak time zone
* 3:00am for the Pacific/Honolulu time zone

通知:如果您同时在日期/时间字符串和第二个参数中都提供了时区,则参数时区将被忽略。

$datetime = new DateTime('2001-01-01 00:00:00 EST', new DateTimeZone('UTC'));

// output: 2001-01-01 00:00:00 EST
echo $datetime1->format('Y-m-d H:i:s');
相关问题