因此,首先您需要问自己最终要寻找什么。将所有时间戳保持为标准 UTC 格式确实符合您的最大利益,如果您要存储字符串,请使用 ISO8601 标准。好玩:XKCD on ISO8601
在您将日期显示给用户之前,仅以一种格式(UTC 时区/ISO8601 格式,如果是字符串)传递日期将使您的生活变得更加轻松。
只有这样,您才应该像用户期望的那样格式化日期以表示本地时间,并且您应该编写一个日期格式化程序以确保始终一致地完成此转换。
在客户端,将日期转换为这种标准化格式,即在用户捕获日期时并将其发送到服务器之前(实际上与上述格式化程序相反)。
除此之外的所有服务器日期逻辑通常都会计算时差,而无需担心时区转换。 /咆哮
现在更详细地讨论您的问题以及您遇到问题的原因。
根据moment.js docs:
默认情况下,moment 解析并显示为当地时间。
所以当你这样做时:
moment.unix();
知道这是相对于当地时间的。同样,unix 时间是相对于一个奇异时间点的秒数,一个纪元恰好是 1970 年 1 月 1 日 00:00:00(当放入 UTC 时区时)。
为了让这个成功。使用您的 PHP 日期函数并输入“0”作为 unix 时间戳。你得到了什么?这将取决于您在 PHP 环境中设置的默认时区。
对于我来说,我使用的在线 PHP 沙箱的输出:
<?php echo date('Y-m-d H:i:s', 0); ?>
// 1969-12-31 16:00:00
哦哦。这里发生了什么?那是在纪元之前,我肯定只是放了一个大胖子零。
因此,这就是保持日期格式全面一致的重要性。它会让你的生活更轻松。
以下是您需要执行的操作以及原因:
1. 获取当地日期的午夜。这是您需要在时刻变量中捕获的第一条信息,因为它代表了您感兴趣的内容。一旦有了这些信息,剩下的就是了解如何按照您的意愿格式化该日期。
var lastLocalMidnight = moment().startOf('day')
var lastUTCMidnight = moment.utc().startOf('day')
为了争论和您的理解,我包含了另一个变量,它在“午夜”之前捕获并将“现在”转换为 UTC 时区。
那么这里有什么不同呢?进一步阅读有关 UTC 的 moment.js 文档:
使用 moment.utc() 创建的任何时刻都将处于 UTC 模式,而使用 moment() 创建的任何时刻都不会。
要从 UTC 切换到本地时间,您可以使用 moment#utc 或
时刻#local。
当您对其执行其他操作时,moment.js 变量中包含自包含的时区信息。区分这与标准 PHP 日期行为之间的区别很重要,标准 PHP 日期行为将日期视为相同(除非您明确说明)。
需要知道或设置在每种情况下使用的时区。不完全理解这两种行为很可能是你困惑的根源。
“日期就是日期”。片刻,因此库名称为“moment.js”。需要说明或设置该日期所在的时区。有不同的格式可以捕获此信息,但请理解“2015-10-29 04:50:06”并不能告诉您任何事情 直到您知道时区。这与 12:00 在您知道 AM 或 PM 之前不会告诉您任何信息的方式基本相同(假设您没有使用军事时间)。
2. 现在您有了一个午夜表示(无论您认为哪个对您的目的来说都是正确的),您可以将它转换为 UNIX 时间戳,因为它与您知道的时区相关感兴趣并代表您想要的确切时刻。
console.log(lastLocalMidnight.format());
// e.g. - 2015-10-28T00:00:00-06:00
console.log(lastUTCMidnight.format());
// e.g. - 2015-10-29T00:00:00+00:00
console.log(lastLocalMidnight.unix());
// e.g. - 1446012000
console.log(lastUTCMidnight.unix());
// e.g. - 1446076800
$timezoneBeforeSet = date_default_timezone_get();
echo $timezoneBeforeSet."\n";
注意 moment.js 的 format() 函数如何默认显示 UTC 偏移量。因此,即使以这种方式打印看起来像您想要的午夜,但您知道如果您将其格式化为 UTC(或您最初请求的日期以外的任何时区),它不会以 00:00:00 结束.
对于提前转换为 UTC 的时刻,没有偏移量。如果您稍后在您的本地时区格式化该时区,它将不在 00:00:00,并且 moment.js format() 的输出将指示基于您设置的时区的时区偏移量(-06:00,对于示例)。
3. 在 PHP 方面,您设置了一个默认的环境时区,正如我们通过查看 PHP 对 unix 时间戳“0”的看法所证明的那样。因此,现在对它们所代表的内容有了更多了解,让我们使用从 moment.js 获得的 unix 时间戳,并尝试使用 PHP 的日期对其进行格式化。
// Timestamps obtained from moment.js
$unixTimestampLocalMidnight = 1446012000;
$unixTimestampUTCMidnight = 1446076800;
// Relative to untampered timezone set in your PHP environment
$phpLocalMidnightUnchangedTZ = date('Y-m-d H:i:s', $unixTimestampLocalMidnight);
echo $phpLocalMidnightUnchangedTZ."\n";
// 2015-10-27 23:00:00
$phpUTCMidnightUnchangedTZ = date('Y-m-d H:i:s', $unixTimestampUTCMidnight);
echo $phpUTCMidnightUnchangedTZ."\n";
// 2015-10-28 17:00:00
是的。这些完全不是我们想要的,对吧?其实他们是。某个地方是 23:00:00,而其他地方是午夜时分是 17:00:00,对吧?
我们需要确定 PHP 认为我们现在所处的位置。我们可以使用 Date 输出该时区信息,但我们不在乎在最终输出中看到它(可以理解)。那么我们如何发现,否则呢?很高兴你问:
$timezoneBeforeSet = date_default_timezone_get();
echo $timezoneBeforeSet."\n";
// US/Pacific
我在美国/山区的科罗拉多州,有什么事吗?嗯,这一定意味着我使用的在线 PHP 沙箱托管在加利福尼亚或其他地方。说得通。知道你的代码在哪里运行。
但不要太担心这一点。这就是为什么我们预先捕获并转换为一致的格式,并且只在我们真正需要它的时候才担心格式化。那样的话,如果你转换错了,你最多只需要在一个或两个地方改变它。
有关 PHP 时区的完整参考,click here。
4. 如果您对 PHP 环境有任何控制权,则应该将默认时区设置为 UTC(您在项目引导或 PHP 环境配置中首先要做的事情之一文件)。
// Explicitly set PHP default timezone to UTC
date_default_timezone_set('UTC');
$timezoneAfterSet = date_default_timezone_get();
echo $timezoneAfterSet."\n";
// UTC
$phpLocalMidnight = date('Y-m-d H:i:s', $unixTimestampLocalMidnight);
echo $phpLocalMidnight."\n";
// 2015-10-28 06:00:00
$phpUTCMidnight = date('Y-m-d H:i:s', $unixTimestampUTCMidnight);
echo $phpUTCMidnight."\n";
// 2015-10-29 00:00:00
所以这是有道理的。我们现在显示的是相对于 UTC 的时间。如果我最初捕获的是美国/山区时间的午夜,我希望看到一天中的某个时间与英格兰格林威治的时间相对应。
如果您知道日期是使用时区格式化的,请考虑在时区指示的位置读取该日期时间。我们知道 PHP 会输出 UTC 的东西,所以当我看到输出时,我可以想象我在英国格林威治。
如果现在是早上 06:00 而我在格林威治,那么科罗拉多州的时间应该早 6 小时 (-6:00)
当然,我们预先明确转换为 UTC 的日期看起来就像一个真正的午夜。为什么?因为 PHP 设置为 UTC 格式的日期。还要注意提前一天。您现在应该知道的足够多,可以自己解释一下 =)
有意义吗?