Враховуючи мітку часу Unix, як отримати початок і кінець цього дня?


80

У мене є мітка часу Unix, така:

$timestamp=1330581600

Як отримати початок дня та кінець дня для цієї позначки часу?

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

Я спробував це:

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

Але я не думаю, що це спрацює, оскільки відмітка часу не є точним початком дня.


Якщо GMT, ймовірно: $ border = floor / ceil ($ timestamp / (60 * 60 * 24)) * (60 * 60 * 24);
hakre

Якщо очікуваний результат - це мітка часу як ціле число, існує простий вкладиш: $ beginOfDay = mktime (0, 0, 0, date ('n'), date ('j') - 1); $ endOfDay = mktime (0, 0, 0, дата ('n'), дата ('j'));
jarederaj

Відповіді:


177

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

5
"сьогодні" також повертає початок дняstrtotime('today', $timestamp)
Семра

1
Здається, схильний до стрибкових випусків
Бред Кент

4
$endOfDay->modify('tomorrow -1 second');також працює.
CGodo

11

Просто 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();

Спочатку створюється об'єкт 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, ми можемо отримати початок чи кінець будь-якого періоду, хоча для правильної обробки високосних років потрібно буде подбати певно.

Відповідні посилання

З документів PHP:


2
Те, що ви створили, є стислим і читабельним. На жаль, це не вдасться у високосні секунди. Деякі дні закінчуються о 23:59:58, а інші закінчуються о 23:59:60. Зокрема, це спричинить проблеми при спробі створити дату для неіснуючого часу, наприклад 23:59:59 в день, який теоретично може закінчитися за одну секунду до цього. Прийнята відповідь, яка використовує метод PHP \ DateTime :: modify, уникне цього. Вбудована бібліотека PHP досить розумна, щоб врахувати всі дивацтва, що оточують дати та час, включаючи високосні секунди.
Elimin

@Elimm, я не знав, що деякі дні закінчувались секундою до або пізніше через високосний день. Я думав, що стрибок лише додав день у високосні роки, і нічого іншого це не вплинуло. Чи можете ви навести в коді приклад того, як це не вдається (або ви можете поділитися днем, який має одну більше або одну секунду менше)? Крім того, чи є стаття, якою ви можете поділитися, яка розповідає більше про це? Дякую, що вказали modify. Я раніше про це не знав.
Роберт Хікман,

Напевно. Вони називаються високосними секундами, а не високосними днями чи роками . Вони пояснюють, що обертання Землі не є постійною швидкістю. Я вважаю, що 30 червня 2016 року став для нас останньою стрибковою секундою. Сторінка Вікіпедії занурюється в дрібні деталі.
Елімн

7

Ви можете використовувати комбінацію 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() достатньо розумний, щоб обернути місяці / роки, якщо їм дано день поза вказаним місяцем (32 січня буде 1 лютого тощо)


4

Ви можете перетворити час на поточні дані, а потім скористатися функцією strtotime, щоб знайти початок дня і просто додати до нього 24 години, щоб знайти кінець дня.

Ви також можете використовувати оператор залишку (%), щоб знайти найближчий день. Наприклад:

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

7
Не всі дні тривають 86400 секунд, тому це не спрацює, як ви очікуєте
Кел,

@Cal о так, я не думав про це
Камерон

2
Коли ви телефонуєте time()двічі, вони можуть мати різні секунди.
Кріс Гаррісон,

@ChrisHarrison $ зараз = час (); $ start_of_day = $ зараз - 86400 + ($ зараз% 86400);
Карім

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');ми замість цього отримуємо мітку часу і віднімаємо одиницю. Прийнята відповідь з використанням modify повинна працювати, але порушується через помилку php у дуже конкретних сценаріях. Ця помилка трапляється в часових поясах, які змінюють перехід на літній час опівночі, в той день року, коли годинник переміщується "вперед". Ось приклад, за допомогою якого можна перевірити цю помилку.

приклад коду помилки

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

1
Це може спричинити несподівану поведінку в дні, коли перехід на літній час змінюється рівно опівночі
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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.