oop-klass

Introduction

介绍

Since I wrote the original article about Handling Date and Time in PHP and MySQL several years ago, it seemed like now was a good time to update it for object-oriented PHP.  This article does that, replacing as much as possible the principles and examples of the original article on a 1:1 basis.  As I created the examples for this article, I came across some anomalies in the PHP OOP DateTime implementation.  Here are some of my impressions and some notable gotcha's that I found.

自从几年前我写了有关在PHP和MySQL中处理日期和时间的原始文章以来,现在似乎是对面向对象PHP进行更新的好时机。 本文做到了这一点,并尽可能以1:1的方式替换了原始文章的原理和示例。 在创建本文的示例时,我遇到了PHP OOP DateTime实现中的一些异常情况。 这是我的一些印象以及发现的一些值得注意的陷阱。

It is possible to create an infinite loop with date/time arithmetic.  Your code will look right, but transitions at the boundaries of daylight savings time will change the values in your DateTime objects.  I hope PHP will fix this.

可以使用日期/时间算法创建无限循环。 您的代码将看起来正确,但是在夏时制边界上的过渡将更改DateTime对象中的值。 我希望PHP将解决此问题。

See: http://php.net/manual/en/datetime.sub.php#114780

请参阅: http : //php.net/manual/en/datetime.sub.php#114780

When you create a new DateTime object, you can assign both a date/time string and a timezone.  If you create the DateTime object from a Unix timestamp, the timezone cannot be used in the constructor.  You must assign the timezone to the object separately, after the object is created.

创建新的DateTime对象时,可以同时分配日期/时间字符串和时区。 如果从Unix时间戳创建DateTime对象,则不能在构造函数中使用时区。 创建对象后,必须将时区分别分配给该对象。

The ISO-8601 format for DateTime::format() method is not 100% ISO-8601 compatible.  You can use DateTime::ATOM instead if you need perfect compatibility.

DateTime :: format()方法的ISO-8601格式不是100%与ISO-8601兼容。 如果需要完美的兼容性,则可以改用DateTime :: ATOM。

The designator for a Unix timestamp in DateTime::__construct() is the at-sign ("@") prepended to the numeric Unix timestamp.  The at-sign ("@") is also the PHP error-control operator, but it has no error-control meaning in the DateTime constructor.

DateTime :: __ construct()中Unix时间戳的代号是数字Unix时间戳的前置符号(“ @”)。 符号(“ @”)也是PHP错误控制运算符 ,但在DateTime构造函数中没有错误控制的含义。

There is no avoiding arithmetic - DateTime::getOffset() returns its answer in seconds, but functions that use this information may expect minutes or hours.

没有回避的算术-DateTime :: getOffset()以秒为单位返回其答案,但是使用此信息的函数可能需要数分钟或数小时。

I found no convenient way to instantiate a DateTime object and get a formatted date/time string in a single line of code.  The marriage of PHP date() and strtotime() was a convenience that is not here any more.  I'll update this article if I find a good solution.

我发现没有方便的方法来实例化DateTime对象并在一行代码中获取格式化的日期/时间字符串。 PHP date()和strtotime()的结合是一种便利,这里不再赘述。 如果找到一个好的解决方案,我将更新本文。

At PHP 7.1+ the DateTime constructor incorporates microseconds when the object is constructed from the current time.  This may increase the risk that two DateTime objects will be unequal.

在PHP 7.1+中,从当前时间构造对象时,DateTime构造函数包含微秒。 这可能会增加两个DateTime对象不相等的风险 。

Now the good news.  Most of what you learned about date formatting with the date() format parameters is still applicable.  You will write a little more code with the OOP notation, but that is common for OOP programming and may help to improve readability.  And none of the common tasks we use in procedural PHP is impeded by the OOP DateTime notation.  A list of the most useful references is included at the end of this Article.

现在是个好消息。 您所学到的有关使用date()格式参数进行日期格式设置的大多数知识仍然适用。 您将使用OOP表示法编写更多代码,但这在OOP编程中很常见,并且可能有助于提高可读性。 OOP DateTime表示法没有阻碍我们在过程PHP中使用的任何常见任务。 本文结尾处列出了最有用的参考资料。

The DATE/TIME Tower of Babel

巴别塔的日期/时间塔

Human beings can read dates and times in a variety of ways.  We readily understand such things as September 5th, 2010, and we know that it comes before November 11th, 2010,and after May 9th, 2010.  We have shorthand conventions that let us write things like 9/5/2010 or the military correspondence format 5 Sep 2010.  But when we try to process dates and times in a computer program, this variety of formats becomes a jumble of confusion.  In response to the confusion, the International Organization for Standards was moved to publish a standard in 1988.  The standard has been revised and extended somewhat since the original publication.  The only thing that mystifies students of history is why it took so long to promulgate a standard.

人类可以以多种方式读取日期和时间。 我们很容易理解诸如2010年9月5日之类的东西,并且知道它早于2010年11月11日以及2010年5月9日之后。我们有速记约定,可让我们编写诸如9/5/2010之类的内容或军事通信格式2010年9月5日。但是,当我们尝试在计算机程序中处理日期和时间时,这种多种格式变得一团混乱。 为了应对这种混乱,国际标准组织(International Organization for Standards)于1988年被要求发布标准。自最初发布以来,该标准已经过修订和扩展。 唯一使历史学生感到迷惑的是为什么要花这么长时间颁布标准。

Toward a Universal DATETIME Notation

迈向通用DATETIME表示法

Date formats for computer processing are prescribed by the ISO-8601 standard.  The ISO-8601 standard places all the information in fixed-width data strings with leading zeros where needed.  When you read ISO-8601 standard information you notice immediately that everything lines up in columns.  The larger values are to the left and progressively smaller values are to the right, starting with Year, then Month, then Day, then Hour, etc.  Date/time information formatted according to the standard is very useful because it is both easy to read and easy to understand in comparisons and computations.  For example, the date '2010-09-05' is a valid ISO-8601 string meaning September 5th, 2010.  Imagine how difficult it would be to write programming that works with dates in the text formats, or dates that are formatted like this: 05.09.2010.  Does that mean May 9th, 2010 or September 5th, 2010?  Fortunately the ISO-8601 standard removes the ambiguity.

ISO-8601标准规定了用于计算机处理的日期格式。 ISO-8601标准将所有信息放置在固定宽度的数据字符串中,并在需要时使用前导零。 当您阅读ISO-8601标准信息时,您会立即注意到所有内容都按列排列。 较大的值在左侧,逐渐减小的值在右侧,依次从年,月,日,小时,小时等开始。按照标准格式化的日期/时间信息非常有用,因为它们都易于阅读并且在比较和计算中易于理解。 例如,日期'2010-09-05'是一个有效的ISO-8601字符串,表示2010年9月5日。想象一下编写使用文本格式的日期或格式如下的日期的程序有多么困难:2010年9月9日。 这意味着2010年5月9日还是2010年9月5日? 幸运的是,ISO-8601标准消除了歧义。

The ISO-8601 standard removes the ambiguity about the time of day, as well.  All of the hours are represented on a 24-hour clock, so there is no question about what "two o'clock" might mean.  The string 0200 or 02:00:00 refers to 2:00 a.m.  If you're thinking of 2:00 p.m. your ISO-8601 standard will use 14:00:00.

ISO-8601标准也消除了一天中的不确定性。 所有小时均以24小时制表示,因此毫无疑问“两点钟”是什么意思。 字符串0200或02:00:00表示凌晨2:00。如果您考虑的是下午2:00,则ISO-8601标准将使用14:00:00。

This link gives a good discussion and examples of permissible variations on the ISO-8601 format.

该链接很好地讨论了ISO-8601格式,并提供了允许的变化示例。

See http://en.wikipedia.org/wiki/ISO_8601

参见http://en.wikipedia.org/wiki/ISO_8601

The Value of PHP time() is Always the Same

PHP time()的值始终相同

No matter where in the world you stand, the value of time() is always the same.  The PHP function time() returns the number of seconds since the Unix Epoch.  While local times may differ, time() ticks on second-by-second.  Run this script to see the effect.  Knowing this, we can do arithmetic with seconds, and then return human-readable date and time values that are sensible for different locations around the world.

无论您站在世界的哪个角落, time()的值始终是相同的。 PHP函数time()返回自Unix时代以来的秒数。 虽然当地时间可能会有所不同,但time()会逐秒滴答。 运行此脚本以查看效果。 知道了这一点,我们可以用秒进行算术运算,然后返回人类可读的日期和时间值,这些值对于世界各地是明智的。

<?php
/**
* Different Timezones share the same Unix Timestamp
*/
error_reporting(E_ALL);
echo '<pre>';
// TIMEZONES AROUND THE GLOBE
$locations
= array
( 'Pacific/Auckland'
, 'Australia/Sydney'
, 'Australia/Perth'
, 'Asia/Tokyo'
, 'Asia/Calcutta'
, 'Asia/Tel_Aviv'
, 'Africa/Cairo'
, 'Europe/Rome'
, 'Europe/London'
, 'Atlantic/Bermuda'
, 'America/Chicago'
, 'America/Anchorage'
, 'Pacific/Honolulu'
, 'UTC'
)
;
// ITERATE OVER THE TIMEZONES
foreach ($locations as $location)
{
// SET OUR ZONE AND LOCAL TIME
$zoneobj = new DateTimeZone($location);
$dateobj = new DateTime(NULL, $zoneobj);
// SHOW THE LOCATION AND THE CURRENT DATE / TIME
echo PHP_EOL;
echo str_pad($location, 24, ' ');
echo $dateobj->format(DateTime::RSS);
// SHOW THE NUMBER OF SECONDS SINCE THE EPOCH, RECOMPUTED IN EACH TIMEZONE
echo ' ';
echo $dateobj->format('U');
}

Handling External Input

处理外部输入

Whenever you accept a date/time string from an external data source, what is the first thing you should do?  Turn it (immediately) into an instance of the DateTime object.  The DateTime constructor can turn almost any English language human-readable date/time text into an object for use in DateTime computations and displays. Like the PHP function date(), the DateTime::format() method can turn DateTime information into a formatted date.

每当您从外部数据源接受日期/时间字符串时,您应该做的第一件事是什么? (立即)将其转换为DateTime对象的实例。 DateTime构造函数可以将几乎所有英语可读的日期/时间文本转换为对象,以用于DateTime计算和显示。 与PHP函数date()一样,DateTime :: format()方法可以将DateTime信息转换为格式化的日期。

<?php
/**
* The DateTime constructor may throw an Exception
*/
error_reporting(E_ALL);
echo '<pre>';
$external = 'Yesterday';
try
{
$dateobj = new DateTime($external);
}
catch (Exception $e)
{
// ON FAILURE, SHOW THE EXCEPTION
var_dump($e);
}
echo PHP_EOL . $dateobj->format(Datetime::ATOM);
echo PHP_EOL;

Once you have done that internal date format conversion your programming will handle internal date/time computations easily.

完成内部日期格式转换后,您的程序将轻松处理内部日期/时间计算。

When you are storing date/time values, you may want to store them in the ISO-8601 format strings or in the form of Unix timestamps.  I prefer to use the formatted strings - they are easier to understand when you're debugging.

当存储日期/时间值时,您可能希望以ISO-8601格式的字符串或Unix时间戳的形式存储它们。 我更喜欢使用格式化的字符串-调试时更易于理解。

Handling External Input that is Invalid

处理无效的外部输入

The PHP DateTime constructor can turn virtually any human-readable date / time text into a DateTime object - but it won't work on everything.  When it fails to make the conversion, it throws Exception.  You can and should test for this.

PHP DateTime构造函数实际上可以将任何人类可读的日期/时间文本转换为DateTime对象-但它不适用于所有事物。 如果无法进行转换,则会抛出Exception 。 您可以并且应该对此进行测试。

<?php
/**
* Invalid date/time strings can be detected when you catch the Exception
*/
error_reporting(E_ALL);
echo '<pre>';
$external = 'Nonsense';
$dateobj  = FALSE;
try
{
$dateobj = new DateTime($external);
}
catch (Exception $e)
{
// ON FAILURE, SHOW THE EXCEPTION
var_dump($e);
}
if ($dateobj)
{
$iso_datetime = $dateobj->format(Datetime::ATOM);
echo "SUCCESS: $external EQUALS ISO-8601 $iso_datetime";
}
else
{
echo "ERROR: I DO NOT UNDERSTAND $external";
}

Handling External Input that is Formatted (contrary to the disambiguation rules)

处理格式化的外部输入 (与消歧规则相反)

The PHP DateTime Constructor works much the same way as strtotime(), making some assumptions and obeying certain rules about the format of the date / time input string.  But what if you have dates that are not formatted according to the rules?  One of the common issues arises when we have dates that are in European order d-m-y, but have been written with slashes, implying American order m/d/y.  This may result in incorrect output when the values for m and d  are both in the range from 1 - 12, and will cause an exception when m exceeds 12.  Fortunately PHP has a way around this issue, in the static constructor createFromFormat().  We can tell PHP what format to use as it interprets the date.  This example shows how.

PHP DateTime构造函数的工作方式与strtotime()大致相同,它作一些假设并遵守有关日期/时间输入字符串格式的某些规则。 但是,如果您的日期没有按照规则格式化,该怎么办? 常见问题之一是当我们的日期与欧洲dmy顺序相同但用斜线写成时,表示美国的m / d / y顺序。 这可能会导致不正确的输出,当md的值均为在从范围1 - 12,并且当m超过12,幸运PHP有解决此问题的一种方式,在静态构造将导致异常createFromFormat() 。 我们可以告诉PHP在解释日期时使用哪种格式。 这个例子说明了如何。

<?php
/**
* Date values separated by slash are assumed to be in American order: m/d/y
* Date values separated by dash are assumed to be in European order: d-m-y
* Exact formats for date/time strings can be injected with createFromFormat()
*
* http://php.net/manual/en/datetime.createfromformat.php
*/
error_reporting(E_ALL);
echo '<pre>';
// THIS WOULD IMPLY MONTH == 19, OBVIOUSLY INVALID
$external = "19/10/2016 14:48:21";
// HOWEVER WE CAN INJECT THE FORMATTING WHEN WE DECODE THE DATE
$format = "d/m/Y H:i:s";
$dateobj = DateTime::createFromFormat($format, $external);
$iso_datetime = $dateobj->format(Datetime::ATOM);
echo "SUCCESS: $external EQUALS ISO-8601 $iso_datetime";

Interesting Forms of External Input

外部输入的有趣形式

All of these external inputs work correctly with the DateTime constructor and this gives you and your clients powerful ways of talking about dates and computing with dates.

所有这些外部输入都可以与DateTime构造函数一起正常使用,这为您和您的客户提供了讨论日期和使用日期进行计算的强大方法。

- 3 hours

- 3小时

tomorrow

明天

tomorrow midnight

明天午夜

tomorrow 1:35pm

明天下午1:35

March 15, 1986

1986年3月15日

yesterday

昨天

yesterday + 1 week

昨天+ 1周

next year

明年

now

现在

now + 627 hours 15 minutes

现在+ 627小时15分钟

last Tuesday

上个星期二

third Wednesday

第三个星期三

3 minutes, 15 seconds

3分15秒

Producing "Pretty" Dates From DateTime Objects ISO-8601 Dates

从DateTime对象ISO-8601日期产生“漂亮”日期

When you are ready to present the dates to people and you want them to see nicely formatted dates, you can use the DateTime::format() method to do the reformatting.  Let's say you have this timestamp value: 1,284,593,400 (which equals the ISO-8601 date: '2010-09-15T18:30:00-0500'. )  Maybe you got it out of your data base or computed it in your script.  It's meaningful, but not what you expect when you open the envelope.  "Please join us for cocktails on Unix Timestamp 1,284,593,400."  How can we get something that would be appropriate on an invitation?  Here is how you might do the conversion from a timestamp or ISO-8601 date to the pretty date.

当您准备向人们展示日期并希望他们看到格式正确的日期时,可以使用DateTime :: format()方法进行重新格式化。 假设您有以下时间戳记值:1,284,593,400(等于ISO-8601日期:'2010-09-15T18:30:00-0500'。)也许您是从数据库中获得它或在脚本中对其进行了计算。 这很有意义,但是打开信封时没有达到预期的效果。 “请加入我们以Unix Timestamp 1,284,593,400的鸡尾酒。” 我们如何才能获得合适的邀请函? 这是从时间戳或ISO-8601日期到漂亮日期的转换方法。

<?php
/**
* The DateTime::format() can change the rendering of date values and produce pretty dates
*/
error_reporting(E_ALL);
echo '<pre>';
$iso_date = '2010-09-15T18:30:00';
$formats  = 'l, F jS, Y \a\t g:ia';
$dateobj  = new DateTime($iso_date);
echo PHP_EOL . $dateobj->format($formats);

Outputs "Wednesday, September 15th, 2010 at 6:30pm" -- very civilized!

输出“ 2010年9月15日,星期三,下午6:30” –非常文明!

Breaking down the date formatting, we have the following (all documented on PHP.net)...

分解日期格式,我们有以下内容(全部记录在PHP.net上)...

$pattern
= 'l, '    // LOWERCASE L - text name of the day of the week
. 'F '     // UPPERCASE F - text name of the month
. 'j'      // LOWERCASE J - day of the month
. 'S, '    // UPPERCASE S - ordinal like the letters in 1st, 2nd, etc
. 'Y '     // UPPERCASE Y - 4-digit year
. '\a\t '  // ESCAPED LETTERS... More to follow
. 'g:'     // LOWERCASE G - hours on a 12-hour clock
. 'i'      // LOWERCASE I - minutes
. 'a'      // LOWERCASE A - designator of "am" or "pm"
;

You might envision several patterns that you need in your application.  Most PHP sites and services are written with a central "common.php" file that gets included into all the specialized scripts.  You could prepare the formatting patterns in the common script and refer to them by a variable name, or define the patterns as constants.

您可能会设想应用程序中需要的几种模式。 大多数PHP网站和服务都是使用中央“ common.php”文件编写的,该文件已包含在所有专用脚本中。 您可以在通用脚本中准备格式设置模式,并通过变量名称引用它们,或者将模式定义为常量。

define('MILITARY_CORRESPONDENCE', 'j M y');
define('SHORT_8601', 'Y-m-d');
define('COCKTAILS', 'l, F jS, Y \a\t g:ia');

What about the escaped letters?  Like the date() function, the DateTime::format() uses letter patterns as signals to describe the conversion into human-readable character strings, so some letters have special relevance and some do not.  Any character that is not used as a signal in the date pattern string is returned from the function unaltered.  Punctuation is one example - commas and hyphens go right through.  But if we want to get one of the signal letters back, we must tell PHP to ignore the signal and just return the letter.  We do that with the back-slash character, as shown here.  Try running these two lines of code to see how the escape can be useful:

那逃脱的信件呢? 与date()函数一样,DateTime :: format()使用字母模式作为信号来描述转换为人类可读的字符串,因此某些字母具有特殊的相关性,而有些则没有。 日期模式字符串中未用作信号的任何字符都将从函数不变地返回。 标点符号就是一个例子-逗号和连字符会一直通过。 但是,如果我们想取回其中一个信号字母,则必须告诉PHP忽略该信号并仅返回该字母。 我们使用反斜杠字符来实现,如下所示。 尝试运行以下两行代码,以了解转义如何有用:

echo PHP_EOL . date('The year is: Y');
echo PHP_EOL . date('\T\h\e \y\e\a\r\ \i\s\: Y');

Setting Your Own Clock Values

设置自己的时钟值

Since the values contained in the DateTime object are usable in many different time zones, you want to have control over the way PHP interprets the time zone.  You control this time with the DateTimeZone object.  You can set the DateTimeZone in the DateTime constructor, or you can inject a new DateTimeZone into a DateTime object via the setTimeZone() method.  Here is an example that I use, because my server is located in the midwest at ChiHost.com.

由于DateTime对象中包含的值可在许多不同的时区中使用,因此您希望控制PHP解释时区的方式。 您可以使用DateTimeZone对象控制此时间。 您可以在DateTime构造函数中设置DateTimeZone,也可以通过setTimeZone()方法将新的DateTimeZone注入DateTime对象。 这是我使用的示例,因为我的服务器位于ChiHost.com的中西部。

<?php
/**
* DateTime objects are usually aware of time zones via the DateTimeZone object
*/
error_reporting(E_ALL);
echo '<pre>';
$string  = 'Now';
$zoneobj = new DateTimeZone("America/Chicago");
$formats = 'l, F jS, Y \a\t g:ia (e)';
$dateobj = new DateTime($string, $zoneobj);
echo PHP_EOL . $dateobj->format($formats);
// WHAT TIMEZONE SHOULD I USE?
$tz_ids = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, 'US');
foreach($tz_ids as $zone)
{
echo PHP_EOL . $zone;
}

Special Meanings for NOW and TODAY

现在和今天的特殊含义

We know how to convert external date/time strings into DateTime objects, and we know how to return them to human-preferred formats with DateTime::format().  Now we can return to some of the special meanings of date/time strings.  NOW and TODAY are particularly useful.

我们知道如何将外部日期/时间字符串转换为DateTime对象,并知道如何使用DateTime :: format()将其返回为人类首选的格式。 现在,我们可以返回日期/时间字符串的一些特殊含义。 现在和今天特别有用。

<?php
/**
* NOW and TODAY have special meanings in the DateTime object; NOW includes time of day
*/
error_reporting(E_ALL);
echo '<pre>';
$date = new DateTime('Now');
echo PHP_EOL . $date->format(DateTime::RSS);
$date = new DateTime('Today');
echo PHP_EOL . $date->format(DateTime::RSS);
$date = new DateTime('Now', new DateTimeZone('UTC'));
echo PHP_EOL . $date->format(DateTime::RSS);
$date = new DateTime('Today', new DateTimeZone('UTC'));
echo PHP_EOL . $date->format(DateTime::RSS);

The principal difference between NOW and TODAY is the time of day.  TODAY is always today's local date at midnight, with hour, minute and second equal to zero.  NOW is today's date including the current time of day.  So in our September example, NOW and TODAY have UNIX timestamp values equal to 1,284,593,400 and 1,284,526,800 respectively.  The difference is 66,600.  This is the number of seconds from midnight to 6:30pm (18 hours plus 30 minutes).

NOW和TODAY之间的主要差异是一天中的时间。 今天始终是今天的午夜当地时间 ,时,分和秒等于零。 现在是今天的日期,包括当天的当前时间。 因此,在我们的9月示例中,NOW和TODAY的UNIX时间戳值分别等于1,284,593,400和1,284,526,800。 差异为66,600。 这是从午夜到下午6:30(18小时加30分钟)的秒数。

This script shows that the Unix timestamp is consistent, no matter what timezone you have specified.

该脚本表明,无论您指定了哪个时区,Unix时间戳都是一致的。

<?php
/**
* The Unix Timestamp values for NOW and TODAY are the same, no matter what timezone
*/
error_reporting(E_ALL);
echo '<pre>';
$dateobj = new DateTime('Now');
echo PHP_EOL . $dateobj->format('U');
$dateobj = new DateTime('Today');
echo PHP_EOL . $dateobj->format('U');
$dateobj = new DateTime('Now', new DateTimeZone('UTC'));
echo PHP_EOL . $dateobj->format('U');
$dateobj = new DateTime('Today', new DateTimeZone('UTC'));
echo PHP_EOL . $dateobj->format('U');

Computing the Difference Between DateTime Objects

计算DateTime对象之间的差异

This script shows how to compute the difference between two DateTime objects, using the diff() method.

该脚本显示了如何使用diff()方法计算两个DateTime对象之间的差异 。

<?php
/**
* Computing the difference between NOW and TODAY in different timezones
*/
error_reporting(E_ALL);
echo '<pre>';
// TESTING UTC
$zoneobj    = new DateTimeZone('UTC');
$date_now   = new DateTime('Now',   $zoneobj);
$date_today = new DateTime('Today', $zoneobj);
$date_diff  = $date_now->diff($date_today);
$print_diff = $date_diff->format('%H:%i:%S');
echo PHP_EOL . $zoneobj->getName();
echo PHP_EOL . $print_diff;
echo PHP_EOL;
// TESTING ANOTHER ZONE
$zoneobj    = new DateTimeZone('America/New_York');
$date_now   = new DateTime('Now',   $zoneobj);
$date_today = new DateTime('Today', $zoneobj);
$date_diff  = $date_now->diff($date_today);
$print_diff = $date_diff->format('%H:%i:%S');
echo PHP_EOL . $zoneobj->getName();
echo PHP_EOL . $print_diff;
echo PHP_EOL;
// USING METHOD CHAINING FOR TIGHTER CODE
$print_diff  = $date_now->diff($date_today)->format('%H:%i:%S');
echo PHP_EOL . $zoneobj->getName();
echo PHP_EOL . $print_diff;
echo PHP_EOL;

As you can see, it is important to be consistent about your timezone.  You can deal with this phenomenon in one of two ways.  You can set your timezone to UTC.  Or you can set your timezone to a reasonable setting for the location of your server.  I prefer the latter.  See http://php.net/manual/en/timezones.php and http://php.net/manual/en/timezones.others.php for more.

如您所见,保持时区一致很重要。 您可以通过以下两种方法之一来处理这种现象。 您可以将时区设置为UTC。 或者,您可以将时区设置为服务器位置的合理设置。 我更喜欢后者。 有关更多信息,请参见http://php.net/manual/en/timezones.php和http://php.net/manual/en/timezones.others.php 。

Time Without Date

没有日期的时间

Let's say we want to know the elapsed time between two events, and we want to express it in notation like HH:MM:SS. DateTime::diff() and DateTime::format() can help with this.

假设我们想知道两个事件之间的经过时间,并希望以HH:MM:SS之类的方式表示它。 DateTime :: diff()和DateTime :: format()可以帮助您解决此问题。

<?php
/**
* Computing the difference between two times
*/
error_reporting(E_ALL);
echo '<pre>';
$alpha = "2:30:47pm";
$omega = "3:43:16pm";
$date_alpha = new DateTime($alpha);
$date_omega = new DateTime($omega);
$elapsed    = $date_omega->format('U') - $date_alpha->format('U');
$date_diff  = $date_omega->diff($date_alpha);;
$print_diff = $date_diff->format('%H:%i:%S');
echo PHP_EOL . "TWIXT $alpha AND $omega THERE ARE " . number_format($elapsed) . " SECONDS";
echo PHP_EOL . "RIGHT ELAPSED TIME IS $print_diff";

Leap Year and Daylight Savings Time

Year年和夏令时

These are amazingly easy in PHP.  But beware of a bug in DateTime::add(), illustrated in this code.

这些在PHP中非常容易。 但是请注意此代码中说明的DateTime :: add()中的错误。

<?php
/**
* Daylight Savings Time and Leap Year are easy, but...
*
* There is bug in the computations when using DateTime::add() across DST
*/
error_reporting(E_ALL);
echo '<pre>';
// USE THE SAME ZONE FOR ALL THESE TESTS
$zoneobj = new DateTimeZone('America/New_York');
// MAKE TESTS FOR THE CURRENT MOMENT
$dateobj = new DateTime('NOW', $zoneobj);
$leap    = $dateobj->format('L');
if ($leap) echo "IT IS A LEAP YEAR";
$dstt = $dateobj->format('I');
if ($dstt) echo "IT IS DAYLIGHT SAVINGS TIME";
// ILLUSTRATE A DST CHANGE IN OUR TIMEZONE
$alpha = new DateTime('November 2, 2014 01:57:00', $zoneobj);
$omega = new DateTime('November 2, 2014 02:02:00', $zoneobj);
echo PHP_EOL . $alpha->format('c');
if ($alpha->format('I')) echo ' IS DST';
echo PHP_EOL . $omega->format('c');
if ($omega->format('I')) echo ' IS DST';
echo PHP_EOL;
// YOU CAN ALSO FIND TIMEZONE INFORMATION IN "isdst" AND "abbr"
$tran = $zoneobj->getTransitions($alpha->format('U'), $alpha->format('U')+1);
var_dump($tran);
// GET THE TIMESTAMPS
$alpha_u = $alpha->format('U');
$omega_u = $omega->format('U');
// SHOW THE TRANSITION BETWEEN EDT AND EST
while ($alpha_u < $omega_u)
{
// CREATE A NEW DATETIME OBJECT FROM THE TIMESTAMP
$alpha = new DateTime("@$alpha_u");
// ASSIGN THE ZONE AND DETERMINE THE STATUS OF DST
$alpha->setTimeZone($zoneobj);
echo PHP_EOL . $alpha->format('r');
if ($alpha->format('I')) echo " IS DAYLIGHT SAVINGS TIME";
// INCREMENT THE TIMESTAMP BY SIXTY SECONDS
$alpha_u = $alpha_u + 60;
}
/**
* DO NOT DO IT THIS WAY; THIS WILL CAUSE AN INFINITE LOOP
*
$alpha = new DateTime('November 2, 2014 01:57:00', $zoneobj);
$omega = new DateTime('November 2, 2014 02:02:00', $zoneobj);
$minute = new DateInterval('PT1M'); // Pee-Tee-One-Em
// SHOW THE TRANSITION BETWEEN EDT AND EST
while ($alpha < $omega)
{
// THIS RECASTS THE TIME TO THE LOCAL CLOCK TIME
$alpha = $alpha->add($minute);
echo PHP_EOL . $alpha->format('r');
if ($alpha->format('I')) echo " IS DAYLIGHT SAVINGS TIME";
}
*/

Using mktime() in DATETIME Computations

在DATETIME计算中使用mktime()

The PHP mktime() function returns a Unix timestamp according to an argument list.  The arguments in order are hour, minute, second, month, day, year.  Because mktime() will work with out-of-range arguments, it can be useful for date calculations.  But in my experience it was better to use the DateInterval object.

PHP mktime()函数根据参数列表返回Unix时间戳。 参数顺序为小时,分钟,秒,月,日,年。 因为mktime()将使用超出范围的参数,所以它对于日期计算可能很有用。 但是以我的经验,最好使用DateInterval对象。

<?php
/**
* Using mktime() is not as dependable as using DateInterval
*/
error_reporting(E_ALL);
echo '<pre>';
// WORKS NO MATTER WHAT MONTH IT IS
$last_month = mktime(0, 0, 0, date("m")-1, date("d"), date("Y"));
var_dump($last_month);
// USE THE SAME ZONE FOR ALL THESE TESTS
$zoneobj = new DateTimeZone('America/New_York');
// HIGH NOON THIRTY DAYS FROM NOW - NOT RELIABLE BECAUSE OF DST TRANSITION
$dateobj = new DateTime( '@' . mktime(12, 0, 0, date("m"), date("d")+30, date("Y")) );
$dateobj->setTimeZone($zoneobj);
var_dump($dateobj->format('g:ia T \o\n D, M j, Y'));
// WORKS BETTER
$interval_p30d = new DateInterval('P30D');
$dateobj  = new DateTime('TODAY 12:00', $zoneobj);
$dateobj->add($interval_p30d);
var_dump($dateobj->format('g:ia T \o\n D, M j, Y'));

Ambiguity of the term "Month"

术语“月份”的歧义

PHP is very permissive in its language requirements when describing dates and this may lead to some confusion when it comes to months.  Consider the meaning of "next month" when used on January 5.  Obviously the answer is February 5.  Now consider what happens when it is January 30.  What should the correct answer be?  This code snippet shows how I handle this question.  Different business rules may apply for your work.  There may be ambiguity in leap year, too.  Consider "Feb 29, 2008 + 1 year."  You may want to install this script and let it inform your policy about the meaning of "month" in contracts and forecasts.

在描述日期时,PHP对其语言要求非常宽容,这可能会导致几个月的混乱。 考虑1月5日使用“下个月”的含义。答案显然是2月5日。现在考虑1月30日会发生什么。正确的答案应该是什么? 此代码段显示了我如何处理此问题。 不同的业务规则可能适用于您的工作。 leap年也可能有歧义。 考虑“ 2008年2月29日+一年”。 您可能需要安装此脚本,并使其在合同和预测中告知您的政策“月”的含义。

<?php
/**
* The term "month" may be ambiguous since months can have different numbers of days
*/
error_reporting(E_ALL);
echo '<pre>';
// USE THE SAME ZONE FOR ALL THESE TESTS
$zone = new DateTimeZone('America/New_York');
// TEST DATES INCLUDE SOME THAT MIGHT CAUSE AMBIGUITY WHEN YOU SAY "next month"
$my_dates
= array
( 'January 28, 2011'
, 'January 29, 2011'
, 'January 30, 2011'
, 'January 31, 2011'
, 'February 1, 2011'
, 'February 2, 2011'
, 'February 28, 2011'
, 'March 30, 2011'
, 'March 31, 2011'
)
;
$month = new DateInterval('P1M');
// TEST EACH OF THE DATES
foreach ($my_dates as $my_date)
{
$date = new DateTime($my_date, $zone);
$date->add($month);
echo PHP_EOL . "$my_date PLUS ONE MONTH = " . $date->format('r');
}
// TEST EACH OF THE DATES
foreach ($my_dates as $my_date)
{
list
( $safe_date
, $requested_day
, $actual_day
) = nextMonth($my_date, 'r');
echo PHP_EOL . "MY_DATE $my_date";
echo PHP_EOL . "NEXTMONTH $safe_date";
echo PHP_EOL . "REQUESTED DAY $requested_day";
echo PHP_EOL . "ACTUAL DAY $actual_day";
echo PHP_EOL;
}
function nextMonth($date, $format='c')
{
$timestamp  = strtotime($date);
$start_Y    = date('Y', $timestamp);
$start_m    = date('m', $timestamp);
$start_d    = date('d', $timestamp);
// MAKE A TIMESTAMP FOR THE FIRST, LAST AND REQUESTED DAY OF NEXT MONTH
$timestamp_first = mktime(0,0,0, $start_m+1,  1, $start_Y);
$timestamp_last  = mktime(0,0,0, $start_m+1, date('t', $timestamp_first), $start_Y);
$timestamp_try   = mktime(0,0,0, $start_m+1, $start_d, $start_Y);
// USE THE LESSER OF THE REQUESTED DAY AND THE LAST OF THE MONTH
if ($timestamp_try > $timestamp_last) $timestamp_try = $timestamp_last;
$good_date = date($format, $timestamp_try);
return array
( $good_date
, $start_d
, date('d', $timestamp_try)
)
;
}

Storing Date and Time in Your Database

在数据库中存储日期和时间

In MySQL, date columns are usually carried in the format DATE and DATETIME.  These are very "relaxed" fields.  You can insert invalid dates (such as February 31) and MySQL will accept these.  More on point, you can store and recall ISO-8601 datetime strings.  MySQL has a large complement of internal date and time functions.  You may sometimes find it practical to perform date / time calculations in your query strings.  See http://dev.mysql.com/doc/refman/5.5/en/datetime.html and http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html for references and examples.

在MySQL中,日期列通常以DATE和DATETIME格式携带。 这些是非常“轻松”的字段。 您可以插入无效的日期(例如2月31日),MySQL会接受这些日期。 更重要的是,您可以存储和调用ISO-8601日期时间字符串。 MySQL具有大量内部日期和时间函数。 您有时可能会发现在查询字符串中执行日期/时间计算很实用。 参见http://dev.mysql.com/doc/refman/5.5/en/datetime.html和http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html供参考和示例。

PHP and MySQL Have Different Time Zone Settings

PHP和MySQL具有不同的时区设置

Note that the time zone values for PHP and for MySQL are completely independent of each other.  You may want to adjust the time zones for one or both of these systems.  Use date_default_timezone_set() to adjust the value in PHP.  Use a query that says something like SET time_zone = '+00:00' to adjust the value in MySQL.  See http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html for more.  The code snippet illustrates this independence.

注意,PHP和MySQL的时区值彼此完全独立 。 您可能要调整其中一个或两个系统的时区。 使用date_default_timezone_set()调整PHP中的值。 使用类似SET time_zone ='+00:00'之类的查询来调整MySQL中的值。 有关更多信息,请参见http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html 。 该代码段说明了这种独立性。

<?php
/**
* PHP and MySQL have different and independent time settings
*/
error_reporting(E_ALL);
echo '<pre>';
// DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "??";
$db_user = "??";
$db_word = "??";
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);
// DID THE CONNECT/SELECT WORK OR FAIL?
if ($mysqli->connect_errno)
{
trigger_error("CONNECT FAIL: $mysqli->connect_errno $mysqli->connect_error", E_USER_ERROR);
}
// GET THE PHP TIME
$zoneobj = new DateTimeZone('GMT');
$dateobj = new DateTime('NOW', $zoneobj);
echo PHP_EOL . 'IN PHP, THE GMT TIME IS: ' . $dateobj->format('c');
echo PHP_EOL;
// GET THE DEFAULT MYSQL TIME SETTINGS
$res = $mysqli->query("SELECT CURRENT_TIMESTAMP AS t, NOW() AS n");
$row = $res->fetch_object();
echo PHP_EOL . 'IN MySQL, THE CURRENT TIMES ARE: ';
print_r($row);
echo PHP_EOL;
// SET THE MYSQL TIMEZONE TO GMT
$sql = "SET time_zone = '+00:00' ";
$res = $mysqli->query($sql);
echo PHP_EOL . "<b>$sql</b>";
// GET THE NEW MYSQL VALUES
$res = $mysqli->query("SELECT CURRENT_TIMESTAMP AS t, NOW() AS n");
$row = $res->fetch_object();
echo PHP_EOL . 'IN MySQL, THE CURRENT TIMES HAVE BEEN CHANGED TO: ';
print_r($row);
echo PHP_EOL;

Practical Application #1

实际应用#1

How old are you today? Given your birthday, this function can return your age. This is easier than the procedural way!

你今天几岁? 给您的生日,此功能可以返回您的年龄。 这比程序方式容易!

<?php
/**
* How old are you?  DateTime::diff() knows
*/
error_reporting(E_ALL);
echo '<pre>';
// A FUNCTION TO RETURN THE AGE ON A GIVEN DATE
function your_age($birth_day, $test_date='Today')
{
$alpha_date = new DateTime($birth_day);
$omega_date = new DateTime($test_date);
$diff = $omega_date->diff($alpha_date);
return $diff->y;
}
var_dump( your_age('May 12, 1993') );

Practical Application #2

实际应用#2

How many days between two dates?  DateTime::diff() knows.

两个日期之间有多少天? DateTime :: diff()知道。

<?php
/**
* Computing the difference between two dates
*/
error_reporting(E_ALL);
echo '<pre>';
function days_between($alpha='TODAY', $omega='TODAY')
{
$alpha_date = new DateTime($alpha);
$omega_date = new DateTime($omega);
$diff = $omega_date->diff($alpha_date);
return $diff->days;
}
var_dump( days_between() );
var_dump( days_between('September 15, 1950') );
var_dump( days_between('Yesterday', 'Tomorrow') );

Practical Application #3

实际应用#3

You want to know how many month, days, hours, minutes, and/or seconds will elapse before an upcoming event.  Given a DATETIME string this function can return a text string or array with the answers.  PHP uses years and months, which can be ambiguous, but the results of the computations and answers are usually satisfactory.

您想知道即将发生的事件之前要经过多少个月,几天,几小时,几分钟和/或几秒钟。 给定一个DATETIME字符串,此函数可以返回带有答案的文本字符串或数组。 PHP使用几年和几个月,这可能是模棱两可的,但是计算和答案的结果通常令人满意。

<?php
/**
* Elapsed time computations
*/
error_reporting(E_ALL);
echo '<pre>';
function elapsed($then, $return_array=FALSE)
{
$string = NULL;
// TIME DESCRIPTIVE TERMS
$terms["Y"] = 'year';
$terms["M"] = 'month';
$terms["D"] = 'day';
$terms["H"] = 'hour';
$terms["I"] = 'minute';
$terms["S"] = 'second';
$other = new DateTime($then);
$curnt = new DateTime('NOW');
// COMPUTE THE DIFFERENCE
$diff = $curnt->diff($other);
// SINCE $then IN THE PAST, UNTIL $then IN THE FUTURE
$since_until = 'until';
if ($diff->invert) $since_until = 'since';
// CREATE A PERIOD DESIGNATOR
$pd
= 'P'
. $diff->y    . 'Y'
. $diff->m    . 'M'
. $diff->d    . 'D'
. 'T'
. $diff->h    . 'H'
. $diff->i    . 'M'
. $diff->s    . 'S'
;
$intvl = new dateInterval($pd);
$formt['Y'] = $intvl->format('%y');
$formt['M'] = $intvl->format('%m');
$formt['D'] = $intvl->format('%d');
$formt['H'] = $intvl->format('%h');
$formt['I'] = $intvl->format('%i');
$formt['S'] = $intvl->format('%s');
// IF RETURNING AN ARRAY
if ($return_array) return $formt;
// MAP VALUES TO TERMS
foreach ($formt as $key => $num)
{
if ($num != 1) $terms[$key] = $terms[$key] . 's';
if ($num == 0) continue;
$string .= $num . ' ' . $terms[$key] . ', ';
}
$string = rtrim($string, ', ');
$string .= " $since_until $then";
return $string;
}
// USE CASES
$cases =
[ '+ 1 week'
, '- 1 week'
, '0 seconds'
, '+1304 hours +2917 seconds'
, 'May 12, 1993 2:05pm'
, '45 days, 6 hours, 277 seconds'
, '-375 days'
]
;
foreach ($cases as $case)
{
echo PHP_EOL . elapsed($case);
}

Practical Application #3a

实际应用#3a

You want to know if a given date is yesterday, today or tomorrow.  This function can tell you.

您想知道给定的日期是昨天,今天还是明天。 此功能可以告诉您。

<?php
/**
* Yesterday, Today, Tomorrow have special meanings in DateTime
*/
error_reporting(E_ALL);
echo '<pre>';
function ytt($string)
{
// NORMALIZE THE DATES
$then      = new DateTime($string);
$yesterday = new DateTime('Yesterday');
$today     = new DateTime('Today');
$tomorrow  = new DateTime('Tomorrow');
// CHOOSE A RETURN
if ($then->format('Y-m-d') == $yesterday->format('Y-m-d')) return 'Yesterday';
if ($then->format('Y-m-d') == $today->format('Y-m-d'))     return 'Today';
if ($then->format('Y-m-d') == $tomorrow->format('Y-m-d'))  return 'Tomorrow';
return NULL;
}
// USE CASE
$y = date('r');
echo PHP_EOL . ytt($y);
echo PHP_EOL . ytt("$y + 1 DAY");

Practical Application #4

实际应用#4

You decide you want to have a party on the fifth Friday of every month that has five Fridays.  When will you be celebrating?

您决定要在每个有五个星期五的每月的第五个星期五参加聚会。 你什么时候庆祝?

<?php
/**
* Finding months with five Fridays
*/
error_reporting(E_ALL);
echo '<pre>';
echo 'WE PARTY ON: ';
print_r(find_fifth_friday());
function find_fifth_friday($input='Today')
{
// GET VALUES FOR FIRST AND LAST OF THE YEAR
$date  = new DateTime($input);
$alpha = new DateTime($date->format('Y-1-1'));
$omega = new DateTime($date->format('Y-12-31'));
while ($alpha < $omega)
{
$first = new DateTime($alpha->format('Y-m-d') . ' first Friday');
$fifth = new DateTime($alpha->format('Y-m-d') . ' fifth Friday');
$month = $first->format('m');
$day_n = $fifth->format('Y-m-d D');
if (substr($day_n,5,2) == $month) $my_fridays[] = $day_n;
$alpha = $alpha->add(new DateInterval('P1M'));
}
return $my_fridays;
}

Practical Application #5

实际应用#5

You wonder if there could ever be a fifth Friday in that short month February.  The answer is "yes" and here is proof.

您想知道在那短短的二月中是否还会有第五个星期五。 答案是“是”,这就是证明。

<?php
/**
* Could there be five Fridays in February?
*/
error_reporting(E_ALL);
echo '<pre>';
function find_weekdays($date='Today', $day='Sunday')
{
$weekdays    = array();
$datething   = new DateTime($date . ' - 1 DAY');
$dateformat  = $datething->format('Y-m-d');
$weekdays[1] = new DateTime($dateformat . " first  $day");
$weekdays[2] = new DateTime($dateformat . " second $day");
$weekdays[3] = new DateTime($dateformat . " third  $day");
$weekdays[4] = new DateTime($dateformat . " fourth $day");
$weekdays[5] = new DateTime($dateformat . " fifth  $day");
if ( $weekdays[5]->format('m') != $weekdays[1]->format('m') ) { unset($weekdays[5]); }
return $weekdays;
}
function count_weekdays($date='Today', $day='Sunday')
{
$weekdays = find_weekdays($date, $day);
return count($weekdays);
}
// USE CASE
$month = 'February 2008';
$wkday = 'Friday';
$kount = count_weekdays($month, $wkday);
echo PHP_EOL . "$wkday OCCURS $kount TIMES IN $month";

Practical Application #6

实际应用#6

It would be nice to be able to print out a little calendar table... And if you wanted to send calendar information between applications, you might be interested in the hCalendar microformat.

能够打印出一个小的日历表将是一件很不错的事情……如果您想在应用程序之间发送日历信息,您可能会对hCalendar微格式感兴趣。

<?php
/**
* Printing a little calendar table
*/
error_reporting(E_ALL);
function little_calendar_table($date='Today')
{
$dateobj           = new DateTime($date);
$month             = new DateTime($dateobj->format('Y-m-01'));
$caption           = $month->format("F Y");
$first_day_number  = $month->format("w");
$last_day_of_month = $month->format("t");
$day_counter       = 0;
// USE HEREDOC NOTATION TO START THE HTML DOCUMENT
$html  = <<<EOT
<style type="text/css">
caption { text-align:left; }
th,td   { text-align:right; width:14%; padding-right:0.2em; }
th      { color:gray;    border:1px solid silver;    }
td      { color:dimgray; border:1px solid gainsboro; }
td.nul  {                border:1px solid white;     }
</style>
<table>
<caption>$caption</caption>
<tr class="cal">
<th abbr="Sunday">    S </th>
<th abbr="Monday">    M </th>
<th abbr="Tuesday">   T </th>
<th abbr="Wednesday"> W </th>
<th abbr="Thursday">  T </th>
<th abbr="Friday">    F </th>
<th abbr="Saturday">  S </th>
</tr>
EOT;
// THE FIRST ROW MAY HAVE DAYS THAT ARE NOT PART OF THIS MONTH
$html .= '<tr>';
while ($day_counter < $first_day_number)
{
$html .= '<td class="nul">&nbsp;</td>';
$day_counter++;
}
// THE DAYS OF THE MONTH
$mday = 1;
while ($mday <= $last_day_of_month)
{
// THE DAYS OF THE WEEK
while ($day_counter < 7)
{
$html .= "<td> $mday </td>";
$day_counter++;
$mday++;
if ($mday > $last_day_of_month) break 2;
}
$html .= '</tr>' . PHP_EOL;
$html .= '<tr>';
$day_counter = 0;
}
// THE LAST ROW MAY HAVE DAYS THAT ARE NOT PART OF THIS MONTH
while ($day_counter < 7)
{
$html .= '<td class="nul">&nbsp;</td>';
$day_counter++;
}
$html .= '</tr>'    . PHP_EOL;
$html .= '</table>' . PHP_EOL;
return $html;
}
echo little_calendar_table('February 2008');
echo little_calendar_table();

Practical Application #6a

实际应用#6a

The author of this question wanted a weekly calendar with "previous" and "next" links.  This function returns an array of nine elements giving previous, weekdays, and next.

这个问题的作者想要一个带有“上一个”和“下一个”链接的每周日历。 此函数返回一个由九个元素组成的数组,给出前一个,工作日和下一个。

<?php
/**
* A weekly calendar with Prev and Next links
*/
error_reporting(E_ALL);
echo '<pre>';
function weekly_calendar($input='TODAY')
{
$dateobj = new DateTime($input);
// WE WILL NEED TO ADD ONE DAY TO OUR OBJECTS
$intvl_p1d = new DateInterval('P1D');
// NORMALIZE TO THE ISO-8601 DATE WITHOUT TIME
$ymd = $dateobj->format('Y-m-d');
$day = $dateobj->format('D');
// THE WEEKLY CALENDAR WILL START ON SUNDAY AND END ON SATURDAY
if ($day == 'Sun')
{
$alphaobj = new DateTime($ymd);
$alpha    = $ymd;
}
else
{
$alphaobj = new DateTime($dateobj->format('Y-m-d') . ' LAST SUNDAY');
$alpha    = $alphaobj->format('Y-m-d');
}
$omegaobj = new DateTime($alphaobj->format('Y-m-d') . ' SATURDAY');
$omega    = $omegaobj->format('Y-m-d');
// THE PREV AND NEXT WEEKS WILL BE COMPUTED FROM THE CURRENT DAY
$prevobj = new DateTime($ymd . ' - 1 WEEK');
$prev    = $prevobj->format('Y-m-d');
$nextobj = new DateTime($ymd . ' + 1 WEEK');
$next    = $nextobj->format('Y-m-d');
// MAKE THE URLS
$prev_uri = $_SERVER['PHP_SELF'] . "?d=$prev";
$next_uri = $_SERVER['PHP_SELF'] . "?d=$next";
// MAKE THE LINK TEXTS
$prev_lnk = '<a href="' . $prev_uri . '">Prev</a>';
$next_lnk = '<a href="' . $next_uri . '">Next</a>';
// MAKE THE REPRESENTATION OF THE WEEK
$week['prev'] = $prev_lnk;
while ($alphaobj <= $omegaobj)
{
// A TEXT VERSION OF THE WEEKDAY
$day = $alphaobj->format('D');
$txt = $alphaobj->format('D m/d');
$ymd = $alphaobj->format('Y-m-d');
// URL AND LINK TEXT
$curr_uri = $_SERVER['PHP_SELF'] . "?d=$ymd";
$curr_lnk = '<a href="' . $curr_uri . '">' . $txt . '</a>';
$week[$day] = $curr_lnk;
// ON TO THE NEXT DAY
$alphaobj->add($intvl_p1d);
}
$week['next'] = $next_lnk;
return $week;
}
// SHOW THE REPRESENTATION OF THE WEEK
$get = !empty($_GET['d']) ? $_GET['d'] : NULL;
$thing = weekly_calendar($get);
print_r($thing);

Practical Application #7

实际应用#7

When you are working with human input to a computer program, it's good to know what works with the DateTime constructor method.  The script in this code snippet will tell you.

当您对计算机程序进行人工输入时,最好了解DateTime构造函数的工作方式。 此代码段中的脚本将告诉您。

<?php
/**
* Catching Exception when the input is unusable
*/
error_reporting(E_ALL);
$zoneobj = new DateTimeZone('America/Chicago');
// IF WE HAVE INPUT FROM THE URL QUERY STRING
if (!empty($_GET["s"]))
{
try
{
$dateobj = new DateTime($_GET['s'], $zoneobj);
}
catch(Exception $datex)
{
$mgsx = $datex->getMessage();
echo "<strong>HONK!</strong><br /> <u>{$_GET["s"]}</u> NOT USEFUL: $mgsx <br/><br/><br/><br/>";
goto FormCreation;
}
$textual = 'l dS \o\f F Y g:i:s A (T)';
$unix_timestamp = $dateobj->format('U');
$iso_datetime   = $dateobj->format(DateTime::ATOM);
$txt_datetime   = $dateobj->format($textual);
echo "<strong>BINGO</strong><br /> <strong><u>{$_GET["s"]}</u></strong> WORKS WITH PHP DateTime CLASS <br/>";
echo "THE INTEGER TIMESTAMP VALUE IS ";
echo number_format($unix_timestamp) . "<br />";
echo "THE ISO8601 DATETIME STRING IS $iso_datetime<br />";
echo "THE TEXTUAL DATE IS $txt_datetime<br />";
echo PHP_EOL;
}
// END OF PROCESSING INPUT - PUT UP THE FORM
FormCreation:
?>
<html>
<head>
<title>TEST THE PHP DateTime CLASS</title>
</head>
<body onload="document.f.s.focus()">
<form name="f" method="get">
<br />TO TEST A STRING FOR A VALID DATE/TIME, TYPE IT HERE:<input name="s" />
<input type="submit" value="GO" />
</form>

Practical Application #8

实际应用#8

What if you wanted to send an email message to your client at 7:00am every day?  But your clients may be all over the world!  You need a way to coordinate your server time with the time at the client's location.  This script shows how to work that out.

如果您想每天早上7:00发送电子邮件给客户该怎么办? 但是您的客户可能遍布世界各地! 您需要一种将服务器时间与客户端位置的时间进行协调的方法。 该脚本显示了如何解决。

<?php
/**
* Compute the difference between the Client time and the Server time
*/
error_reporting(E_ALL);
// THE TIME WE WANT AT THE CLIENT LOCATION
$client_timestring ='TODAY 0700';
$server_timezone = new DateTimeZone('America/Denver');
$server_datetime = new DateTime($client_timestring, $server_timezone);
$server_offset_seconds = $server_timezone->getOffset($server_datetime);
// WHEN THE FORM IS SUBMITTED
if (!empty($_POST))
{
// JAVASCRIPT TELLS US THE CLIENT TIME OFFSET FROM GMT / UTC
$client_offset_minutes = $_POST["date_O"];
$client_offset_seconds = $client_offset_minutes * 60;
// ADD CLIENT OFFSET TO SERVER OFFSET
$offset = $client_offset_seconds + $server_offset_seconds;
// WORKAROUND FOR NO NEGATIVE OFFSET IN THE DateInterval CONSTRUCTOR
$offset_abs = abs($offset);
$offset_intvl = new DateInterval('PT' . $offset_abs . 'S');
if ($offset < 0) $offset_intvl->invert = 1;
$server_datetime->add($offset_intvl);
$server_timestring = $server_datetime->format('l, F j, Y \a\t g:i a');
echo "<br/>ACCORDING TO THE VALUE FROM PHP DateTimeZone::getOffset()";
echo "<br/>SERVER IS LOCATED $server_offset_seconds SECONDS FROM UTC IN " . $server_timezone->getName();
echo "<br/>";
echo "<br/>ACCORDING TO THE VALUE FROM JS dateObject.getTimezoneOffset()";
echo "<br/>CLIENT IS LOCATED $client_offset_minutes MINUTES FROM UTC";
echo "<br/>";
echo "<br/>WHEN IT IS '$client_timestring' AT THE CLIENT, IT IS '$server_timestring' AT THE SERVER IN " . $server_timezone->getName();
}
// END OF PHP - USE HTML AND JS TO CREATE THE FORM
echo PHP_EOL;
?>
<form method="post">
<input name="date_O" id="dateTime_O" type="hidden" />
<input type="submit" value="CHECK CLIENT DATETIME" />
</form>
<!-- NOTE THIS WILL GIVE YOU THE VALUES AT PAGE-LOAD TIME, NOT AT SUBMIT TIME -->
<!-- MAN PAGE REF: http://www.w3schools.com/jsref/jsref_obj_date.asp -->
<script type="text/javascript">
var dateObject = new Date();
document.getElementById("dateTime_O").value = dateObject.getTimezoneOffset();
</script>

Practical Application #9

实际应用#9

We promise to ship our products within "n" business days.  This function can tell you the required shipment date.  Orders are deemed to have arrived at the close of business on the actual date of arrival.  Example: If you promise to ship within one business day and an order arrives at any time on Tuesday, you have all day Tuesday and until close of business on Wednesday before the shipment is required.  If the order arrives on Saturday or Sunday, it is deemed to have arrived on the following business day, probably Monday, thus shipment is not required until the close of business Tuesday.  This is probably good enough for commercial applications, but for Government work you might want to add a greater awareness of holidays into the function.

我们保证在“ n”个工作日内发货。 此功能可以告诉您所需的发货日期。 订单被视为在实际到达日期营业时间结束。 示例:如果您承诺在一个工作日内发货,而订单在星期二的任何时间到达,则您整周星期二全天营业,直到星期三关闭,然后才需要发货。 如果订单在周六或周日到达,则视为已在下一个工作日(可能是周一)到达,因此直到周二营业时间才需要装运。 这对于商业应用程序可能已经足够了,但是对于政府工作,您可能需要在功能中增加对假期的认识。

A technical note: While we usually choose the ISO-8601 format for an internal representation of a date, we make an exception here and choose the RFC2822 format, created by date('r').  It has an advantage in this case because we want to eliminate the weekend days from the computation and these are the only days that start with S.  RFC2822 dates look something like this, with the abbreviation of the weekday at the left: Wed, 10 Aug 2011 00:00:00 -0400.  The PHP substr() function makes it easy to find the days that start with S.

技术说明:虽然我们通常选择ISO-8601格式作为日期的内部表示形式,但是在这里我们例外,选择由date('r')创建的RFC2822格式。 在这种情况下它有一个优势,因为我们希望从计算中消除周末,而这是唯一以S开头的日子。 RFC2822日期看起来像这样,左边是工作日的缩写: 2011年8月10日,星期三00:00:00 -0400 。 PHP substr()函数使查找以S开头的日子变得容易。

<?php
/**
* Add "business days" to a given date, skipping weekends and holidays
*/
error_reporting(E_ALL);
echo '<pre>';
// A FUNCTION TO ADD BUSINESS DAYS TO A GIVEN DATE
function add_business_days($days=0, $date="TODAY", $format="c")
{
// CREATE YOUR ARRAY OF HOLIDAYS
$holidays = array();
$today    = new DateTime($date);
$january  = new DateTime($today->format('Y-01-1'));
$november = new DateTime($today->format('Y-11-1'));
$dateobj = new DateTime('Third Monday ' . $january->format('Y-01-0'));
$holidays['Dr_M_L_King']  = $dateobj->format(DateTime::RSS);
$dateobj = new DateTime($today->format('Y-07-04'));
$holidays['Independence'] = $dateobj->format(DateTime::RSS);
$dateobj = new DateTime('Fourth Thursday ' . $november->format('Y-11-0'));
$holidays['Thanksgiving'] = $dateobj->format(DateTime::RSS);
$dateobj = new DateTime($today->format('Y-12-25'));
$holidays['Christmas']    = $dateobj->format(DateTime::RSS);
$dateobj = new DateTime($today->format('Y-12-31') . '+ 1 DAY');
$holidays['NewYear']      = $dateobj->format(DateTime::RSS);
// ACTIVATE THIS TO SEE THE HOLIDAYS
// print_r($holidays);
// INTERPRET THE INPUTS INTO FUTURE DATES
$current = $today;
$weeks   = $days * 2 + 15;
$future  = new DateTime("$date $weeks DAYS");
// MAKE AN ARRAY OF FUTURE RSS DATES
$interval_p1d = new DateInterval('P1D');
while ($current < $future)
{
$dateobj = new DateTime($current->format('c'));
$arr[]   = $dateobj->format(DateTime::RSS);
$current->add($interval_p1d);
}
// REMOVE THE DAY FROM THE ARRAY IF IT IS A HOLIDAY OR WEEKEND DAY
foreach ($arr as $key => $date_string)
{
if (in_array($date_string, $holidays)) $arr[$key] = 'S';
if (substr($arr[$key],0,1) == 'S') unset($arr[$key]);
}
// RECAST THE ARRAY KEYS INTO OFFSETS FROM THE STARTING DATE
$arr = array_values($arr);
// RETURN THE FUTURE DATE ACCORDING TO THE REQUESTED FORMAT
$business_day = new DateTime($arr[$days]);
return $business_day->format($format);
}
var_dump( add_business_days() );
var_dump( add_business_days(1, 'December 23, 2015', 'r') );
var_dump( add_business_days(2, 'December 23, 2015', 'r') );

Practical Application #10

实际应用#10

We need an array of 7 weekdays, beginning on a specified date, as expressed in this question:

我们需要一个从指定日期开始的7个工作日的数组,如以下问题所示 :

<?php
/**
* Seven weekdays, beginning on an arbitrary weekday
*/
error_reporting(E_ALL);
echo '<pre>';
function weekdays($input)
{
$dateobj = new DateTime($input);
$day  = $dateobj->format('D');
$days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat','Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
return array_slice($days, array_search($day, $days), 7);
}
var_dump( weekdays('Tomorrow') );
var_dump( weekdays('Yesterday') );

After reviewing that question and answer, we might want a more generalized solution.  Perhaps we do not only want those abbreviations; we might want the 7 weekdays returned in a different format.  This function preserves the functionality of the original answer and generalizes the solution to allow for different return formats.  We use the DateTime::add() method with the DateInterval object to increment the days

在查看了该问题和答案之后,我们可能需要一个更通用的解决方案。 也许我们不仅要这些缩写,还需要这些缩写。 我们可能希望以其他格式返回7个工作日。 该功能保留了原始答案的功能,并泛化了解决方案以允许使用不同的返回格式。 我们将DateTime :: add()方法与DateInterval对象一起使用来增加天数

<?php
/**
* Seven weekdays, in any date format
*/
error_reporting(E_ALL);
echo '<pre>';
function weekdays($input, $format='D')
{
$interval_p1d = new DateInterval('P1D');
$dateobj = new DateTime($input);
$datemax = new DateTime($dateobj->format('c') . ' + 6 DAYS');
while ($dateobj <= $datemax)
{
$dates[] = $dateobj->format($format);
$dateobj->add($interval_p1d);
}
return $dates;
}
var_dump( weekdays('Tomorrow') );
var_dump( weekdays('Yesterday') );

Practical Application #11

实际应用#11

Given the beginning date of a Fiscal Year, what are the beginning dates of the Fiscal Quarters?  Since each quarter is three months, we can easily get the dates for the quarters.  This application illustrates one of the strange behaviors of the DateTime class.  If you call the add() method, instead of receiving a new object as a return value, you mutate the object.  Therefore it is necessary to clone() the object before calling add(), if you want to keep a copy of the original object.

给定会计年度的开始日期,会计季度的开始日期是什么? 由于每个季度为三个月,因此我们可以轻松获取这些季度的日期。 此应用程序说明了DateTime类的奇怪行为之一。 如果调用add()方法,则对对象进行突变,而不是接收新的对象作为返回值。 因此,如果要保留原始对象的副本,则有必要在调用add()之前克隆对象。

<?php
/**
* Fiscal Years
*
* Note the use of clone() because the add() method mutates the DateTime object
*/
error_reporting(E_ALL);
echo '<pre>';
// SOME TEST DATES FOR THE FISCAL YEARS
$fys = array
( 'CALENDAR' => 'January 1'
, 'ACADEMIC' => 'July 1'
, 'FEDERAL'  => 'October 1'
)
;
// COMPUTE THE QUARTERS
$interval_p3m = new DateInterval('P3M');
$interval_p6m = new DateInterval('P6M');
$interval_p9m = new DateInterval('P9M');
foreach ($fys as $key => $start)
{
$dateobj = new DateTime($start);
$res['q1'] = $dateobj->format(DateTime::ATOM);
$datework = clone($dateobj); // MUST MAKE A CLONE BECAUSE add() MUTATES THE OBJECT
$datework->add($interval_p3m);
$res['q2'] = $datework->format(DateTime::ATOM);
$datework = clone($dateobj);
$datework->add($interval_p6m);
$res['q3'] = $datework->format(DateTime::ATOM);
$datework = clone($dateobj);
$datework->add($interval_p9m);
$res['q4'] = $datework->format(DateTime::ATOM);
// SAVE THESE ELEMENTS
$new[$key] = $res;
}
print_r($new);

Practical Application #12

实际应用#12

What are the essential elements of a resource scheduling calendar?  Unlike an appointment calendar which assumes the general availability of all calendar dates and times, a resource calendar must enumerate the resources and keep track of when they are available and when they are scheduled, and therefore unavailable.  The important moving parts are the resource name and the period of unavailability as given by the beginning DATETIME and the ending DATETIME.  Armed with this information we can write SQL queries that will allow us to schedule the resources and detect potential conflicts.  A starting point for the resource scheduling calendar might be something like this.

资源调度日历的基本要素是什么? 与假定所有日历日期和时间都可以普遍使用的约会日历不同, 资源日历必须枚举资源并跟踪何时可用,何时安排以及因此不可用。 重要的移动部分是资源名称和不可用的时间段,由开始的DATETIME和结束的DATETIME给出。 有了这些信息,我们就可以编写SQL查询,从而使我们能够调度资源并检测潜在的冲突。 资源调度日历的起点可能是这样的。

<?php
/**
* Demonstrate the basics of a MySQL-based resource scheduling calendar
*/
error_reporting(E_ALL);
echo '<pre>';
// DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "??";
$db_user = "??";
$db_word = "??";
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);
// DID THE CONNECT/SELECT WORK OR FAIL?
if ($mysqli->connect_errno)
{
trigger_error("CONNECT FAIL: $mysqli->connect_errno $mysqli->connect_error", E_USER_ERROR);
}
// CREATING A TABLE FOR OUR TEST DATA
$sql
=
"
CREATE TEMPORARY TABLE my_calendar
( id    INT         NOT NULL AUTO_INCREMENT PRIMARY KEY
, rname VARCHAR(24) NOT NULL DEFAULT ''                    # RESOURCE NAME
, alpha DATETIME    NOT NULL DEFAULT '0000-00-00 00:00:00' # BEGINNING OF COMMITMENT
, omega DATETIME    NOT NULL DEFAULT '0000-00-00 00:00:00' # END OF COMMITMENT
)
"
;
// CREATE THE TABLE OR LOG AND SHOW THE ERROR
if (!$res = $mysqli->query($sql))
{
$err
= 'QUERY FAILURE:'
. ' ERRNO: '
. $mysqli->errno
. ' ERROR: '
. $mysqli->error
. ' QUERY: '
. $sql
;
trigger_error($err, E_USER_ERROR);
}
// PRE-LOAD SOME SCHEDULED RESOURCES INTO THE CALENDAR
$mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( 'One', '2013-06-20T08:00:00', '2013-06-20T09:59:59' )");
$mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( 'Two', '2013-06-20T08:00:00', '2013-06-20T09:59:59' )");
$mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( 'Two', '2013-06-20T11:00:00', '2013-06-20T12:59:59' )");
// SHOW THE CALENDAR
$res = $mysqli->query("SELECT * FROM my_calendar");
while ($row = $res->fetch_object()) { print_r($row); }
// SCHEDULE A RESOURCE FROM 1:00pm TO 3:00pm
$rname = 'One';
$dateobj = new DateTime('June 20, 2013 1:00pm');
$alpha = $dateobj->format(DateTime::ATOM);
$dateobj = new DateTime('June 20, 2013 3:00pm - 1 SECOND');
$omega = $dateobj->format(DateTime::ATOM);
$res = $mysqli->query("LOCK TABLES my_calendar");
$res = $mysqli->query("SELECT id FROM my_calendar WHERE rname = '$rname' AND ( (alpha BETWEEN '$alpha' AND '$omega') OR (omega BETWEEN '$alpha' AND '$omega') )  LIMIT 1");
$num = $res->num_rows;
if ($num == 0)
{
$res = $mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( '$rname', '$alpha', '$omega' )");
echo "SCHEDULED $rname FROM $alpha TO $omega" . PHP_EOL;
}
else
{
echo "CONFLICT! $rname FROM $alpha TO $omega" . PHP_EOL;
}
$res = $mysqli->query("UNLOCK TABLES my_calendar");
// TRY TO SCHEDULE THE SAME RESOURCE FROM 2:00pm TO 4:00pm
$rname = 'One';
$dateobj = new DateTime('June 20, 2013 2:00pm');
$alpha = $dateobj->format(DateTime::ATOM);
$dateobj = new DateTime('June 20, 2013 4:00pm - 1 SECOND');
$omega = $dateobj->format(DateTime::ATOM);
$res = $mysqli->query("LOCK TABLES my_calendar");
$res = $mysqli->query("SELECT id FROM my_calendar WHERE rname = '$rname' AND ( (alpha BETWEEN '$alpha' AND '$omega') OR (omega BETWEEN '$alpha' AND '$omega') )  LIMIT 1");
$num = $res->num_rows;
if ($num == 0)
{
$mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( '$rname', '$alpha', '$omega' )");
echo "SCHEDULED $rname FROM $alpha TO $omega" . PHP_EOL;
}
else
{
echo "CONFLICT! $rname FROM $alpha TO $omega" . PHP_EOL;
}
$res = $mysqli->query("UNLOCK TABLES my_calendar");
// TRY TO SCHEDULE A DIFFERENT RESOURCE FROM 2:00pm TO 4:00pm
$rname = 'Two';
$dateobj = new DateTime('June 20, 2013 2:00pm');
$alpha = $dateobj->format(DateTime::ATOM);
$dateobj = new DateTime('June 20, 2013 4:00pm - 1 SECOND');
$omega = $dateobj->format(DateTime::ATOM);
$res = $mysqli->query("LOCK TABLES my_calendar");
$res = $mysqli->query("SELECT id FROM my_calendar WHERE rname = '$rname' AND ( (alpha BETWEEN '$alpha' AND '$omega') OR (omega BETWEEN '$alpha' AND '$omega') )  LIMIT 1");
$num = $res->num_rows;
if ($num == 0)
{
$mysqli->query("INSERT INTO my_calendar (rname, alpha, omega) VALUES ( '$rname', '$alpha', '$omega' )");
echo "SCHEDULED $rname FROM $alpha TO $omega" . PHP_EOL;
}
else
{
echo "CONFLICT! $rname FROM $alpha TO $omega" . PHP_EOL;
while ($row = $res->fetch_object()) { var_dump($row); }
}
$res = $mysqli->query("UNLOCK TABLES my_calendar");
// SHOW THE RESULTING CALENDAR
$res = $mysqli->query("SELECT * FROM my_calendar");
while ($row = $res->fetch_object()) { print_r($row); }

Practical Application #13

实际应用#13

What time will the sun rise or set?  PHP can tell you this if you set your location and timezone correctly.  However your location in the default PHP installation is probably wrong unless you're in Israel near the PHP developers at Zend.  There are two initialization settings for your location: latitude and longitude, and conveniently they are settable in your PHP script.  They can also be set in the function calls to date_sunrise() and date_sunset().  Interestingly, they are independent of your timezone settings, and if you don't have all these settings in consonance, you may get incorrect output from the functions.  The code snippet shows how to determine the time of sunrise and sunset.  The user-contributed notes for date_sunrise() have some interesting and useful observations, too.

太阳什么时候升起或落山? 如果您正确设置了位置和时区,PHP可以告诉您。 但是,除非您在以色列的ZendPHP开发人员附近,否则您在默认PHP安装中的位置可能是错误的。 您所在的位置有两个初始化设置:纬度和经度,可以方便地在您PHP脚本中设置它们。 也可以在对date_sunrise()和date_sunset()的函数调用中设置它们。 有趣的是,它们独立于您的时区设置,并且如果您不将所有这些设置协调使用,则可能会从函数中获得错误的输出。 该代码段显示了如何确定日出和日落的时间。 用户为date_sunrise()提供的注释也有一些有趣且有用的观察结果。

<?php
/**
* Getting the time of sunrise
*
* There is no date_default_longitude_set() or date_default_longitude_get()
* These values are settable PHP_INI_ALL and gettable with ini_get()
* If you're using the default values and you're not located in Israel...
* your computations will probably come out wrong.
*
* Incorrect output if your location settings do not match your timezone.
*/
error_reporting(E_ALL);
echo '<pre>';
// SET LOCATION VALUES TO CHICAGO
ini_set('date.default_latitude',    '41.850687');
ini_set('date.default_longitude',  '-87.650046');
$zone = new DateTimeZone('America/Chicago');
$date = new DateTime(NULL, $zone);
// GET UNIX TIMESTAMP
$unix = date_sunrise
( $date->getTimestamp()
, SUNFUNCS_RET_TIMESTAMP
, ini_get('date.default_latitude')
, ini_get('date.default_longitude')
, ini_get("date.sunrise_zenith")
, $date->getOffset() / 3600 //--> NOTE THIS IS IN HOURS, NOT SECONDS
)
;
// SHOW ANSWER IN LOCAL TIME
$date = new DateTime("@$unix");
$date->setTimeZone($zone);
$sun = $date->format('g:ia (T)');
$day = $date->format('D, M jS Y');
$lat = ini_get('date.default_latitude');
$lon = ini_get('date.default_longitude');
$dtz = $zone->getName();
echo PHP_EOL . "LOCATION: $lat, $lon ($dtz) OBSERVES SUNRISE AT: $sun ON $day";
// CHANGE VALUES TO LOS ANGELES
ini_set('date.default_latitude',    '34.071103');
ini_set('date.default_longitude', '-118.440150');
$zone = new DateTimeZone('America/Los_Angeles');
$date = new DateTime(NULL, $zone);
// GET UNIX TIMESTAMP
$unix = date_sunrise
( $date->getTimestamp()
, SUNFUNCS_RET_TIMESTAMP
, ini_get('date.default_latitude')
, ini_get('date.default_longitude')
, ini_get("date.sunrise_zenith")
, $date->getOffset() / 3600 //--> NOTE THIS IS IN HOURS, NOT SECONDS
)
;
// SHOW ANSWER IN LOCAL TIME
$date = new DateTime("@$unix");
$date->setTimeZone($zone);
$sun = $date->format('g:ia (T)');
$day = $date->format('D, M jS Y');
$lat = ini_get('date.default_latitude');
$lon = ini_get('date.default_longitude');
$dtz = $zone->getName();
echo PHP_EOL . "LOCATION: $lat, $lon ($dtz) OBSERVES SUNRISE AT: $sun ON $day";
// CHANGE VALUES TO WRONG VALUES FOR WASHINGTON, DC
ini_set('date.default_latitude',    '38.898748');
ini_set('date.default_longitude',  '-77.037684');
$zone = new DateTimeZone('America/Los_Angeles'); //--> THIS IS INTENTIONALLY WRONG
$date = new DateTime(NULL, $zone);
// GET UNIX TIMESTAMP
$unix = date_sunrise
( $date->getTimestamp()
, SUNFUNCS_RET_TIMESTAMP
, ini_get('date.default_latitude')
, ini_get('date.default_longitude')
, ini_get("date.sunrise_zenith")
, $date->getOffset() / 3600 //--> NOTE THIS IS IN HOURS, NOT SECONDS
)
;
// SHOW WRONG ANSWER IN LOCAL TIME
$date = new DateTime("@$unix");
$date->setTimeZone($zone);
$sun = $date->format('g:ia (T)');
$day = $date->format('D, M jS Y');
$lat = ini_get('date.default_latitude');
$lon = ini_get('date.default_longitude');
$dtz = $zone->getName();
echo PHP_EOL . "LOCATION: $lat, $lon ($dtz) OBSERVES SUNRISE AT: $sun ON $day --> NOT!!";
// CHANGE VALUES TO CORRECT VALUES FOR WASHINGTON, DC
ini_set('date.default_latitude',    '38.898748');
ini_set('date.default_longitude',  '-77.037684');
$zone = new DateTimeZone('America/New_York'); //--> THIS HAS BEEN CORRECTED
$date = new DateTime(NULL, $zone);
// GET UNIX TIMESTAMP
$unix = date_sunrise
( $date->getTimestamp()
, SUNFUNCS_RET_TIMESTAMP
, ini_get('date.default_latitude')
, ini_get('date.default_longitude')
, ini_get("date.sunrise_zenith")
, $date->getOffset() / 3600 //--> NOTE THIS IS IN HOURS, NOT SECONDS
)
;
// SHOW WRONG ANSWER IN LOCAL TIME
$date = new DateTime("@$unix");
$date->setTimeZone($zone);
$sun = $date->format('g:ia (T)');
$day = $date->format('D, M jS Y');
$lat = ini_get('date.default_latitude');
$lon = ini_get('date.default_longitude');
$dtz = $zone->getName();
echo PHP_EOL . "LOCATION: $lat, $lon ($dtz) OBSERVES SUNRISE AT: $sun ON $day";

Practical Application #14

实际应用#14

When it is some given time in one time zone, what time is it in another time zone?  This function can tell you.  It is much easier to use PHP's built-in time computations than trying to write your own because PHP will automatically account for leap years and daylight savings time.

如果在一个时区中有给定时间,那么在另一个时区中是什么时间? 此功能可以告诉您。 使用PHP的内置时间计算比尝试编写自己的时间要容易得多,因为PHP会自动考虑leap年和夏时制。

If you need a list of the timezone identifiers, PHP can give you that: print_r( timezone_identifiers_list() );

如果您需要时区标识符的列表,PHP可以为您提供:print_r( timezone_identifiers_list() );

<?php
/**
* Compute the clock-setting difference between two timezones
*/
error_reporting(E_ALL);
echo '<pre>';
function timezone_difference($tz1, $tz2, $date='NOW')
{
$now = new DateTime($date);
$ond = $now->format(DateTime::ATOM);
$sig = NULL;
// THE RETURN ARRAY HAS THESE FIELDS
$ret = array
( 'from' => $tz1
, 'is'   => 'same as'
, 'to'   => $tz2
, 'secs' => '0'
, 'hhmm' => '00:00'
, 'asof' => $ond
)
;
// GET TIMEZONE SETTINGS
$zone1 = new DateTimeZone($tz1);
$zone2 = new DateTimeZone($tz2);
$zz1 = $zone1->getOffset($now);
$zz2 = $zone2->getOffset($now);
// COMPUTE THE CLOCK DIFFERENCE
$dif = $zz2 - $zz1;
if ($dif < 0) $sig = '-';
if ($dif > 0) $sig = '+';
if ($sig == '-') $ret['is'] = 'ahead of';
if ($sig == '+') $ret['is'] = 'behind';
$dif = abs($dif);
$dat = new DateTime("TODAY + $dif SECONDS");
$fmt = $dat->format('H:i');
$ret['secs'] = $sig . $dif;
$ret['hhmm'] = $sig . $fmt;
return $ret;
}
// OBSERVE THE FUNCTION IN ACTION
echo '<pre>';
$tz1 = 'America/Chicago';
$tz2 = 'America/St_Johns';
$tzd = timezone_difference($tz1, $tz2);
var_dump($tzd);

Practical Application #15

实际应用#15

Given a country code, what are its time zones?  Given a time zone, what country is in play?  This application can answer that question.

给定国家代码 ,其时区是什么? 给定一个时区,哪个国家在起作用? 该应用程序可以回答该问题。

<?php
/**
* Get the TimeZone Identifiers
*/
error_reporting(E_ALL);
echo '<pre>';
// CLASSES TO HOLD TIMEZONE-TO-ISO_3166 DATA
Class CountryTimeZone
{
public function __construct($timezone, $iso_3166)
{
$this->timezone = $timezone;
$this->country  = $iso_3166;
}
}
Class CountryTimeZones
{
public $timezones = [];
public $countries = [];
public function add($timezone, $iso_3166)
{
$this->timezones[$timezone] = new CountryTimeZone($timezone, $iso_3166);
$this->countries[$iso_3166][] = $timezone;
}
public function getCountry($timezone)
{
return array_key_exists($timezone, $this->timezones)
? $this->timezones[$timezone]->country
: FALSE
;
}
public function getTimeZones($iso_3166)
{
return array_key_exists($iso_3166, $this->countries)
? $this->countries[$iso_3166]
: FALSE
;
}
}
// COLLECT THE DATA SET
$ctz = new CountryTimeZones;
$arr = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
foreach ($arr as $tz_name)
{
$obj = new DateTimeZone($tz_name);
$sub = $obj->getLocation();
$iso = $sub['country_code'];
$ctz->add($tz_name, $iso);
}
// DEMONSTRATE THE CLASS
echo '<pre>';
var_dump($ctz->getCountry('America/New_York'));
var_dump($ctz->getCountry('America/Panama'));
var_dump($ctz->getCountry('America/Los_Angeles'));
var_dump($ctz->getCountry('UTC'));
var_dump($ctz->getCountry('wtf'));
var_dump($ctz->getTimeZones('PA'));
var_dump($ctz->getTimeZones('CN'));
var_dump($ctz->getTimeZones('US'));
var_dump($ctz->getTimeZones('??'));
// SAVE THE DATA SET
var_export($ctz);

Practical Application #16

实际应用#16

How can I create a range of dates (inspired by this question)

如何创建日期范围 (受此问题启发)

<?php
/**
* Get a range of dates
*/
error_reporting(E_ALL);
echo '<pre>';
// SET THE START AND END DATES
$alpha = 'July 15, 2015';
$omega = 'Aug  14, 2015';
// COMPUTE AND DISPLAY THE RANGE OF DATES
$range = date_range($alpha, $omega);
print_r($range);
function date_range($a, $z, $format='Y-m-d')
{
$return = [];
// AN INTERVAL SETTING
$interval_p1d = new DateInterval('P1D');
// NORMALIZE THE DATES
$alpha   = new DateTime($a);
$omega   = new DateTime($z);
// CREATE THE RANGE
while ($alpha <= $omega)
{
$return[] = $alpha->format($format);
$alpha->add($interval_p1d);
}
return $return;
}

Practical Application #17

实际应用#17

You might like the jQuery datepicker.  This is not a PHP issue, but it's a popular question, so I'll just leave the example here.

您可能喜欢jQuery datepicker 。 这不是PHP的问题,而是一个受欢迎的问题,因此我将在此处保留示例。

<?php
/**
* Demonstrate the jQuery Date Picker
*/
error_reporting(E_ALL);
echo '<pre>';
// IF THE DATE WAS SUBMITTED, USE IT IN PHP
if (!empty($_POST['chosen_date']))
{
$dateobj = FALSE;
try
{
$dateobj = new DateTime($_POST['chosen_date']);
}
catch(Exception $e)
{
error_log($e);
}
if ($dateobj)
{
$chosen_date = $dateobj->format(DateTime::ATOM);
$chosen_date = $dateobj->format('Y-m-d');
echo PHP_EOL . "You chose date: <b>$chosen_date</b>";
}
}
// CREATE THE HTML USING HEREDOC NOTATION ADAPTED FROM http://jqueryui.com/datepicker/
$htm = <<<EOD
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Datepicker - Default functionality</title>
<script>
$(function() {
$("#datepicker").datepicker();
});
</script>
</head>
<body>
<form method="post">
<p>Date: <input name="chosen_date" type="text" id="datepicker" /></p>
<input type="submit" />
</form>
</body>
</html>
EOD;
echo $htm;

Practical Application #18

实际应用#18

How long does it take your client to fill out a form?  A bit of jQuery can identify the load time and the submit time.  The difference between these two times gives us the answer.

您的客户需要多长时间填写一份表格? 一点点的jQuery可以识别加载时间和提交时间。 这两次之间的差异为我们提供了答案。

<?php
/**
* Find out how long it takes your client to submit a form
*
* JavaScript date().toString() returns something like this:
*    Sat Apr 09 2016 07:33:27 GMT-0400 (Eastern Daylight Time)
* PHP needs something like this (33 characters):
*    Sat Apr 09 2016 07:33:27 GMT-0400
*/
error_reporting(E_ALL);
if (!empty($_POST))
{
$alpha = new DateTime( substr($_POST['alpha'],0,33) );
$omega = new DateTime( substr($_POST['omega'],0,33) );
$lapse = $alpha->diff($omega);
$timex = $lapse->format('%I:%S');
echo PHP_EOL . "It took $timex (minutes:seconds) to submit this form";
// ACTIVATE THIS TO SHOW THE REQUEST
// var_dump($_POST);
}
// CREATE OUR WEB PAGE IN HTML5 FORMAT
$htm = <<<HTML5
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
/* STYLE SHEET HERE */
</style>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function(){
var tload = new Date().toString();
var alpha = $("<input>").attr("type", "hidden").attr("name", "alpha").val(tload);
$("#myForm").append($(alpha));
$("#myForm").submit(function(e){
var tsubm = new Date().toString();
var omega = $("<input>").attr("type", "hidden").attr("name", "omega").val(tsubm);
$("#myForm").append($(omega));
});
});
</script>
<title>HTML5 Page With jQuery in UTF-8 Encoding</title>
</head>
<body>
<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>
<form id="myForm" method="post">
<input type="submit" />
</form>
</body>
</html>
HTML5;
// RENDER THE WEB PAGE
echo $htm;

Procedural DATETIME Notation

程序DATETIME表示法

Here is a link to the original procedural article about date/time.

这是有关日期/时间的原始程序文章的链接。

http://www.experts-exchange.com/articles/201/Handling-Date-and-Time-in-PHP-and-MySQL.html

http://www.experts-exchange.com/articles/201/Handling-Date-and-Time-in-PHP-and-MySQL.html

Creativity and Routine

创造力与常规

Like most things in computer programming, there are several ways to achieve equivalent results.  This article has shown some tried-and-true ways to use PHP's powerful date / time processing functions.  The methods shown here will help you get quick and accurate answers to many common questions, all with a minimum risk of introducing bugs into the code.

像计算机编程中的大多数事物一样,有几种方法可以达到相同的结果。 本文展示了一些使用PHP强大的日期/时间处理功能的可靠方法。 此处显示的方法将帮助您快速准确地回答许多常见问题,所有这些将代码中引入错误的风险降到最低。

References and Further Reading 

参考资料和进一步阅读

http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

http://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html

http://php.net/manual/en/class.datetime.php

http://php.net/manual/zh/class.datetime.php

http://php.net/manual/en/class.datetime.php#120264

http://php.net/manual/zh/class.datetime.php#120264

http://php.net/manual/en/class.datetime.php#datetime.constants.types

http://php.net/manual/zh-CN/class.datetime.php#datetime.constants.types

http://php.net/manual/en/class.datetimezone.php

http://php.net/manual/zh/class.datetimezone.php

http://php.net/manual/en/dateinterval.construct.php

http://php.net/manual/en/dateinterval.construct.php

http://php.net/manual/en/dateinterval.format.php

http://php.net/manual/en/dateinterval.format.php

http://php.net/manual/en/datetime.add.php

http://php.net/manual/en/datetime.add.php

http://php.net/manual/en/datetime.construct.php

http://php.net/manual/en/datetime.construct.php

http://php.net/manual/en/datetime.diff.php#113283

http://php.net/manual/en/datetime.diff.php#113283

http://php.net/manual/en/datetime.diff.php#114881

http://php.net/manual/en/datetime.diff.php#114881

http://php.net/manual/en/datetime.format.php

http://php.net/manual/en/datetime.format.php

http://php.net/manual/en/datetime.formats.relative.php

http://php.net/manual/en/datetime.formats.relative.php

http://php.net/manual/en/datetime.sub.php#114780

http://php.net/manual/en/datetime.sub.php#114780

http://php.net/manual/en/datetimezone.construct.php

http://php.net/manual/en/datetimezone.construct.php

http://php.net/manual/en/datetimezone.gettransitions.php

http://php.net/manual/en/datetimezone.gettransitions.php

http://php.net/manual/en/function.date.php

http://php.net/manual/zh/function.date.php

http://php.net/manual/en/function.date-default-timezone-set.php

http://php.net/manual/en/function.date-default-timezone-set.php

http://php.net/manual/en/ref.calendar.php

http://php.net/manual/zh/ref.calendar.php

http://php.net/manual/en/refs.calendar.php

http://php.net/manual/en/refs.calendar.php

http://php.net/manual/en/timezones.america.php#85815

http://php.net/manual/en/timezones.america.php#85815

http://php.net/manual/en/timezones.php

http://php.net/manual/en/timezones.php

http://php.net/manual/en/function.date.php

http://php.net/manual/zh/function.date.php

http://www.timeanddate.com/time/change/usa/new-york?year=2014

http://www.timeanddate.com/time/change/usa/new-york?year=2014

http://www.w3schools.com/jsref/jsref_obj_date.asp

http://www.w3schools.com/jsref/jsref_obj_date.asp

https://en.wikipedia.org/wiki/ISO_8601#Durations

https://zh.wikipedia.org/wiki/ISO_8601#Durations

Please give us your feedback!

请给我们您的反馈意见!

If you found this article helpful, please click the "thumb's up" button below. Doing so lets the E-E community know what is valuable for E-E members and helps provide direction for future articles.  If you have questions or comments, please add them.  Thanks!

如果您发现本文有帮助,请单击下面的“竖起大拇指”按钮。 这样做可以使EE社区了解对EE成员有价值的内容,并为将来的文章提供指导。 如果您有任何问题或意见,请添加。 谢谢!

翻译自: https://www.experts-exchange.com/articles/20920/Handling-Time-and-Date-in-PHP-and-MySQL-OOP-Version.html

oop-klass

oop-klass_在PHP和MySQL中处理时间和日期-OOP版本相关推荐

  1. mysql中Long类型日期比较大小

    项目里遇到一个功能,需要查出表中,昨天一天某个人的考勤记录. 问题本不复杂,但是表中用户打卡时间为char类型的时间戳(毫秒).这样一来比较时间范围就麻烦了许多. 还好,网上以为有脾气的博主写的文章帮 ...

  2. MySQL 中的常用日期函数

    MySQL 中的常用日期函数: 函数 描述 NOW() 返回当前的日期和时间 CURDATE() 返回当前的日期 CURTIME() 返回当前的时间 DATE() 提取日期或日期/时间表达式的日期部分 ...

  3. mysql 日期详解,MySQL中如何操作日期的详解

    日期是数据库存储很重要的一部分,下面总结下在MySQL中常用的日期操作 1.select curDate(); #获取当前日期select curTime(); #获取当前时间select now() ...

  4. mysql创建带日期的表_在MySQL中创建带有日期的临时表

    要创建带有日期的临时表,请在MySQL中使用CREATE TEMPORARY TABLE.以下是语法- 语法create temporary table yourTableName( yourColu ...

  5. MySQL 中常用的日期相关函数

    目录 第一部分:时间差函数 timestampdiff.datediff.timediff 一.时间差函数:timestampdiff 二.时间差函数:datediff 三.时间差函数:timedif ...

  6. mysql中的dateDayOfYear_MySQL日期函数

    MySQL日期函数 1:获取系统当前日期和时间 NOW(),LOCALTIME(),LOCALTIMESTAMP(),CURDATE(),CURRENT_DATE(),CURRENT_TIME(),C ...

  7. MySQL中实现连续日期内数据统计,缺省天数0补全

    某一日,需要查询订单表中一个月每天的金额数 查询出数据如下: array(14) {[0] => array(2) {["money"] => string(7) &q ...

  8. mysql query日期_如何获取mysql中两个日期之间的日期列表select query

    尝试: select * from (select adddate('1970-01-01',t4.i*10000 + t3.i*1000 + t2.i*100 + t1.i*10 + t0.i) s ...

  9. mysql 指定日期条件求和_如何在mysql中按每个日期对字段进行求和-问答-阿里云开发者社区-阿里云...

    我正在尝试根据案件的日期查询QUERY总计字段罚款,何时但不成功,有解决方案吗? 我的桌子 NIP NAMA TANGGAL JENIS_KEHADIRAN DENDA 10016 Novi Iraw ...

  10. mysql中sql语句日期比较,mysql sql语句中 日期函数的使用

    select now();  获取当前时间 2018-08-30 09:44:31函数 select CURDATE(); 获取当前日期  2018-08-30orm select  CURTIME( ...

最新文章

  1. python 实现桶排序
  2. 如何自定义制表符到空格的转换因子?
  3. i7跑服务器系统,i7主机做服务器
  4. python用import xlwt出现红字_如何用python处理excel
  5. 《中国人工智能学会通讯》——12.33 众包知识库补全方法概览
  6. 中国移动携手华为完成5G话音的全部功能测试
  7. python场景识别_python 场景
  8. bootstrap栅栏系统 解决当弹窗口变小的时候变成1列问题
  9. 【UOJ #351】新年的叶子(树的直径,期望)
  10. 棋盘中正方形,长方形个数
  11. 【程序员如何买基金 一】基金的优势及分类
  12. 东软始业教育结业考试
  13. 语音端点matlab,语音端点检测及其在Matlab中的实现
  14. 微信企业号回调 java_微信公众平台企业号回调模式的URL验证——Java
  15. React实现(Web端)网易云音乐项目(六),错过了真的可惜呀
  16. ZUCC_计算机网络实验_实验03 交换机基本配置
  17. Linux 下实现虚拟专用网(PPTP)
  18. 夜神模拟器 版本下载
  19. 公司不会告诉你的潜规则
  20. C#调用12306API做余票查询

热门文章

  1. VB中On Error Resume Next 什么意思,一般在什么情况下使用
  2. [基础服务] 常用邮箱服务地址
  3. 捷多邦6层板阻抗及压合设计
  4. 四成单身、平均年薪19万、最爱买房,原来真实的程序员是这个样子的…...
  5. Android底层网络防火墙,Android系统中实现网络防火墙的方法
  6. 9张图揭秘:优秀的数据分析项目,这样做!
  7. 短信网关协议(cmpp、sgip、smgp、smpp)长短信开发要点
  8. 不小心删除JDK文件夹,无法重新安装该怎么办*
  9. 文件关联后即时生效代码
  10. Beta周王者荣耀交流协会第一次Scrum会议