Given a Unix timestamp, how to get beginning and end of that day?
Asked Answered
S

12

92

I have a Unix timestamp like this:

$timestamp=1330581600

How do I get the beginning of the day and the end of the day for that timestamp?

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

I tried this:

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

But I don't think it'll work because the timestamp itself isn't the exact beginning of the day.

Smackdab answered 17/4, 2012 at 19:33 Comment(2)
If it's GMT, probably: $boundary = floor/ceil($timestamp / (60 * 60 * 24)) * (60 * 60 * 24);Nonjuror
If your expected output is a timestamp as an integer there is a simple one liner: $beginOfDay = mktime(0, 0, 0, date('n'), date('j') - 1); $endOfDay = mktime(0, 0, 0, date('n'), date('j'));Cantabrigian
S
195

strtotime can be used to to quickly chop off the hour/minutes/seconds

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

DateTime can also be used, though requires a few extra steps to get from a long timestamp

$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'),
    )
);

With the addition of extended time in PHP7, there is potential to miss a second if using $now <= $end checking with this. Using $now < $nextStart checking would avoid that gap, in addition to the oddities around subtracting seconds and daylight savings in PHP's time handling.

Soleure answered 17/4, 2012 at 19:39 Comment(8)
Why minus 1 second at the end?Modiolus
I had read the original question as getting the last second of the day, rather then the first second of the next day. 'tomorrow' will give the first second of the day, so '-1' to get the second before the first second of the day.Soleure
How to do the same thing, but specifiying the timezone (not using server default)?Assignation
(Well, ended up using date_default_timezone_set(ServerConfig::DEFAULT_TIMEZONE) to set approriate timezone, so now this solution works for me too. +1.)Assignation
'today' also returns the beginning of the day strtotime('today', $timestamp)Effortless
Seems prone to leap-second issuesHydrophobic
$endOfDay->modify('tomorrow -1 second'); also works.Azygous
Unfortunately due to a php bug, this answer breaks in very specific scenarios. See my answer for the fix. @Soleure I know this is an old answer, but if you want to edit it per my answer please do, it is the top google resultDislike
E
17

Just DateTime

$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();

First a DateTime object is created and the timestamp is set to the desired timestamp. Then the object is formatted as a string setting the hour/minute/second to the beginning or end of the day. Lastly, a new DateTime object is created from this string and the timestamp is retrieved.

Readable

$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();

We can get the end of the day in an alternate manner using this longer version:

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

Timezone

The timezone can be set as well by adding a timestamp indicator to the format such as O and specifying the timestamp after creating the DateTime object:

$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();

Flexibility of DateTime

We can also get other information such as the beginning/end of the month or the beginning/end of the hour by changing the second format specified. For month: 'Y-m-01 00:00:00' and 'Y-m-t 23:59:59'. For hour: 'Y-m-d H:00:00' and 'Y-m-d H:59:59'

Using various formats in combination with add()/sub() and DateInterval objects, we can get the beginning or end of any period, although some care will need to be taken to handle leap years correctly.

Relevant Links

From the PHP docs:

Eads answered 4/1, 2016 at 18:7 Comment(3)
What you have created is succinct and readable. Unfortunately it will fail on leap seconds. Some days end at 23:59:58, while others end on 23:59:60. In particular this will cause problems if attempting to create a date for a nonexistant datetime, such as 23:59:59 on a day that could theoretically end one second before that. The accepted answer, which uses PHP's \DateTime::modify method, would avoid this. PHP's built in lib is smart enough to account for all of the oddities that surround dates and times including leap seconds.Audet
@Elimm, I wasn't aware that some days ended one second before or later because of leap day. I thought that leap only added a day on leap years and nothing else was affected. Can you give some example in code of how this fails (or can you share a day that has one more or one fewer seconds)? Also, is there an article you can share that tells more about this? Thanks for pointing out modify. I didn't know about that before.Eads
For sure. These are called leap seconds not leap days or years. They account for the rotation of the earth not being a constant speed. I believe June 30th, 2016 was our last leap second. The Wikipedia page dives in to the gritty details.Audet
J
9

You can use a combination of date() and 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() is smart enough to wrap months/years when given a day outside the specified month (jan 32nd will be feb 1st, etc)

Jobe answered 17/4, 2012 at 19:38 Comment(0)
O
4

You could convert the time to the current data and then use the strtotime function to find the start of the day and simply add 24 hours to that to find the end of the day.

You could also use the remainder operator (%) to find the nearest day. For example:

$start_of_day = time() - 86400 + (time() % 86400);
$end_of_day = $start_of_day + 86400;
Only answered 17/4, 2012 at 19:36 Comment(3)
Not all days are 86400 seconds long, so this wont work as you expectJobe
When you call time() twice, they could be different seconds.Andantino
@ChrisHarrison $now = time(); $start_of_day = $now - 86400 + ($now % 86400);Denisse
D
4

The accepted answer unfortunately breaks due to a php bug that occurs in very specific scenarios. I'll discuss those scenarios, but first the answer using DateTime. The only difference between this and the accepted answer occurs after the // IMPORTANT line:

$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);

So you'll note that instead of using ->modify('1 second ago'); we instead get the timestamp and subtract one. The accepted answer using modify should work, but breaks because of php bug in very specific scenarios. This bug occurs in timezones that change daylight savings at midnight, on the day of the year that clocks are moved "forward". Here is an example you can use to verify that bug.

bug example code

// 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;

bug example code output

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
Dislike answered 18/10, 2019 at 14:41 Comment(0)
G
3

Today Starting date timestamp. Simple

$stamp = mktime(0, 0, 0);
echo date('m-d-Y H:i:s',$stamp);
Gong answered 19/5, 2016 at 6:56 Comment(1)
This can cause unexpected behavior on days that have a daylight savings change exactly at midnightDislike
D
1
$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = ceil (time() / 86400) * 86400;

If your need both values in the same script. It is faster to +/- 86400 seconds to one of the variables than to fire both floor and ceil. For example:

$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = $start_of_day + 86400;
Denisse answered 22/3, 2016 at 22:56 Comment(0)
R
0

For anyone that have this question in the future:

Any day code

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

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

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

Current day code

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

$diff = $now - $midnight;
echo $diff;
?>
Remunerative answered 30/3, 2015 at 9:29 Comment(0)
D
0
$date = (new \DateTime())->setTimestamp(1330581600);

echo $date->modify('today')->format('Y-m-d H:i:s'); // 2012-02-29 00:00:00
echo PHP_EOL;
echo $date->modify('tomorrow - 1 second')->format('Y-m-d H:i:s'); // 2012-02-29 23:59:59
Despinadespise answered 29/4, 2021 at 13:39 Comment(0)
B
0
    $startOfDay = new \DateTime('tomorrow');
    $startOfDay->modify('-1 day');

This works for me :)

Boldface answered 17/5, 2021 at 13:21 Comment(0)
W
0

A little late to the party, but here's another easy way to achieve what you're looking for:

$timestamp=1330581600;
$format = DATE_ATOM;

$date = (new DateTime())->setTimestamp($timestamp);
// Here's your initial date, created from the timestamp above
// 2012-03-01T06:00:00+00:00
$dateFromTimestamp = $date->format($format);

// This is the beginning of the day
// 2012-03-01T00:00:00+00:00
$startOfDay = $date->setTime(0,0);

// This is the beginning of the next day
// 2012-03-02T00:00:00+00:00
$startOfNextDay = $startOfDay->modify('+1 day');

I would personally avoid using the end of the day unless it's absolutely necessary. You can, of course, use 23:59:59 but this is not the actual end of the day (there's still 1 second left). What I do is use the start of the next day as my end boundary, for example:

$start = new DateTime('2021-11-09 00:00:00');
$end = new DateTime('2021-11-10 00:00:00');
    
if ($someDateTime >= $start && $someDateTime < $end) {
    // do something
}

If I must use the end of the day, I'd go with calculating the start of the next day and then subtracting 1 microsecond from that.

Wayland answered 9/11, 2021 at 15:55 Comment(0)
F
0
$beginOfDay = (new DateTime('today', new DateTimeZone('Asia/Tehran')))->getTimestamp();
$endOfDay   = $beginOfDay + 86399;

You can set a timezone by replacing "Asia/Tehran". One day is 86400 seconds, Don't ask me why 86399, It is a whisper in my mind that says it is 86399, So I do not even want to think about its truth.

Fenian answered 18/2, 2022 at 20:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.