给定Unix时间戳,该如何开始和结束这一天?


79

我有一个这样的Unix时间戳:

$timestamp=1330581600

如何获得该时间戳记的开始和结束时间?

e.g.
$beginOfDay = Start of Timestamp's Day
$endOfDay = End of Timestamp's Day

我尝试了这个:

$endOfDay = $timestamp + (60 * 60 * 23);

但是我认为它不会起作用,因为时间戳本身并不是一天的确切开始。


如果是格林尼治标准时间,则可能是:$ boundary = floor / ceil($ timestamp /(60 * 60 * 24))*(60 * 60 * 24);
hakre 2012年

如果您的期望输出是一个时间戳记(整数),则有一个简单的衬里:$ beginOfDay = mktime(0,0,0,date('n'),date('j')-1); $ endOfDay = mktime(0,0,0,date('n'),date('j'));
jarederaj

Answers:


176

strtotime可用于快速切断小时/分钟/秒

$beginOfDay = strtotime("today", $timestamp);
$endOfDay   = strtotime("tomorrow", $beginOfDay) - 1;

DateTime也可以使用,尽管需要很长时间才能获得较长的时间戳

$dtNow = new DateTime();
// Set a non-default timezone if needed
$dtNow->setTimezone(new DateTimeZone('Pacific/Chatham'));
$dtNow->setTimestamp($timestamp);

$beginOfDay = clone $dtNow;
$beginOfDay->modify('today');

$endOfDay = clone $beginOfDay;
$endOfDay->modify('tomorrow');
// adjust from the start of next day to the end of the day,
// per original question
// Decremented the second as a long timestamp rather than the
// DateTime object, due to oddities around modifying
// into skipped hours of day-lights-saving.
$endOfDateTimestamp = $endOfDay->getTimestamp();
$endOfDay->setTimestamp($endOfDateTimestamp - 1);

var_dump(
    array(
        'time ' => $dtNow->format('Y-m-d H:i:s e'),
        'start' => $beginOfDay->format('Y-m-d H:i:s e'),
        'end  ' => $endOfDay->format('Y-m-d H:i:s e'),
    )
);

随着PHP7中时间的延长,如果$now <= $end对此进行检查,则有可能会错过一秒钟。$now < $nextStart除了在PHP的时间处理中减少秒数和节省日光之外,使用检查还可以避免这种差距。


2
为什么最后要减去1秒?
Kurt Zhong

1
我读的原始问题是在一天的最后一秒,而不是第二天的第一秒。“明天”将提供一天的第一秒,因此“ -1”将获得一天的第一秒。
rrehbein

4
“今天”还返回一天的开始strtotime('today', $timestamp)
Semra

1
似乎容易出现leap秒问题
Brad Kent

3
$endOfDay->modify('tomorrow -1 second');也可以。
CGodo

11

只是日期时间

$beginOfDay = DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->setTimestamp($timestamp)->format('Y-m-d 00:00:00'))->getTimestamp();
$endOfDay = DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->setTimestamp($timestamp)->format('Y-m-d 23:59:59'))->getTimestamp();

首先,创建一个DateTime对象,并将时间戳设置为所需的时间戳。然后,将对象格式化为字符串,将小时/分钟/秒设置为一天的开始或结束。最后,从该字符串创建一个新的DateTime对象,并检索时间戳。

可读的

$dateTimeObject = new DateTime();
$dateTimeObject->setTimestamp($timestamp);
$beginOfDayString = $dateTimeObject->format('Y-m-d 00:00:00');
$beginOfDayObject = DateTime::createFromFormat('Y-m-d H:i:s', $beginOfDayString);
$beginOfDay = $beginOfDayObject->getTimestamp();

我们可以使用以下较长版本来结束一天的工作:

$endOfDayObject = clone $beginOfDayOject(); // Cloning because add() and sub() modify the object
$endOfDayObject->add(new DateInterval('P1D'))->sub(new DateInterval('PT1S'));
$endOfDay = $endOfDayOject->getTimestamp();

时区

还可以通过以下方式来设置时区O:在创建DateTime对象后,将时间戳指示符添加到格式,例如,并指定时间戳:

$beginOfDay = DateTime::createFromFormat('Y-m-d H:i:s O', (new DateTime())->setTimezone(new DateTimeZone('America/Los_Angeles'))->setTimestamp($timestamp)->format('Y-m-d 00:00:00 O'))->getTimestamp();

DateTime的灵活性

通过更改指定的第二种格式,我们还可以获得其他信息,例如月份的开始/结束或小时的开始/结束。对于月份:'Y-m-01 00:00:00''Y-m-t 23:59:59'。小时:'Y-m-d H:00:00''Y-m-d H:59:59'

通过将各种格式与add()/ sub()和DateInterval对象结合使用,我们可以获取任何时期的开始或结束,尽管需要采取一些措施才能正确处理leap年。

相关连结

从PHP文档:


2
您创建的内容简洁易读。不幸的是,它将在leap秒内失败。有些日子在23:59:58结束,而另一些日子则在23:59:60结束。特别是,如果尝试为不存在的日期时间创建日期,例如在理论上可以在此之前结束一秒的一天中的23:59:59,则会引起问题。接受的答案使用PHP的\ DateTime :: modify方法,可以避免这种情况。PHP的内置库足够聪明,可以解决围绕日期和时间(包括leap秒)的所有奇怪问题。
伊林2015年

@Elimm,我不知道有几天是因为leap日而在一秒钟之前或之后结束的。我以为,leap年只增加了一天,而其他一切都没有受到影响。您能否在代码中举一些例子说明失败的方式(或者您可以分享一天多一点或少一点的一天)?此外,是否有您可以分享的文章介绍了更多信息?感谢您指出modify。我以前不知道
罗伯特·希克曼

当然。这些被称为leap秒,而不是days日years年。它们解释了地球的旋转不是恒定的速度。我相信2016年6月30日是我们的第二次飞跃。在维基百科页面潜水到坚韧不拔的细节。
伊林2015年

6

您可以使用组合date()mktime()

list($y,$m,$d) = explode('-', date('Y-m-d', $ts));
$start = mktime(0,0,0,$m,$d,$y);
$end = mktime(0,0,0,$m,$d+1,$y);

mktime() 如果在指定月份之外的某一天给出日期,则足够聪明以包装月份/年份(1月32日将是2月1日,依此类推)


4

您可以将时间转换为当前数据,然后使用strtotime函数查找一天的开始时间,然后再添加24小时以查找一天的结束时间。

您还可以使用余数运算符(%)查找最近的日期。例如:

$start_of_day = time() - 86400 + (time() % 86400);
$end_of_day = $start_of_day + 86400;

7
并非所有的日子都长86400秒,所以这不会按您预期的那样工作
2012年

@Cal哦,是的,我没想到
James

2
当您拨打time()两次时,它们可能会不同。
克里斯·哈里森

@ChrisHarrison $ now = time(); $ start_of_day = $ now-86400 +($ now%86400);
Kareem

4

不幸的是,由于在非常特定的情况下发生了PHP错误,因此无法接受答案。我将讨论这些情况,但首先使用DateTime回答。此行与接受的答案之间的唯一区别是在下// IMPORTANT一行之后:

$dtNow = new DateTime();
// Set a non-default timezone if needed
$dtNow->setTimezone(new DateTimeZone('America/Havana'));
$dtNow->setTimestamp($timestamp);

$beginOfDay = clone $dtNow;

// Go to midnight.  ->modify('midnight') does not do this for some reason
$beginOfDay->modify('today');

// now get the beginning of the next day
$endOfDay = clone $beginOfDay;
$endOfDay->modify('tomorrow');

// IMPORTANT
// get the timestamp
$ts = $endOfDay->getTimestamp();
// subtract one from that timestamp
$tsEndOfDay = $ts - 1;

// we now have the timestamp at the end of the day. we can now use that timestamp
// to set our end of day DateTime
$endOfDay->setTimestamp($tsEndOfDay);

因此,您会注意到,不是使用->modify('1 second ago');我们而是获取时间戳并减去1。使用可接受的答案modify 应该可以,但是由于在特定情况下的php bug而中断。此错误发生在时区,该时区会在时钟“向前”移动的一年中的午夜更改夏令时。这是您可以用来验证该错误的示例。

错误示例代码

// a time zone, Cuba, that changes their clocks forward exactly at midnight. on
// the day before they make that change. there are other time zones which do this
$timezone = 'America/Santiago';
$dateString = "2020-09-05";

echo 'the start of the day:<br>';
$dtStartOfDay = clone $dtToday;
$dtStartOfDay->modify('today');
echo $dtStartOfDay->format('Y-m-d H:i:s');
echo ', '.$dtStartOfDay->getTimestamp();

echo '<br><br>the start of the *next* day:<br>';
$dtEndOfDay = clone $dtToday;
$dtEndOfDay->modify('tomorrow');
echo $dtEndOfDay->format('Y-m-d H:i:s');
echo ', '.$dtEndOfDay->getTimestamp();

echo '<br><br>the end of the day, this is incorrect. notice that with ->modify("-1 second") the second does not decrement the timestamp by 1:<br>';
$dtEndOfDayMinusOne = clone $dtEndOfDay;
$dtEndOfDayMinusOne->modify('1 second ago');
echo $dtEndOfDayMinusOne->format('Y-m-d H:i:s');
echo ', '.$dtEndOfDayMinusOne->getTimestamp();

echo '<br><br>the end of the day, this is correct:<br>';
$dtx = clone $dtEndOfDay;
$tsx = $dtx->getTimestamp() - 1;
$dty = clone $dtEndOfDay;
$dty->setTimestamp($tsx);
echo $dty->format('Y-m-d H:i:s');
echo ', '.$tsx;

错误示例代码输出

the start of the day:
2020-03-26 00:00:00, 1585173600

the start of the *next* day:
2020-03-27 01:00:00, 1585260000

the end of the day, this is incorrect. notice that with ->modify("1 second ago") the
second does not decrement the timestamp by 1:
2020-03-27 01:59:59, 1585263599

the end of the day, this is correct:
2020-03-26 23:59:59, 1585259999

3

今天开始日期时间戳。简单

$stamp = mktime(0, 0, 0);
echo date('m-d-Y H:i:s',$stamp);

这可能导致在夏令时正好在午夜更改的日子中发生意外行为
KayakinKoder

0

对于以后有这个问题的任何人:

任何一天的代码

<?php
$date = "2015-04-12 09:20:00";

$midnight = strtotime("midnight", strtotime($date));
$now = strtotime($date);

$diff = $now - $midnight;
echo $diff;
?>

当日代码

<?php
$midnight = strtotime("midnight");
$now = date('U');

$diff = $now - $midnight;
echo $diff;
?>

0
$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = ceil (time() / 86400) * 86400;

如果您需要在同一脚本中使用两个值。对变量之一进行+/- +/- 86400秒比触发地板和天花板要快。例如:

$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = $start_of_day + 86400;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.