Як порівняти два об'єкти DateTime у PHP 5.2.8?


294

Переглянувши документацію PHP, DateTimeмогло б вирішити мою проблему наступні два методи об’єкта:

  • DateTime :: diff : Отримайте різницю та використовуйте її, щоб визначити, що є найдавнішим.
  • DateTime :: getTimestamp : Отримайте часовий такт UNIX та порівняйте їх.

Обидва ці методи позначені в doco як такі, що доступні у версії> = 5.3 (і, не дивно, якщо я спробую викликати їх, я вважаю, що їх не існує). Я не можу знайти якусь конкретну документацію для 5.2.8, тому я не впевнений, чи є у моїй версії еквівалентні методи. Я вирішив проблему і знайшов еклектичний спектр рішень, жоден з яких не відповідає моїм дуже простим вимогам:

  • Як порівняти два об'єкти DateTime?
  • Де я можу знайти doco для попередніх версій PHP? Зокрема версія 5.2.8?

Для деякого контексту у мене є такий код:

$st_dt = new DateTime(verifyParam ('start_date'));
$end_dt = new DateTime(verifyParam ('end_date'));

// is the end date more ancient than the start date?
if ($end_dt < $start_dt) 

Мабуть, у цього хлопця немає оператора порівняння.

Редагувати

Мабуть, мої припущення були повністю помилковими (дякую Мілен за те, що це так ефективно проілюструвала). Є оператор порівняння, і він працює чудово завдяки. Іноді я дуже сумую за компілятором. Помилка в коді вище, я впевнений, що ви знайдете її набагато швидше, ніж я :).


1
Що стосується відсутності компілятора - встановіть "error_reporting" на "E_ALL", і ви отримаєте повідомлення типу "Примітка: Не визначена змінна: start_dt в ...".
Мілен А. Радев

5
Крім того, будь ласка, використовуйте htmlentities на вашій $_POSTформі, або кошеня буде вбито.
Климент Герреман

2
А де помилка? : p, я це теж роблю U_U. Спасибі заздалегідь!
castarco

2
@castarco Я ініціалізую $ st_dt, але я порівнюю проти неініціалізованого $ start_dt. Перевірте імена змінних і, можливо, дотримуйтесь пропозиції Мілена та встановіть повідомлення про помилки в E_ALL, щоб отримати невизначені попередження змінної. :)
RedBlueThing

Відповіді:


432

Здається, що підтверджує наявність операторів порівняння для класу DateTime:

dev:~# php
<?php
date_default_timezone_set('Europe/London');

$d1 = new DateTime('2008-08-03 14:52:10');
$d2 = new DateTime('2008-01-03 11:11:10');
var_dump($d1 == $d2);
var_dump($d1 > $d2);
var_dump($d1 < $d2);
?>
bool(false)
bool(true)
bool(false)
dev:~# php -v
PHP 5.2.6-1+lenny3 with Suhosin-Patch 0.9.6.2 (cli) (built: Apr 26 2009 20:09:03)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
dev:~#

7
Дякую Мілен, схоже, мені просто потрібні були видалені мої помилкові припущення, і раптом кричуща помилка в моєму коді стала очевидною для мене.
RedBlueThing

2
Хм, це цікаво. Можливо, в якийсь момент нам вдасться перевантажити операторів у визначених користувачем класах.
Ionuț G. Stan

1
З php.net/manual/en/language.operators.comppare.php Вбудовані класи можуть визначити власне порівняння, різні класи незрівнянні, той самий клас - порівняти властивості так само, як масиви (PHP 4), PHP 5 має свою власне пояснення
Саул

7
будьте
уважні,

1
TiMESPLiNTER, я вважаю, що попередження полягає в тому, що якщо вас цікавить лише порівняння дат, ви можете пропустити той факт, що години відрізняються, і, отже, два години DateTimeз тією ж датою не будуть порівнюватися з рівними, коли ви вважаєте, що повинні. Виправити це можна, чітко встановивши часові компоненти об’єкта на нуль, перш ніж порівнювати їх.
Джейсон

52

З офіційної документації :

Станом на PHP 5.2.2, об’єкти DateTime можна порівняти за допомогою операторів порівняння .

$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // false
var_dump($date1 < $date2); // true
var_dump($date1 > $date2); // false

Для версій PHP до 5.2.2 (фактично для будь-якої версії) ви можете використовувати diff .

$datetime1 = new DateTime('2009-10-11'); // 11 October 2013
$datetime2 = new DateTime('2009-10-13'); // 13 October 2013

$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days'); // +2 days

3
Цю відповідь я вважаю найкращою, оскільки вона цитує посібник, а не просто перевіряти поведінку та припускати, що результат є таким, як очікувалося. ТАК не місце для здогадок. Браво Роберто.
cprn

3
@roberto DateTime :: diff додано лише в PHP 5.3
NeXuS

30

Ви також можете порівняти епохальні секунди:

$d1->format('U') < $d2->format('U')

Джерело: http://laughingmeme.org/2007/02/27/looking-at-php5s-datetime-and-datetimezone/ (досить цікава стаття про DateTime)


16
Остерігайтеся, що formatстворює рядок , тож це порівняння рядків. Це ледве проблема після 1000000000 епох (приблизно 9 вересня 2001 р.), Але якщо вам доведеться мати справу з датами до цього, ви можете виникнути проблеми через різну тривалість числа. Або конвертуйте результати в числа (віднімання їх також працює), або використовуйте справді сортований формат, як c.
MaxArt

1
@MaxArt, чи можете ви детальніше розібратися в проблемах через різну довжину рядків? Посібник щодо рядків у числових контекстах: "Якщо рядок не містить жодного символу". "," E "або" E ", і числове значення вписується в цілі обмеження типу (як визначено PHP_INT_MAX), рядок буде оцінено як ціле число. У всіх інших випадках воно буде оцінюватися як плавець ". Майбутні дати (близько 2038 р.) Можуть переповнювати підписані 32-бітні цілі числа, але в чому проблема старіших дат?
Адріан Гюнтер

1
@ AdrianGünter Проблема полягає в тому, що ми не знаходимося в числовому контексті, але ми мали б справу з рядками . Числові, але все ж рядки. Таким чином, було б зроблено рядкове порівняння.
MaxArt


2
@ FrédéricMarchal Так, я дійсно пізніше дізнався, що мій попередній коментар насправді помилковий. PHP по-справжньому злий спосіб поводитися з цими випадками, жодна інша мова (наскільки я знаю) не піддається цифрам, коли у вас є два рядки для порівняння. Він дійсно накручує ваш код, якщо ви насправді хочете зробити лексикографічне порівняння.
MaxArt

20

Якщо ви хочете порівняти дати, а не час, ви можете скористатися цим:

$d1->format("Y-m-d") == $d2->format("Y-m-d")

5
Ви також можете встановити час скидання. $d1->setTime(0, 0, 0);
Атлан

3

Станом на PHP 7.x, ви можете використовувати наступне:

$aDate = new \DateTime('@'.(time()));
$bDate = new \DateTime('@'.(time() - 3600));

$aDate <=> $bDate; // => 1, `$aDate` is newer than `$bDate`

0
$elapsed = '2592000';
// Time in the past
$time_past = '2014-07-16 11:35:33';
$time_past = strtotime($time_past);

// Add a month to that time
$time_past = $time_past + $elapsed;

// Time NOW
$time_now = time();

// Check if its been a month since time past
if($time_past > $time_now){
    echo 'Hasnt been a month';    
}else{
    echo 'Been longer than a month';
}

мітка часу має деякі обмеження. Ви можете прочитати цей stackoverflow.com/a/7229760/2652018
Steel Brain

Добре знати! Це було призначено просто для простого порівняння часів.
Кайл Коутс

-1

Це може вам допомогти.

$today = date("m-d-Y H:i:s");
$thisMonth =date("m");
$thisYear = date("y");
$expectedDate = ($thisMonth+1)."-08-$thisYear 23:58:00";


if (strtotime($expectedDate) > strtotime($today)) {
    echo "Expected date is greater then current date";
    return ;
} else
{
 echo "Expected date is lesser then current date";
}

мітка часу має деякі обмеження. Ви можете прочитати цей stackoverflow.com/a/7229760/2652018
Steel Brain

@SteelBrain Ви думаєте, що обмеження часових позначок турбує вище коду, який має весь поточний час дати. Будь ласка, прочитайте код ще раз. Це, в основному, перевірте, чи є хлопець $ очікуванийДата, який завжди буде в поточному місяці. Я не думаю, тому ми повинні думати про обмеження часових позначок у цьому випадку.
Тарун Гупта

Я знаю, але це не рекомендований спосіб, (я не спростував :-))
Steel Brain

Чи можете ви запропонувати рекомендований спосіб.
Тарун Гупта

звичайно, $today = new DateTime("now"); $time = DateTime::createFromFormat('d-m-Y',"26-October-1998"); if ($today > $time){echo "today is greater";}else{echo "other time is greater";}ура.
Сталевий мозок
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.