php DateTime diff - include both dates in range? - php

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.

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

Related

PHP: get weekday number of the month

I'm looking for functionality that would do the opposite of
strtotime("third monday");
i.e. a function that is fed a timestamp and would return the weekday number of the month.
So if today is 18.07.2016, ideally the function should return "3" (i.e. 3rd Monday of July).
I can get the weekday itself by using date("D", [timestamp]), but I'm not sure how to calculate that it is in fact the third one this month.
Has anyone tried doing anything like this before?
You'll want to verify you're working within a valid date range, but this is a relatively simple task:
$today = date('d', time());
echo 1 + floor(($today - 1) / 7); // nth day of month
You should look into the Carbon class. It expands date and time functions to basically everything you'd ever need, including human-readable timestamps (ie. "5 minutes ago")
These two would be useful to you - the day and week of the month.
var_dump($dt->dayOfWeek); // int(3)
var_dump($dt->weekOfMonth); // int(1)
http://carbon.nesbot.com/docs/#api-getters

PHP DateTime diff

This may be a complete noob question but here goes:
I have the following code that compares two dates for absence management. Where I expect the answer to return as 2 (the difference between start and end date) I get 1.
$start_time = new DateTime("2015-01-01 00:00:00");
$end_time = new DateTime("2015-01-02 00:00:00");
$diff = $end_time->diff($start_time);
$d = $diff->days; // 1
I have also tried using just the dates (but I need the times as some absence type are done by hours not days)
Difference is 1 because there is only one day difference between both days.
To convert the datetime into hours or minutes you should look to these links:
Convert datetime into year, month, days, hours, minutes, seconds
Difference between 2 time() values

Calculate total subscription end date from multiple subscription end dates in PHP

Today is 2014-11-16.
I got these three dates in the future but I want them to be only one date instead.
2014-12-15 21:27:12
2014-12-15 21:32:20
2014-12-16 12:22:09
I want to get the total end date from today. That would be aproximately three month into the future but how can i calculate it to be the same date each time from the three dates above?
How can this be achieved with PHP's DateTime and DateInterval classes?
This might help:
$dateTimeObject=new DateTime(date('Y-m-d h:i:s', strtotime('2014-12-16 12:22:09')));
//to get diff with now
$diff = $dateTimeObject->diff(new DateTime(date('Y-m-d h:i:s')));
Then,
//to get diff months
echo $diff->m;
//to get diff hours
echo $diff->h;
//to get diff minutes
echo $diff->i;
And so on.
It is highly recommended to take a look at the PHP's DateTime official document.
Note that, DateTime is available on PHP >=5.2.0

php giving wrong answer when using time zone Australia/Sydney

I am developing an website to run in Australia.
so i have set the time zone as follows.
date_default_timezone_set('Australia/Sydney');
I need to calculate number of days between two dates.
I found a strange behavior in the month of October.
$now = strtotime('2013-10-06'); // or your date as well
$your_date = strtotime('2013-10-01');
$datediff = $now - $your_date;
echo floor($datediff/(60*60*24));//gives output 5, this is right
$now = strtotime('2013-10-07'); // or your date as well
$your_date = strtotime('2013-10-01');
$datediff = $now - $your_date;
echo floor($datediff/(60*60*24));//gives output 5, this is wrong, but it should be 6 here
after 2013-10-07 it always give one day less in answer.
Its fine with other timezones. May be its due to daylight saving. But whats the solution for this.
Please help.
Thanks
Why it says 5, and why this is technically correct
In Sydney, DST begins at 2013-10-06 02:00:00 - so you lose an hour in dates straddling that.
When you call strtime, it will interpret the time as a Sydney time, but return a Unix timestamp. If you converted the second set of timestamps to UTC, you'd get a range from 2013-09-30 14:00:00 to 2013-10-06 13:00:00, which isn't quite 6 days, so gets rounded down to 5.
How to get the time difference ignoring DST transitions
Try using DateTime objects instead, e.g.
$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-01', $tz);
$end=new DateTime('2013-10-07', $tz);
$diff=$end->diff($start);
//displays 6
echo "difference in days is ".$diff->d."\n";
Why does DateTime::diff work differently?
You might ask "why does that work?" - after all, there really isn't 6 days between those times, it's 5 days and 23 hours.
The reason is that DateTime::diff actually corrects for DST transitions. I had to read the source to figure that out - the correction happens inside the internal timelib_diff function. This correction happens if all the following are true
each DateTime uses the same timezone
the timezone must be geographic id and not an abbreviation like GMT
each DateTime must have different DST offsets (i.e. one in DST and one not)
To illustrate this point, here's what happens if we use two times just a few hours either side of the switch to DST
$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-06 00:00:00', $tz);
$end=new DateTime('2013-10-06 04:00:00', $tz);
//diff will correct for the DST transition
$diffApparent=$end->diff($start);
//but timestamps represent the reality
$diffActual=($end->getTimestamp() - $start->getTimestamp()) / 3600;
echo "Apparent difference is {$diffApparent->h} hours\n";
echo "Actual difference is {$diffActual} hours\n";
This outputs
Apparent difference is 4 hours
Actual difference is 3 hours

PHP DateTime / DateInterval object difference returning strange results

I have the following PHP datetime object giving strange results:
<?php
$date = new DateTime("2013-01-01");
$date2 = new DateTime("2011-01-01");
$interval = $date2->diff($date);
echo $interval->m;
?>
When using months (m), returns 0. Incorrect.
When I switch the interval to years (y) it returns 2 which is correct.
When I switch to days (d) it returns 0, incorrect.
When I switch to days using "days", it returns 731 which is correct
I am not sure why certain intervals are working and others are not. Any ideas or is this expected? If possible - I would like to continue using DateTime to find this difference but an open to other necessary means.
See, $interval is an object, not some primitive value. In your example this interval consists of two years, zero months and zero days. It doesn't get automatically converted into 'interval in months, interval in days' etc. when you're querying its properties: it just returns their values. And it's quite right: should you consider 29 days interval a month interval, for example?
The only exception is $days property (not $d!), which actually has a calculated value of days in that interval. And it's quite well described in the documentation:
$days
Total number of days between the starting and ending dates in a
DateTime::diff() calculation

Categories