PHP: Add months/days/years to user supplied date - php

***** SOLVED *****
I have a small program where I get a date from a user - (mm/dd/yyy) - then allow them to add x number of days, months, or years. I've been trying to use the 'strtotime' function but I'm not sure if I am understanding it right.
My code is below. Say, for example, $od (original date) was 7/24/2015. The $d, $m, and $y variables are read from the form filled out by the user. These could be 0's or a user-supplied value.
Before spending hours on this one simple task, I thought I'd ask if I should be approaching this in a different fashion and/or using another function.
// Function to determine new date
function newDate($od, $d, $m, $y) {
$newDate = Date($od, strtotime('+ $d days'));
$newDate = Date($od, strtotime('+ $m months'));
$newDate = Date($od, strtotime('+ $y years'));
if ($od != $newDate) {
return $newDate;
}
else if ($od == $newDate ){
return '[no change]';
}
else {
return '[error occurred]';
}
}
EDIT: Trying now with the interval date as suggested. Can you not parse the interval string together? I feel like this should work (results in some 'non-object' error):
$newDate = $od;
$newDate->add(new DateInterval('P'.$m.'M'.$d.'D'.$y.'Y'));
echo $newDate;
if ($od != $newDate) {
return $newDate->format('mm/dd/yyyy');
EDIT: I figured it out - you can't have '0's in the string so the function won't be as clean as I had hoped.
***** SOLVED *****

The right way : DateTime::add -- date_add — Adds an amount of days, months, years, hours, minutes and seconds to a DateTime object
http://php.net/manual/en/datetime.add.php
Using native functions is always fastest, and in your case seems the proper way to go!

Related

Find Number of days in seasons range by providing from and to date [duplicate]

How to find number of days between two dates using PHP?
$now = time(); // or your date as well
$your_date = strtotime("2010-01-31");
$datediff = $now - $your_date;
echo round($datediff / (60 * 60 * 24));
If you're using PHP 5.3 >, this is by far the most accurate way of calculating the absolute difference:
$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");
$abs_diff = $later->diff($earlier)->format("%a"); //3
If you need a relative (signed) number of days, use this instead:
$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");
$pos_diff = $earlier->diff($later)->format("%r%a"); //3
$neg_diff = $later->diff($earlier)->format("%r%a"); //-3
More on php's DateInterval format can be found here: https://www.php.net/manual/en/dateinterval.format.php
From PHP Version 5.3 and up, new date/time functions have been added to get difference:
$datetime1 = new DateTime("2010-06-20");
$datetime2 = new DateTime("2011-06-22");
$difference = $datetime1->diff($datetime2);
echo 'Difference: '.$difference->y.' years, '
.$difference->m.' months, '
.$difference->d.' days';
print_r($difference);
Result as below:
Difference: 1 years, 0 months, 2 days
DateInterval Object
(
[y] => 1
[m] => 0
[d] => 2
[h] => 0
[i] => 0
[s] => 0
[invert] => 0
[days] => 367
)
Hope it helps !
TL;DR do not use UNIX timestamps. Do not use time(). If you do, be prepared should its 98.0825% reliability fail you. Use DateTime (or Carbon).
The correct answer is the one given by Saksham Gupta (other answers are also correct):
$date1 = new DateTime('2010-07-06');
$date2 = new DateTime('2010-07-09');
$days = $date2->diff($date1)->format('%a');
Or procedurally as a one-liner:
/**
* Number of days between two dates.
*
* #param date $dt1 First date
* #param date $dt2 Second date
* #return int
*/
function daysBetween($dt1, $dt2) {
return date_diff(
date_create($dt2),
date_create($dt1)
)->format('%a');
}
With a caveat: the '%a' seems to indicate the absolute number of days. If you want it as a signed integer, i.e. negative when the second date is before the first, then you need to use the '%r' prefix (i.e. format('%r%a')).
If you really must use UNIX timestamps, set the time zone to GMT to avoid most of the pitfalls detailed below.
Long answer: why dividing by 24*60*60 (aka 86400) is unsafe
Most of the answers using UNIX timestamps (and 86400 to convert that to days) make two assumptions that, put together, can lead to scenarios with wrong results and subtle bugs that may be difficult to track, and arise even days, weeks or months after a successful deployment. It's not that the solution doesn't work - it works. Today. But it might stop working tomorrow.
First mistake is not considering that when asked, "How many days passed since yesterday?", a computer might truthfully answer zero if between the present and the instant indicated by "yesterday" less than one whole day has passed.
Usually when converting a "day" to a UNIX timestamp, what is obtained is the timestamp for the midnight of that particular day.
So between the midnights of October 1st and October 15th, fifteen days have elapsed. But between 13:00 of October 1st and 14:55 of October 15th, fifteen days minus 5 minutes have elapsed, and most solutions using floor() or doing implicit integer conversion will report one day less than expected.
So, "how many days ago was Y-m-d H:i:s"? will yield the wrong answer.
The second mistake is equating one day to 86400 seconds. This is almost always true - it happens often enough to overlook the times it doesn't. But the distance in seconds between two consecutive midnights is surely not 86400 at least twice a year when daylight saving time comes into play. Comparing two dates across a DST boundary will yield the wrong answer.
So even if you use the "hack" of forcing all date timestamps to a fixed hour, say midnight (this is also done implicitly by various languages and frameworks when you only specify day-month-year and not also hour-minute-second; same happens with DATE type in databases such as MySQL), the widely used formula
FLOOR((unix_timestamp(DATE2) - unix_timestamp(DATE1)) / 86400)
or
floor((time() - strtotime($somedate)) / 86400)
will return, say, 17 when DATE1 and DATE2 are in the same DST segment of the year; but even if the hour:minute:second part is identical, the argument might be 17.042, and worse still, 16.958 when they are in different DST segments and the time zone is DST-aware. The use of floor() or any implicit truncation to integer will then convert what should have been a 17 to a 16. In other circumstances, expressions like "$days > 17" will return true for 17.042, even if this will look as if the elapsed day count is 18.
And things grow even uglier since such code is not portable across platforms, because some of them may apply leap seconds and some might not. On those platforms that do, the difference between two dates will not be 86400 but 86401, or maybe 86399. So code that worked in May and actually passed all tests will break next June when 12.99999 days are considered 12 days instead of 13. Two dates that worked in 2015 will not work in 2017 -- the same dates, and neither year is a leap year. And between 2018-03-01 and 2017-03-01, on those platforms that care, 366 days will have passed instead of 365, making 2018 a leap year (which it is not).
So if you really want to use UNIX timestamps:
use round() function wisely, not floor().
as an alternative, do not calculate differences between D1-M1-YYY1 and D2-M2-YYY2. Those dates will be really considered as D1-M1-YYY1 00:00:00 and D2-M2-YYY2 00:00:00. Rather, convert between D1-M1-YYY1 22:30:00 and D2-M2-YYY2 04:30:00. You will always get a remainder of about twenty hours. This may become twenty-one hours or nineteen, and maybe eighteen hours, fifty-nine minutes thirty-six seconds. No matter. It is a large margin which will stay there and stay positive for the foreseeable future. Now you can truncate it with floor() in safety.
The correct solution though, to avoid magic constants, rounding kludges and a maintenance debt, is to
use a time library (Datetime, Carbon, whatever); don't roll your own
write comprehensive test cases using really evil date choices - across DST boundaries, across leap years, across leap seconds, and so on, as well as commonplace dates. Ideally (calls to datetime are fast!) generate four whole years' (and one day) worth of dates by assembling them from strings, sequentially, and ensure that the difference between the first day and the day being tested increases steadily by one. This will ensure that if anything changes in the low-level routines and leap seconds fixes try to wreak havoc, at least you will know.
run those tests regularly together with the rest of the test suite. They're a matter of milliseconds, and may save you literally hours of head scratching.
Whatever your solution, test it!
The function funcdiff below implements one of the solutions (as it happens, the accepted one) in a real world scenario.
<?php
$tz = 'Europe/Rome';
$yearFrom = 1980;
$yearTo = 2020;
$verbose = false;
function funcdiff($date2, $date1) {
$now = strtotime($date2);
$your_date = strtotime($date1);
$datediff = $now - $your_date;
return floor($datediff / (60 * 60 * 24));
}
########################################
date_default_timezone_set($tz);
$failures = 0;
$tests = 0;
$dom = array ( 0, 31, 28, 31, 30,
31, 30, 31, 31,
30, 31, 30, 31 );
(array_sum($dom) === 365) || die("Thirty days hath September...");
$last = array();
for ($year = $yearFrom; $year < $yearTo; $year++) {
$dom[2] = 28;
// Apply leap year rules.
if ($year % 4 === 0) { $dom[2] = 29; }
if ($year % 100 === 0) { $dom[2] = 28; }
if ($year % 400 === 0) { $dom[2] = 29; }
for ($month = 1; $month <= 12; $month ++) {
for ($day = 1; $day <= $dom[$month]; $day++) {
$date = sprintf("%04d-%02d-%02d", $year, $month, $day);
if (count($last) === 7) {
$tests ++;
$diff = funcdiff($date, $test = array_shift($last));
if ((double)$diff !== (double)7) {
$failures ++;
if ($verbose) {
print "There seem to be {$diff} days between {$date} and {$test}\n";
}
}
}
$last[] = $date;
}
}
}
print "This function failed {$failures} of its {$tests} tests";
print " between {$yearFrom} and {$yearTo}.\n";
The result is,
This function failed 280 of its 14603 tests
Horror Story: the cost of "saving time"
It all began in late 2014. An ingenious programmer decided to save several microseconds off a calculation that took about thirty seconds at most, by plugging in the infamous "(MidnightOfDateB-MidnightOfDateA)/86400" code in several places. It was so obvious an optimization that he did not even document it, and the optimization passed the integration tests and somehow lurked in the code for several months, all unnoticed.
This happened in a program that calculates the wages for several top-selling salesmen, the least of which has a frightful lot more clout than a whole humble five-people programmer team taken together. On March 28th, 2015, the summer time zone engaged, the bug struck -- and some of those guys got shortchanged one whole day of fat commissions. To make things worse, most of them did not work on Sundays and, being near the end of the month, used that day to catch up with their invoicing. They were definitely not amused.
Infinitely worse, they lost the (already very little) faith they had in the program not being designed to surreptitiously shaft them, and pretended - and obtained - a complete, detailed code review with test cases ran and commented in layman's terms (plus a lot of red-carpet treatment in the following weeks).
What can I say: on the plus side, we got rid of a lot of technical debt, and were able to rewrite and refactor several pieces of a spaghetti mess that hearkened back to a COBOL infestation in the swinging '90s. The program undoubtedly runs better now, and there's a lot more debugging information to quickly zero in when anything looks fishy. I estimate that just this last one thing will save perhaps one or two man-days per month for the foreseeable future, so the disaster will have a silver, or even golden, lining.
On the minus side, the whole brouhaha costed the company about €200,000 up front - plus face, plus undoubtedly some bargaining power (and, hence, yet more money).
The guy responsible for the "optimization" had changed job in December 2014, well before the disaster, but still there was talk to sue him for damages. And it didn't go well with the upper echelons that it was "the last guy's fault" - it looked like a set-up for us to come up clean of the matter, and in the end, we remained in the doghouse for the rest of the year, and one of the team resigned at the end of that summer.
Ninety-nine times out of one hundred, the "86400 hack" will work flawlessly. (For example in PHP, strtotime() will ignore DST, and report that between the midnights of the last Saturday of October and that of the following Monday, exactly 2 * 24 * 60 * 60 seconds have passed, even if that is plainly not true... and two wrongs will happily make one right).
This, ladies and gentlemen, was one instance when it did not. As with air-bags and seat belts, you will perhaps never really need the complexity (and ease of use) of DateTime or Carbon. But the day when you might (or the day when you'll have to prove you thought about this) will come as a thief in the night (likely at 02:00 some Sunday in October). Be prepared.
Convert your dates to unix timestamps, then substract one from the another. That will give you the difference in seconds, which you divide by 86400 (amount of seconds in a day) to give you an approximate amount of days in that range.
If your dates are in format 25.1.2010, 01/25/2010 or 2010-01-25, you can use the strtotime function:
$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');
$days_between = ceil(abs($end - $start) / 86400);
Using ceil rounds the amount of days up to the next full day. Use floor instead if you want to get the amount of full days between those two dates.
If your dates are already in unix timestamp format, you can skip the converting and just do the $days_between part. For more exotic date formats, you might have to do some custom parsing to get it right.
Easy to using date_diff
$from=date_create(date('Y-m-d'));
$to=date_create("2013-03-15");
$diff=date_diff($to,$from);
print_r($diff);
echo $diff->format('%R%a days');
See more at: https://blog.devgenius.io/how-to-find-the-number-of-days-between-two-dates-in-php-1404748b1e84
Object oriented style:
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');
Procedural style:
$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%a days');
Used this :)
$days = (strtotime($endDate) - strtotime($startDate)) / (60 * 60 * 24);
print $days;
Now it works
Well, the selected answer is not the most correct one because it will fail outside UTC.
Depending on the timezone (list) there could be time adjustments creating days "without" 24 hours, and this will make the calculation (60*60*24) fail.
Here it is an example of it:
date_default_timezone_set('europe/lisbon');
$time1 = strtotime('2016-03-27');
$time2 = strtotime('2016-03-29');
echo floor( ($time2-$time1) /(60*60*24));
^-- the output will be **1**
So the correct solution will be using DateTime
date_default_timezone_set('europe/lisbon');
$date1 = new DateTime("2016-03-27");
$date2 = new DateTime("2016-03-29");
echo $date2->diff($date1)->format("%a");
^-- the output will be **2**
You can find dates simply by
<?php
$start = date_create('1988-08-10');
$end = date_create(); // Current time and date
$diff = date_diff( $start, $end );
echo 'The difference is ';
echo $diff->y . ' years, ';
echo $diff->m . ' months, ';
echo $diff->d . ' days, ';
echo $diff->h . ' hours, ';
echo $diff->i . ' minutes, ';
echo $diff->s . ' seconds';
// Output: The difference is 28 years, 5 months, 19 days, 20 hours, 34 minutes, 36 seconds
echo 'The difference in days : ' . $diff->days;
// Output: The difference in days : 10398
Calculate the difference between two dates:
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
Output:
+272 days
The date_diff() function returns the difference between two DateTime objects.
$start = '2013-09-08';
$end = '2013-09-15';
$diff = (strtotime($end)- strtotime($start))/24/3600;
echo $diff;
I'm using Carbon in my composer projects for this and similar purposes.
It'd be as easy as this:
$dt = Carbon::parse('2010-01-01');
echo $dt->diffInDays(Carbon::now());
You can try the code below:
$dt1 = strtotime("2019-12-12"); //Enter your first date
$dt2 = strtotime("12-12-2020"); //Enter your second date
echo abs(($dt1 - $dt2) / (60 * 60 * 24));
number of days between two dates in PHP
function dateDiff($date1, $date2) //days find function
{
$diff = strtotime($date2) - strtotime($date1);
return abs(round($diff / 86400));
}
//start day
$date1 = "11-10-2018";
// end day
$date2 = "31-10-2018";
// call the days find fun store to variable
$dateDiff = dateDiff($date1, $date2);
echo "Difference between two dates: ". $dateDiff . " Days ";
If you have the times in seconds (I.E. unix time stamp) , then you can simply subtract the times and divide by 86400 (seconds per day)
$datediff = floor(strtotime($date1)/(60*60*24)) - floor(strtotime($date2)/(60*60*24));
and, if needed:
$datediff=abs($datediff);
Easiest way to find the days difference between two dates
$date1 = strtotime("2019-05-25");
$date2 = strtotime("2010-06-23");
$date_difference = $date2 - $date1;
$result = round( $date_difference / (60 * 60 * 24) );
echo $result;
$diff = strtotime('2019-11-25') - strtotime('2019-11-10');
echo abs(round($diff / 86400));
function howManyDays($startDate,$endDate) {
$date1 = strtotime($startDate." 0:00:00");
$date2 = strtotime($endDate." 23:59:59");
$res = (int)(($date2-$date1)/86400);
return $res;
}
If you want to echo all days between the start and end date, I came up with this :
$startdatum = $_POST['start']; // starting date
$einddatum = $_POST['eind']; // end date
$now = strtotime($startdatum);
$your_date = strtotime($einddatum);
$datediff = $your_date - $now;
$number = floor($datediff/(60*60*24));
for($i=0;$i <= $number; $i++)
{
echo date('d-m-Y' ,strtotime("+".$i." day"))."<br>";
}
This code worked for me and tested with PHP 8 version :
function numberOfDays($startDate, $endDate)
{
//1) converting dates to timestamps
$startSeconds = strtotime($startDate);
$endSeconds = strtotime($endDate);
//2) Calculating the difference in timestamps
$diffSeconds = $startSeconds - $endSeconds;
//3) converting timestamps to days
$days=round($diffSeconds / 86400);
/* note :
1 day = 24 hours
24 * 60 * 60 = 86400 seconds
*/
//4) printing the number of days
printf("Difference between two dates: ". abs($days) . " Days ");
return abs($days);
}
Here is my improved version which shows 1 Year(s) 2 Month(s) 25 day(s) if the 2nd parameter is passed.
class App_Sandbox_String_Util {
/**
* Usage: App_Sandbox_String_Util::getDateDiff();
* #param int $your_date timestamp
* #param bool $hr human readable. e.g. 1 year(s) 2 day(s)
* #see http://stackoverflow.com/questions/2040560/finding-the-number-of-days-between-two-dates
* #see http://qSandbox.com
*/
static public function getDateDiff($your_date, $hr = 0) {
$now = time(); // or your date as well
$datediff = $now - $your_date;
$days = floor( $datediff / ( 3600 * 24 ) );
$label = '';
if ($hr) {
if ($days >= 365) { // over a year
$years = floor($days / 365);
$label .= $years . ' Year(s)';
$days -= 365 * $years;
}
if ($days) {
$months = floor( $days / 30 );
$label .= ' ' . $months . ' Month(s)';
$days -= 30 * $months;
}
if ($days) {
$label .= ' ' . $days . ' day(s)';
}
} else {
$label = $days;
}
return $label;
}
}
$early_start_date = date2sql($_POST['early_leave_date']);
$date = new DateTime($early_start_date);
$date->modify('+1 day');
$date_a = new DateTime($early_start_date . ' ' . $_POST['start_hr'] . ':' . $_POST['start_mm']);
$date_b = new DateTime($date->format('Y-m-d') . ' ' . $_POST['end_hr'] . ':' . $_POST['end_mm']);
$interval = date_diff($date_a, $date_b);
$time = $interval->format('%h:%i');
$parsed = date_parse($time);
$seconds = $parsed['hour'] * 3600 + $parsed['minute'] * 60;
// display_error($seconds);
$second3 = $employee_information['shift'] * 60 * 60;
if ($second3 < $seconds)
display_error(_('Leave time can not be greater than shift time.Please try again........'));
set_focus('start_hr');
set_focus('end_hr');
return FALSE;
}
<?php
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
?>
used the above code very simple. Thanks.
function get_daydiff($end_date,$today)
{
if($today=='')
{
$today=date('Y-m-d');
}
$str = floor(strtotime($end_date)/(60*60*24)) - floor(strtotime($today)/(60*60*24));
return $str;
}
$d1 = "2018-12-31";
$d2 = "2018-06-06";
echo get_daydiff($d1, $d2);
Using this simple function. Declare function
<?php
function dateDiff($firstDate,$secondDate){
$firstDate = strtotime($firstDate);
$secondDate = strtotime($secondDate);
$datediff = $firstDate - $secondDate;
$output = round($datediff / (60 * 60 * 24));
return $output;
}
?>
and call this function like this where you want
<?php
echo dateDiff("2018-01-01","2018-12-31");
// OR
$firstDate = "2018-01-01";
$secondDate = "2018-01-01";
echo dateDiff($firstDate,$secondDate);
?>
// Change this to the day in the future
$day = 15;
// Change this to the month in the future
$month = 11;
// Change this to the year in the future
$year = 2012;
// $days is the number of days between now and the date in the future
$days = (int)((mktime (0,0,0,$month,$day,$year) - time(void))/86400);
echo "There are $days days until $day/$month/$year";
If you are using MySql
function daysSince($date, $date2){
$q = "SELECT DATEDIFF('$date','$date2') AS days;";
$result = execQ($q);
$row = mysql_fetch_array($result,MYSQL_BOTH);
return ($row[0]);
}
function execQ($q){
$result = mysql_query( $q);
if(!$result){echo ('Database error execQ' . mysql_error());echo $q;}
return $result;
}
Try using Carbon
$d1 = \Carbon\Carbon::now()->subDays(92);
$d2 = \Carbon\Carbon::now()->subDays(10);
$days_btw = $d1->diffInDays($d2);
Also you can use
\Carbon\Carbon::parse('')
to create an object of Carbon date using given timestamp string.

Failing to check if time is in the past using strtotime

I am trying to check if a certain time is in the past. Solution 1 works but the solutions 2 and 3 using strtotime do not. Any ideas why the strtotime solutions fail with this date when they work fine when the date is not that distant (f.ex. using 27.05.2035 works)?
<?php
$date = "27.05.2045";
$hour = "22";
$min = "15";
// 1. This one works
$datetime = DateTime::createFromFormat('d.m.Y H:i', $date.' '.$hour.':'.$min);
$now = new DateTime();
if ($datetime < $now)
{
echo "Datetime is in the past";
}
else if ($datetime > $now)
{
echo "Datetime is in the future";
}
// 2. Does not work
if (time() > strtotime($date.' '.$hour.':'.$min))
{
echo "Datetime is in the past (strtotime)";
}
else if (time() < strtotime($date.' '.$hour.':'.$min))
{
echo "Datetime is in the future (strtotime)";
}
// 3. Using another date format but still does not work
$array = explode('.', $date);
$date_converted = $array[2].'-'.$array[1].'-'.$array[0];
if (time() > strtotime($date_converted.' '.$hour.':'.$min))
{
echo "Datetime is in the past (strtotime with converted date)";
}
else if (time() < strtotime($date_converted.' '.$hour.':'.$min))
{
echo "Datetime is in the future (strtotime with converted date)";
}
?>
The 32 bit integer maximum makes it impossible to represent dates past 19 January 2038.
The solution would be to either:
Use DateTime objects, which do not represent dates using the number of seconds passed since 1970, but using a field for each time unit.
Use the 64-bit version of PHP, where the maximum integer is much higher.
See The 2038 Year Problem for more details.

Need to add number of months in date

I need a method for adding some number of months to any date in PHP. I know how to do this in MySQL but not in PHP. Here's my attempt:
MySQL:
SELECT DATE_ADD( '2011-12-29', INTERVAL 2
MONTH ) // Output "2012-02-29"
SELECT DATE_ADD( '2011-12-30', INTERVAL 2
MONTH ) // output "2012-02-29"
SELECT DATE_ADD( '2011-12-31', INTERVAL 2
MONTH ) // output "2012-02-29"
PHP:
$date = date_create('2011-12-29');
$date->modify("+1 month");
echo $date->format("Y-m-d");
// Output is "2012-01-29" -- this is correct
$date = date_create('2011-12-30');
$date->modify("+2 month");
echo $date->format("Y-m-d");
// Output is "2012-03-01" -- I need the answer like "2012-02-29"
$date = date_create('2011-12-31');
$date->modify("+2 month");
echo $date->format("Y-m-d");
// Output is "2012-03-02" -- I need the answer like "2012-02-29"
The MySQL output is correct. I need the same output in PHP.
If you use PHP5 >= 5.3, all you need to do is use
$date->modify("last day of +2 months");
as suggested in other answers. But if you use 5.2 you could try altering your code like this:
Class DateTimeM Extends DateTime
{
public function modify ($modify)
{
$day = $this->format ('d');
$buf = new DateTime ($this->format ('Y-m-01\TH:i:sO'));
$buf->modify ($modify);
if ($day > $buf->format ('t'))
{
$this->setDate ($buf->format ('Y'), $buf->format ('m'), $buf->format ('t'));
}
else
{
$this->setDate ($buf->format ('Y'), $buf->format ('m'), $day);
}
$this->setTime ($buf->format ('H'), $buf->format ('i'), $buf->format ('s'));
return $this;
}
}
$date = new DateTimeM ('2011-12-29');
$date->modify("+2 month");
echo $date->format("Y-m-d");
I suggest adding the class definition to a separate file and require_once() it. Switch from date_create() to using the new class's object constructor. The new class's modify() method will modify the date using the first day of the original given month instead of the last and check if the original given day of month is larger than the new month's number of days.
A benefit of this approach is that it will work for say $date->modify ('2 year 2 month') as well.
Here's a solution that might do the job for you:
function addMonths(DateTime $date, $months) {
$last = clone $date;
$last = $last->modify("last day of +$months months")->getTimestamp();
$default = clone $date;
$default = $default->modify("+$months months")->getTimestamp();
return $date->setTimestamp(min($last, $default));
}
$date = new DateTime('2011-12-31');
$laterDate = addMonths($date, 2);
This will work regardless of which day of the month you start with.
Hope it surely helps you.
I just try with adding days instead of adding months
$MonthAdded = strtotime("+60 days",strtotime('2011-12-31'));
echo "After adding month: ".date('Y-m-d', $MonthAdded)."<br>";
Output:
After adding month: 2012-02-29
Read the link Dagon posted in the comments to your question. Extrapolating on the answer there, I tried this and it works:
$d = new DateTime("2011-12-31");
$d->modify("last day of +2 months");
echo $d->format("Y-m-d");
// result is 2012-02-29
$d = new DateTime("2012-12-31");
$d->modify("last day of +2 months");
echo $d->format("Y-m-d");
// result is 2013-02-28

Finding the number of days between two dates

How to find number of days between two dates using PHP?
$now = time(); // or your date as well
$your_date = strtotime("2010-01-31");
$datediff = $now - $your_date;
echo round($datediff / (60 * 60 * 24));
If you're using PHP 5.3 >, this is by far the most accurate way of calculating the absolute difference:
$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");
$abs_diff = $later->diff($earlier)->format("%a"); //3
If you need a relative (signed) number of days, use this instead:
$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");
$pos_diff = $earlier->diff($later)->format("%r%a"); //3
$neg_diff = $later->diff($earlier)->format("%r%a"); //-3
More on php's DateInterval format can be found here: https://www.php.net/manual/en/dateinterval.format.php
From PHP Version 5.3 and up, new date/time functions have been added to get difference:
$datetime1 = new DateTime("2010-06-20");
$datetime2 = new DateTime("2011-06-22");
$difference = $datetime1->diff($datetime2);
echo 'Difference: '.$difference->y.' years, '
.$difference->m.' months, '
.$difference->d.' days';
print_r($difference);
Result as below:
Difference: 1 years, 0 months, 2 days
DateInterval Object
(
[y] => 1
[m] => 0
[d] => 2
[h] => 0
[i] => 0
[s] => 0
[invert] => 0
[days] => 367
)
Hope it helps !
TL;DR do not use UNIX timestamps. Do not use time(). If you do, be prepared should its 98.0825% reliability fail you. Use DateTime (or Carbon).
The correct answer is the one given by Saksham Gupta (other answers are also correct):
$date1 = new DateTime('2010-07-06');
$date2 = new DateTime('2010-07-09');
$days = $date2->diff($date1)->format('%a');
Or procedurally as a one-liner:
/**
* Number of days between two dates.
*
* #param date $dt1 First date
* #param date $dt2 Second date
* #return int
*/
function daysBetween($dt1, $dt2) {
return date_diff(
date_create($dt2),
date_create($dt1)
)->format('%a');
}
With a caveat: the '%a' seems to indicate the absolute number of days. If you want it as a signed integer, i.e. negative when the second date is before the first, then you need to use the '%r' prefix (i.e. format('%r%a')).
If you really must use UNIX timestamps, set the time zone to GMT to avoid most of the pitfalls detailed below.
Long answer: why dividing by 24*60*60 (aka 86400) is unsafe
Most of the answers using UNIX timestamps (and 86400 to convert that to days) make two assumptions that, put together, can lead to scenarios with wrong results and subtle bugs that may be difficult to track, and arise even days, weeks or months after a successful deployment. It's not that the solution doesn't work - it works. Today. But it might stop working tomorrow.
First mistake is not considering that when asked, "How many days passed since yesterday?", a computer might truthfully answer zero if between the present and the instant indicated by "yesterday" less than one whole day has passed.
Usually when converting a "day" to a UNIX timestamp, what is obtained is the timestamp for the midnight of that particular day.
So between the midnights of October 1st and October 15th, fifteen days have elapsed. But between 13:00 of October 1st and 14:55 of October 15th, fifteen days minus 5 minutes have elapsed, and most solutions using floor() or doing implicit integer conversion will report one day less than expected.
So, "how many days ago was Y-m-d H:i:s"? will yield the wrong answer.
The second mistake is equating one day to 86400 seconds. This is almost always true - it happens often enough to overlook the times it doesn't. But the distance in seconds between two consecutive midnights is surely not 86400 at least twice a year when daylight saving time comes into play. Comparing two dates across a DST boundary will yield the wrong answer.
So even if you use the "hack" of forcing all date timestamps to a fixed hour, say midnight (this is also done implicitly by various languages and frameworks when you only specify day-month-year and not also hour-minute-second; same happens with DATE type in databases such as MySQL), the widely used formula
FLOOR((unix_timestamp(DATE2) - unix_timestamp(DATE1)) / 86400)
or
floor((time() - strtotime($somedate)) / 86400)
will return, say, 17 when DATE1 and DATE2 are in the same DST segment of the year; but even if the hour:minute:second part is identical, the argument might be 17.042, and worse still, 16.958 when they are in different DST segments and the time zone is DST-aware. The use of floor() or any implicit truncation to integer will then convert what should have been a 17 to a 16. In other circumstances, expressions like "$days > 17" will return true for 17.042, even if this will look as if the elapsed day count is 18.
And things grow even uglier since such code is not portable across platforms, because some of them may apply leap seconds and some might not. On those platforms that do, the difference between two dates will not be 86400 but 86401, or maybe 86399. So code that worked in May and actually passed all tests will break next June when 12.99999 days are considered 12 days instead of 13. Two dates that worked in 2015 will not work in 2017 -- the same dates, and neither year is a leap year. And between 2018-03-01 and 2017-03-01, on those platforms that care, 366 days will have passed instead of 365, making 2018 a leap year (which it is not).
So if you really want to use UNIX timestamps:
use round() function wisely, not floor().
as an alternative, do not calculate differences between D1-M1-YYY1 and D2-M2-YYY2. Those dates will be really considered as D1-M1-YYY1 00:00:00 and D2-M2-YYY2 00:00:00. Rather, convert between D1-M1-YYY1 22:30:00 and D2-M2-YYY2 04:30:00. You will always get a remainder of about twenty hours. This may become twenty-one hours or nineteen, and maybe eighteen hours, fifty-nine minutes thirty-six seconds. No matter. It is a large margin which will stay there and stay positive for the foreseeable future. Now you can truncate it with floor() in safety.
The correct solution though, to avoid magic constants, rounding kludges and a maintenance debt, is to
use a time library (Datetime, Carbon, whatever); don't roll your own
write comprehensive test cases using really evil date choices - across DST boundaries, across leap years, across leap seconds, and so on, as well as commonplace dates. Ideally (calls to datetime are fast!) generate four whole years' (and one day) worth of dates by assembling them from strings, sequentially, and ensure that the difference between the first day and the day being tested increases steadily by one. This will ensure that if anything changes in the low-level routines and leap seconds fixes try to wreak havoc, at least you will know.
run those tests regularly together with the rest of the test suite. They're a matter of milliseconds, and may save you literally hours of head scratching.
Whatever your solution, test it!
The function funcdiff below implements one of the solutions (as it happens, the accepted one) in a real world scenario.
<?php
$tz = 'Europe/Rome';
$yearFrom = 1980;
$yearTo = 2020;
$verbose = false;
function funcdiff($date2, $date1) {
$now = strtotime($date2);
$your_date = strtotime($date1);
$datediff = $now - $your_date;
return floor($datediff / (60 * 60 * 24));
}
########################################
date_default_timezone_set($tz);
$failures = 0;
$tests = 0;
$dom = array ( 0, 31, 28, 31, 30,
31, 30, 31, 31,
30, 31, 30, 31 );
(array_sum($dom) === 365) || die("Thirty days hath September...");
$last = array();
for ($year = $yearFrom; $year < $yearTo; $year++) {
$dom[2] = 28;
// Apply leap year rules.
if ($year % 4 === 0) { $dom[2] = 29; }
if ($year % 100 === 0) { $dom[2] = 28; }
if ($year % 400 === 0) { $dom[2] = 29; }
for ($month = 1; $month <= 12; $month ++) {
for ($day = 1; $day <= $dom[$month]; $day++) {
$date = sprintf("%04d-%02d-%02d", $year, $month, $day);
if (count($last) === 7) {
$tests ++;
$diff = funcdiff($date, $test = array_shift($last));
if ((double)$diff !== (double)7) {
$failures ++;
if ($verbose) {
print "There seem to be {$diff} days between {$date} and {$test}\n";
}
}
}
$last[] = $date;
}
}
}
print "This function failed {$failures} of its {$tests} tests";
print " between {$yearFrom} and {$yearTo}.\n";
The result is,
This function failed 280 of its 14603 tests
Horror Story: the cost of "saving time"
It all began in late 2014. An ingenious programmer decided to save several microseconds off a calculation that took about thirty seconds at most, by plugging in the infamous "(MidnightOfDateB-MidnightOfDateA)/86400" code in several places. It was so obvious an optimization that he did not even document it, and the optimization passed the integration tests and somehow lurked in the code for several months, all unnoticed.
This happened in a program that calculates the wages for several top-selling salesmen, the least of which has a frightful lot more clout than a whole humble five-people programmer team taken together. On March 28th, 2015, the summer time zone engaged, the bug struck -- and some of those guys got shortchanged one whole day of fat commissions. To make things worse, most of them did not work on Sundays and, being near the end of the month, used that day to catch up with their invoicing. They were definitely not amused.
Infinitely worse, they lost the (already very little) faith they had in the program not being designed to surreptitiously shaft them, and pretended - and obtained - a complete, detailed code review with test cases ran and commented in layman's terms (plus a lot of red-carpet treatment in the following weeks).
What can I say: on the plus side, we got rid of a lot of technical debt, and were able to rewrite and refactor several pieces of a spaghetti mess that hearkened back to a COBOL infestation in the swinging '90s. The program undoubtedly runs better now, and there's a lot more debugging information to quickly zero in when anything looks fishy. I estimate that just this last one thing will save perhaps one or two man-days per month for the foreseeable future, so the disaster will have a silver, or even golden, lining.
On the minus side, the whole brouhaha costed the company about €200,000 up front - plus face, plus undoubtedly some bargaining power (and, hence, yet more money).
The guy responsible for the "optimization" had changed job in December 2014, well before the disaster, but still there was talk to sue him for damages. And it didn't go well with the upper echelons that it was "the last guy's fault" - it looked like a set-up for us to come up clean of the matter, and in the end, we remained in the doghouse for the rest of the year, and one of the team resigned at the end of that summer.
Ninety-nine times out of one hundred, the "86400 hack" will work flawlessly. (For example in PHP, strtotime() will ignore DST, and report that between the midnights of the last Saturday of October and that of the following Monday, exactly 2 * 24 * 60 * 60 seconds have passed, even if that is plainly not true... and two wrongs will happily make one right).
This, ladies and gentlemen, was one instance when it did not. As with air-bags and seat belts, you will perhaps never really need the complexity (and ease of use) of DateTime or Carbon. But the day when you might (or the day when you'll have to prove you thought about this) will come as a thief in the night (likely at 02:00 some Sunday in October). Be prepared.
Convert your dates to unix timestamps, then substract one from the another. That will give you the difference in seconds, which you divide by 86400 (amount of seconds in a day) to give you an approximate amount of days in that range.
If your dates are in format 25.1.2010, 01/25/2010 or 2010-01-25, you can use the strtotime function:
$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');
$days_between = ceil(abs($end - $start) / 86400);
Using ceil rounds the amount of days up to the next full day. Use floor instead if you want to get the amount of full days between those two dates.
If your dates are already in unix timestamp format, you can skip the converting and just do the $days_between part. For more exotic date formats, you might have to do some custom parsing to get it right.
Easy to using date_diff
$from=date_create(date('Y-m-d'));
$to=date_create("2013-03-15");
$diff=date_diff($to,$from);
print_r($diff);
echo $diff->format('%R%a days');
See more at: https://blog.devgenius.io/how-to-find-the-number-of-days-between-two-dates-in-php-1404748b1e84
Object oriented style:
$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');
Procedural style:
$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%a days');
Used this :)
$days = (strtotime($endDate) - strtotime($startDate)) / (60 * 60 * 24);
print $days;
Now it works
Well, the selected answer is not the most correct one because it will fail outside UTC.
Depending on the timezone (list) there could be time adjustments creating days "without" 24 hours, and this will make the calculation (60*60*24) fail.
Here it is an example of it:
date_default_timezone_set('europe/lisbon');
$time1 = strtotime('2016-03-27');
$time2 = strtotime('2016-03-29');
echo floor( ($time2-$time1) /(60*60*24));
^-- the output will be **1**
So the correct solution will be using DateTime
date_default_timezone_set('europe/lisbon');
$date1 = new DateTime("2016-03-27");
$date2 = new DateTime("2016-03-29");
echo $date2->diff($date1)->format("%a");
^-- the output will be **2**
You can find dates simply by
<?php
$start = date_create('1988-08-10');
$end = date_create(); // Current time and date
$diff = date_diff( $start, $end );
echo 'The difference is ';
echo $diff->y . ' years, ';
echo $diff->m . ' months, ';
echo $diff->d . ' days, ';
echo $diff->h . ' hours, ';
echo $diff->i . ' minutes, ';
echo $diff->s . ' seconds';
// Output: The difference is 28 years, 5 months, 19 days, 20 hours, 34 minutes, 36 seconds
echo 'The difference in days : ' . $diff->days;
// Output: The difference in days : 10398
Calculate the difference between two dates:
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
Output:
+272 days
The date_diff() function returns the difference between two DateTime objects.
$start = '2013-09-08';
$end = '2013-09-15';
$diff = (strtotime($end)- strtotime($start))/24/3600;
echo $diff;
I'm using Carbon in my composer projects for this and similar purposes.
It'd be as easy as this:
$dt = Carbon::parse('2010-01-01');
echo $dt->diffInDays(Carbon::now());
You can try the code below:
$dt1 = strtotime("2019-12-12"); //Enter your first date
$dt2 = strtotime("12-12-2020"); //Enter your second date
echo abs(($dt1 - $dt2) / (60 * 60 * 24));
number of days between two dates in PHP
function dateDiff($date1, $date2) //days find function
{
$diff = strtotime($date2) - strtotime($date1);
return abs(round($diff / 86400));
}
//start day
$date1 = "11-10-2018";
// end day
$date2 = "31-10-2018";
// call the days find fun store to variable
$dateDiff = dateDiff($date1, $date2);
echo "Difference between two dates: ". $dateDiff . " Days ";
If you have the times in seconds (I.E. unix time stamp) , then you can simply subtract the times and divide by 86400 (seconds per day)
$datediff = floor(strtotime($date1)/(60*60*24)) - floor(strtotime($date2)/(60*60*24));
and, if needed:
$datediff=abs($datediff);
Easiest way to find the days difference between two dates
$date1 = strtotime("2019-05-25");
$date2 = strtotime("2010-06-23");
$date_difference = $date2 - $date1;
$result = round( $date_difference / (60 * 60 * 24) );
echo $result;
$diff = strtotime('2019-11-25') - strtotime('2019-11-10');
echo abs(round($diff / 86400));
function howManyDays($startDate,$endDate) {
$date1 = strtotime($startDate." 0:00:00");
$date2 = strtotime($endDate." 23:59:59");
$res = (int)(($date2-$date1)/86400);
return $res;
}
If you want to echo all days between the start and end date, I came up with this :
$startdatum = $_POST['start']; // starting date
$einddatum = $_POST['eind']; // end date
$now = strtotime($startdatum);
$your_date = strtotime($einddatum);
$datediff = $your_date - $now;
$number = floor($datediff/(60*60*24));
for($i=0;$i <= $number; $i++)
{
echo date('d-m-Y' ,strtotime("+".$i." day"))."<br>";
}
This code worked for me and tested with PHP 8 version :
function numberOfDays($startDate, $endDate)
{
//1) converting dates to timestamps
$startSeconds = strtotime($startDate);
$endSeconds = strtotime($endDate);
//2) Calculating the difference in timestamps
$diffSeconds = $startSeconds - $endSeconds;
//3) converting timestamps to days
$days=round($diffSeconds / 86400);
/* note :
1 day = 24 hours
24 * 60 * 60 = 86400 seconds
*/
//4) printing the number of days
printf("Difference between two dates: ". abs($days) . " Days ");
return abs($days);
}
Here is my improved version which shows 1 Year(s) 2 Month(s) 25 day(s) if the 2nd parameter is passed.
class App_Sandbox_String_Util {
/**
* Usage: App_Sandbox_String_Util::getDateDiff();
* #param int $your_date timestamp
* #param bool $hr human readable. e.g. 1 year(s) 2 day(s)
* #see http://stackoverflow.com/questions/2040560/finding-the-number-of-days-between-two-dates
* #see http://qSandbox.com
*/
static public function getDateDiff($your_date, $hr = 0) {
$now = time(); // or your date as well
$datediff = $now - $your_date;
$days = floor( $datediff / ( 3600 * 24 ) );
$label = '';
if ($hr) {
if ($days >= 365) { // over a year
$years = floor($days / 365);
$label .= $years . ' Year(s)';
$days -= 365 * $years;
}
if ($days) {
$months = floor( $days / 30 );
$label .= ' ' . $months . ' Month(s)';
$days -= 30 * $months;
}
if ($days) {
$label .= ' ' . $days . ' day(s)';
}
} else {
$label = $days;
}
return $label;
}
}
$early_start_date = date2sql($_POST['early_leave_date']);
$date = new DateTime($early_start_date);
$date->modify('+1 day');
$date_a = new DateTime($early_start_date . ' ' . $_POST['start_hr'] . ':' . $_POST['start_mm']);
$date_b = new DateTime($date->format('Y-m-d') . ' ' . $_POST['end_hr'] . ':' . $_POST['end_mm']);
$interval = date_diff($date_a, $date_b);
$time = $interval->format('%h:%i');
$parsed = date_parse($time);
$seconds = $parsed['hour'] * 3600 + $parsed['minute'] * 60;
// display_error($seconds);
$second3 = $employee_information['shift'] * 60 * 60;
if ($second3 < $seconds)
display_error(_('Leave time can not be greater than shift time.Please try again........'));
set_focus('start_hr');
set_focus('end_hr');
return FALSE;
}
<?php
$date1=date_create("2013-03-15");
$date2=date_create("2013-12-12");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");
?>
used the above code very simple. Thanks.
function get_daydiff($end_date,$today)
{
if($today=='')
{
$today=date('Y-m-d');
}
$str = floor(strtotime($end_date)/(60*60*24)) - floor(strtotime($today)/(60*60*24));
return $str;
}
$d1 = "2018-12-31";
$d2 = "2018-06-06";
echo get_daydiff($d1, $d2);
Using this simple function. Declare function
<?php
function dateDiff($firstDate,$secondDate){
$firstDate = strtotime($firstDate);
$secondDate = strtotime($secondDate);
$datediff = $firstDate - $secondDate;
$output = round($datediff / (60 * 60 * 24));
return $output;
}
?>
and call this function like this where you want
<?php
echo dateDiff("2018-01-01","2018-12-31");
// OR
$firstDate = "2018-01-01";
$secondDate = "2018-01-01";
echo dateDiff($firstDate,$secondDate);
?>
// Change this to the day in the future
$day = 15;
// Change this to the month in the future
$month = 11;
// Change this to the year in the future
$year = 2012;
// $days is the number of days between now and the date in the future
$days = (int)((mktime (0,0,0,$month,$day,$year) - time(void))/86400);
echo "There are $days days until $day/$month/$year";
If you are using MySql
function daysSince($date, $date2){
$q = "SELECT DATEDIFF('$date','$date2') AS days;";
$result = execQ($q);
$row = mysql_fetch_array($result,MYSQL_BOTH);
return ($row[0]);
}
function execQ($q){
$result = mysql_query( $q);
if(!$result){echo ('Database error execQ' . mysql_error());echo $q;}
return $result;
}
Try using Carbon
$d1 = \Carbon\Carbon::now()->subDays(92);
$d2 = \Carbon\Carbon::now()->subDays(10);
$days_btw = $d1->diffInDays($d2);
Also you can use
\Carbon\Carbon::parse('')
to create an object of Carbon date using given timestamp string.

performing datetime related operations in PHP

How do you actually perform datetime operations such as adding date, finding difference, find out how many days excluding weekends in an interval? I personally started to pass some of these operations to my postgresql dbms as typically I would only need to issue one sql statement to obtain an answer, however, to do it in PHP way I would have to write a lot more code that means more chances for errors to occur...
Are there any libraries in PHP that does datetime operation in a way that don't require a lot of code? that beats sql in a situation where 'Given two dates, how many workdays are there between the two dates? Implement in either SQL, or $pet_lang' that is solved by making this query?
SELECT COUNT(*) AS total_days
FROM (SELECT date '2008-8-26' + generate_series(0,
(date '2008-9-1' - date '2008-8-26')) AS all_days) AS calendar
WHERE EXTRACT(isodow FROM all_days) < 6;
While for most datetime operations I would normally convert to Unixtime and perform addition subtraction etc. on the Unixtime integer, you may want to look at the Zend framework Zend_Date class.
This has a lot of the functionality you describe. Although Zend is billed as a "framework" it works exceptionally well as a class library to pick and chose elements from. We routinely include it in projects and then just pull in bits as and when we need them.
PHP5+'s DateTime object is useful because it is leap time and
daylight savings aware, but it needs some extension to really
solve the problem. I wrote the following to solve a similar problem.
The find_WeekdaysFromThisTo() method is brute-force, but it works reasonably quickly if your time span is less than 2 years.
$tryme = new Extended_DateTime('2007-8-26');
$newer = new Extended_DateTime('2008-9-1');
print 'Weekdays From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-d').': '.$tryme -> find_WeekdaysFromThisTo($newer) ."\n";
/* Output: Weekdays From 2007-08-26 To 2008-09-01: 265 */
print 'All Days From '.$tryme->format('Y-m-d').' To '.$newer->format('Y-m-d').': '.$tryme -> find_AllDaysFromThisTo($newer) ."\n";
/* Output: All Days From 2007-08-26 To 2008-09-01: 371 */
$timefrom = $tryme->find_TimeFromThisTo($newer);
print 'Between '.$tryme->format('Y-m-d').' and '.$newer->format('Y-m-d').' there are '.
$timefrom['years'].' years, '.$timefrom['months'].' months, and '.$timefrom['days'].
' days.'."\n";
/* Output: Between 2007-08-26 and 2008-09-01 there are 1 years, 0 months, and 5 days. */
class Extended_DateTime extends DateTime {
public function find_TimeFromThisTo($newer) {
$timefrom = array('years'=>0,'months'=>0,'days'=>0);
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$timefrom['years'] = $this->find_YearsFromThisTo($testnewer);
$mod = '-'.$timefrom['years'].' years';
$testnewer -> modify($mod);
$timefrom['months'] = $this->find_MonthsFromThisTo($testnewer);
$mod = '-'.$timefrom['months'].' months';
$testnewer -> modify($mod);
$timefrom['days'] = $this->find_AllDaysFromThisTo($testnewer);
return $timefrom;
} // end function find_TimeFromThisTo
public function find_YearsFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 year');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 year');
}
return $count;
} // end function find_YearsFromThisTo
public function find_MonthsFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 month');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 month');
}
return $count;
} // end function find_MonthsFromThisTo
public function find_AllDaysFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 day');
while ( $this->format('U') < $testnewer->format('U')) {
$count ++;
$testnewer -> modify ('-1 day');
}
return $count;
} // end function find_AllDaysFromThisTo
public function find_WeekdaysFromThisTo($newer) {
/*
If the passed is:
not an object, not of class DateTime or one of its children,
or not larger (after) $this
return false
*/
if (!is_object($newer) || !($newer instanceof DateTime) || $newer->format('U') < $this->format('U'))
return FALSE;
$count = 0;
// Clone because we're using modify(), which will destroy the object that was passed in by reference
$testnewer = clone $newer;
$testnewer -> modify ('-1 day');
while ( $this->format('U') < $testnewer->format('U')) {
// If the calculated day is not Sunday or Saturday, count this day
if ($testnewer->format('w') != '0' && $testnewer->format('w') != '6')
$count ++;
$testnewer -> modify ('-1 day');
}
return $count;
} // end function find_WeekdaysFromThisTo
public function set_Day($newday) {
if (is_int($newday) && $newday > 0 && $newday < 32 && checkdate($this->format('m'),$newday,$this->format('Y')))
$this->setDate($this->format('Y'),$this->format('m'),$newday);
} // end function set_Day
public function set_Month($newmonth) {
if (is_int($newmonth) && $newmonth > 0 && $newmonth < 13)
$this->setDate($this->format('Y'),$newmonth,$this->format('d'));
} // end function set_Month
public function set_Year($newyear) {
if (is_int($newyear) && $newyear > 0)
$this->setDate($newyear,$this->format('m'),$this->format('d'));
} // end function set_Year
} // end class Extended_DateTime
strtotime() is useful but it does have some odd behaviors that can pop-up from time to time if you are not just using it to convert a formatted date/time string.
things like "+1 month" or "-3 days" can sometimes not give you what you expect it to output.
For adding a date, you can use the method DateTime::add (Adds an amount of days, months, years, hours, minutes and seconds to a DateTime object), available from php 5.3.0 onwards.
To find the difference between two dates, there's the DateTime::diff method; but there doesn't seem to be a method for counting the working days between two dates.
PEAR::Date looks like it might have some useful functionality.
PEAR::Calendar might also be useful.
The easiest method is to use a timestamp, representing the number of seconds since January 1, 2008. With a timestamp type, you can do things like...
now = time();
tomorrow = now + 24 * 60 * 60; // 24 hours * 60 minutes * 60 seconds
Check out the documentation for time(), date() and mktime() on the php web pages. Those are the three methods that I tend to use the most frequently.
You can use a combination of strtotime, mktime and date todo the arithmetic
Here is an example which uses a combo todo some arithmetic http://rushi.wordpress.com/2008/04/13/php-print-out-age-of-date-in-words/ I'll reproduce the code here for simplicity
if ($timestamp_diff < (60*60*24*7)) {
echo floor($timestamp_diff/60/60/24)." Days";
} elseif ($timestamp_diff > (60*60*24*7*4)) {
echo floor($timestamp_diff/60/60/24/7)." Weeks";
} else {
$total_months = $months = floor($timestamp_diff/60/60/24/30);
if($months >= 12) {
$months = ($total_months % 12);
$years = ($total_months - $months)/12;
echo $years . " Years ";
}
if($months > 0)
echo $months . " Months";
}
?>
#Rushi I don't like strtotime() personally.. i don't know why but i discovered this morning that passing a string like this '2008-09-11 9:5 AM' to strtotime returns a false...
I don't think the code you provided solve the example problem 'Given two dates, how many workdays are there between the two dates? Implement in either SQL, or $pet_lang' and I haven't consider if I have a list of public holiday...
You can get number of days between two dates like this:
$days = (strtotime("2008-09-10") - strtotime("2008-09-12")) / (60 * 60 * 24);
And you can make function something like that (I don't have php installed in my work computer so i can't guarantee syntax is 100% correct)
function isWorkDay($date)
{
// check if workday and return true if so
}
function numberOfWorkDays($startdate, $enddate)
{
$workdays = 0;
$tmp = strtotime($startdate);
$end = strtotime($enddate);
while($tmp <= $end)
{
if ( isWorkDay( date("Y-m-d",$tmp) ) ) $workdays++;
$tmp += 60*60*24;
}
return $workdays;
}
If you don't like strtotime and you always have date in same format you can use explode function like
list($year, $month, day) = explode("-", $date);
I would strongly recommend using PHP 5.2's DateTime objects, rather than using UNIX timestamps, when doing date calculations. When you use the PHP date functions that return UNIX timestamps, you have a very limited range to work with (e.g. nothing before 1970).
If you have a look at http://php.net/date , you will find some examples of using mktime() to perform operations.
A simple example would be to workout what tomorrows date would be. You can do that by simply adding 1, to the day value in mktime() as follows:
$tomorrow = date("Y-m-d", mktime(0, 0, 0, date("m"), date("d") + 1, date("Y")));
So here, you will receive a date in the form of YYYY-MM-DD containing tomorrows date. You can also subtract days by simply replacing '+' with '-'. mktime() makes life a lot easier, and saves you from having to do nested if statements and other such troublesome coding.
to get working days/holidays, postgresql CTE ftw -- see http://osssmb.wordpress.com/2009/12/02/business-days-working-days-sql-for-postgres-2/

Categories