2

I have been using DateTime Diff (in php) to get various settings for pairs of dates - two formatted dates to display, a difference from the date to now (eg "start date was 3 months 2 days ago"), and a length between the two dates ("length is 2 months 3 days").

The problem is that DateTime Diff ignores one of the days so if the start is yesterday and the end is tomorrow, it gives 2 days whereas I want 3 because both dates should be included in the length. If it was just days, I could simply add 1 to the result, but I wanted to use the years/months/days results from the Diff and these are determined at construct.

The only way I have found to get the desired results is to create a DateTime for start and end (to get the formatted dates and the differences). Then take the end DateTime, add 1 day to it, then work out the length.

It's a bit clunky but there seems to be no way to tell DateTime Diff to include both start and end dates in the result.

1
  • As of now, no. Same thing applies to DatePeriod. It's a shortcoming for sure but, as you already know, it can be overcome. Commented Jul 9, 2016 at 13:34

1 Answer 1

2

DateTime encapsulates a specific moment in time. "yesterday" is not a moment but a time range. The same for "tomorrow".

DateTime::diff() doesn't ignore anything; it just provides you the exact difference (in day, hours, minutes a.s.o.) between two moments in time.

If you want to get the diff between "tomorrow" and "yesterday" as "3 days" you can subtract the first second of "yesterday" from (one second after the last second of "tomorrow").

Like this:

// Always set the timezone of your DateTime objects to avoid troubles
$tz = new DateTimeZone('Europe/Bucharest');
// Some random time yesterday
$date1 = new DateTime('2016-07-08 21:30:15', $tz);
// Other random time tomorrow
$date2 = new DateTime('2016-07-10 12:34:56', $tz);

// Don't mess with $date1 and $date2;
// clone them and do whatever you want with the clones
$yesterday = clone $date1;
$yesterday->setTime(0, 0, 0);         // first second of yesterday (the midnight)
$tomorrow = clone $date2;
$tomorrow->setTime(23, 59, 59)               // last second of tomorrow
         ->add(new DateInterval('PT1S'));    // one second

// Get the difference; it is the number of days between and including $date1 and $date2
$diff = $tomorrow->diff($yesterday);

printf("There are %d days between %s and %s (including the start and end date).\n",
     $diff->days, $date1->format('Y-m-d'), $date2->format('Y-m-d')
);
Sign up to request clarification or add additional context in comments.

3 Comments

Instead of cloning, you could use DateTimeImmutable instead.
When it comes to changing, the part with "do whatever you want" with DateTimeImmutable silently creates new objects. Nevertheless, the use of DateTimeImmutable whenever is possible is a good advice, especially when the datetime objects are function arguments.
Yeah, I consider DateTime objects to be value objects, so I prefer them to be immutable, I've fallen foul of mutable DateTime objects creating weird bugs a few times until I became more experienced with them :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.