每个人都必须在编程的某个时候处理日期/时间格式,时区,怪异的时间格式等。 PHP很少有解决这些问题的方法,其中最著名的是PHP内置于DateTime
类中。这是因为DateTime
类充当了所有这些问题的一体解决方案。
但是,DateTime
类有一个缺陷:如果您还不熟悉它,可能会令人困惑。
这篇文章旨在帮助那些想进一步了解DateTime
类和/或发现自己问以下问题之一的人:
请注意:
本文不会讨论date()
,time()
,strtotime()
或其任何相关功能的用法。这篇文章纯粹是为了解释DateTime
及其在PHP中相关类的正确用法。尽管许多答案也可以通过date()
及其相关功能来实现,但DateTime
会将所有功能包装到几个干净的类中。这样可以更容易地整体理解。
答案 0 :(得分:1)
以下大多数信息可以从PHP's documentation of the DateTime
class的各个部分获得。但是,此答案的格式应能回答 most 个关于DateTime
类的人的问题,并应适用于 most 个用例。>
如果您尝试使用日期/时间进行更高级的操作,例如创建DateTime
包装器,使用不可变的DateTime
实例或其他特定于您的应用程序的需求,我强烈建议您结帐完整的Date and Time documentation。
编程中最困难的事情之一就是尝试使最终用户输入变得可用。但是,在日期和时间方面,DateTime
类实际上是儿童游戏。
DateTime
的构造函数使用功能强大的解析器,该解析器接受最广为人知的格式,包括相对格式。
$datetime = new DateTime($datetime_string);
从那里,您可以使用以下任何一种方法来修改时间:
$datetime->modify()
-更改时间戳(适用于相对格式!)$datetime->add()
-向DateTime对象添加天,月,年,小时,分钟和秒的数量$datetime->sub()
-从DateTime对象中减去几天,几个月,几年,几小时和几秒钟的时间$datetime->setDate()
-设置日期$datetime->setISODate()
-设置ISO日期$datetime->setTime()
-设置时间$datetime->setTimestamp()
-根据Unix时间戳设置日期和时间(非常适合处理跨时区的绝对时间!)要查看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
类也不是完美的,并且不支持每种格式。这就是为什么您应该始终将DateTime
与try ... 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
通常,您需要获取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;
通常需要知道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'));
在编程中要处理时间时,到目前为止,最糟糕的部分是处理时区。幸运的是,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');