I am trying to find the date not less than 18 years, I tried this following code, but its not working for me.
// validate birthday
function validateAge($then, $min)
{
// $then will first be a string-date
$then = strtotime($then);
echo "<br>";
echo 'test1-';
var_dump( $then );
exit;
//The age to be over, over +18
$min = strtotime('+18 years', $then);
if(time() < $min) {
die('Not 18');
}
}
$res = validateAge('2016-02-29', $min = 18);
var_dump($res);
I fyou see the above question, you can see that, date is not valid, even if i pass the wrong date, its shows the $then = strtotime($then);
var_dump($then) show the int
my question is, how its printing the timestamp, event if we passing the invalid date.
Your logic is correct. Remove die, exit and echo which is not needed
function validateAge($then, $min)
{
// $then will first be a string-date
$then = strtotime($then);
//The age to be more then min years
$min = strtotime('+'. $min . ' years', $then);
return time() > $min;
}
$res = validateAge('2016-02-29', $min = 18);
echo $res ? 'O\'key' : "Not $min years";
demo
Try maybe something like this
function compareAge($date,$min=18)
{
$strdate = strtotime($date);
$curdate = strtotime("today");
$datefin=date("Ymd",$curdate)-date("Ymd",$strdate);
$age=substr($datefin,0,strlen($datefin)-4);
return $age>=$min;
}
var_dump(compareAge("2013-05-13"));
DEMO
you could use this method:
public function validateAge($then)
{
$then= date_create($then);
$now = date_create("now");
$diff = $now->diff($then);
if ($diff->y > 18)
{
die('not 18');
}
}
Duplicate:
Calculating number of years between 2 dates in PHP
use the datetime object to save all sorts of pain. Its so much more simple.
function validateAge(DateTime $then, $min = 18)
{
$now = new DateTime();
$minimum = clone($now); // you could just modify now, but this is simpler to explain
$minimum->modify("-$min years");
if($then < $minimum) {
return false;
}
return true;
}
echo validateAge(new DateTime('1-1-1997')) ? 'true' : 'false'; // returns false
echo validateAge(new DateTime('1-1-1999')) ? 'true' : 'false'; // returns true
see example
Wow, so many try-hards.
In case you like is simple:
<?php
function validateAge($date) {
return date_create('18 years ago') > date_create($date);
}
var_dump(
validateAge('2010-10-05'),
validateAge('1992-09-02')
);
OUTPUT
bool(false)
bool(true)
Play with me on 3v4l.org
Edit: Also works with the $min parameter:
<?php
function validateAge($date, $min) {
return date_create("$min years ago") > date_create($date);
}
var_dump(
validateAge('2010-10-05', 18),
validateAge('1992-09-02', 18)
);
I have an array of random dates (not coming from MySQL). I need to group them by the week as Week1, Week2, and so on upto Week5.
What I have is this:
$dates = array('2015-09-01','2015-09-05','2015-09-06','2015-09-15','2015-09-17');
What I need is a function to get the week number of the month by providing the date.
I know that I can get the weeknumber by doing
date('W',strtotime('2015-09-01'));
but this week number is the number between year (1-52) but I need the week number of the month only, e.g. in Sep 2015 there are 5 weeks:
Week1 = 1st to 5th
Week2 = 6th to 12th
Week3 = 13th to 19th
Week4 = 20th to 26th
Week5 = 27th to 30th
I should be able to get the week Week1 by just providing the date
e.g.
$weekNumber = getWeekNumber('2015-09-01') //output 1;
$weekNumber = getWeekNumber('2015-09-17') //output 3;
I think this relationship should be true and come in handy:
Week of the month = Week of the year - Week of the year of first day of month + 1
We also need to make sure that "overlapping" weeks from the previous year are handeled correctly - if January 1st is in week 52 or 53, it should be counted as week 0. In a similar fashion, if a day in December is in the first week of the next year, it should be counted as 53. (Previous versions of this answer failed to do this properly.)
<?php
function weekOfMonth($date) {
//Get the first day of the month.
$firstOfMonth = strtotime(date("Y-m-01", $date));
//Apply above formula.
return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
}
function weekOfYear($date) {
$weekOfYear = intval(date("W", $date));
if (date('n', $date) == "1" && $weekOfYear > 51) {
// It's the last week of the previos year.
return 0;
}
else if (date('n', $date) == "12" && $weekOfYear == 1) {
// It's the first week of the next year.
return 53;
}
else {
// It's a "normal" week.
return $weekOfYear;
}
}
// A few test cases.
echo weekOfMonth(strtotime("2020-04-12")) . " "; // 2
echo weekOfMonth(strtotime("2020-12-31")) . " "; // 5
echo weekOfMonth(strtotime("2020-01-02")) . " "; // 1
echo weekOfMonth(strtotime("2021-01-28")) . " "; // 5
echo weekOfMonth(strtotime("2018-12-31")) . " "; // 6
To get weeks that starts with sunday, simply replace date("W", ...) with strftime("%U", ...).
You can use the function below, fully commented:
/**
* Returns the number of week in a month for the specified date.
*
* #param string $date
* #return int
*/
function weekOfMonth($date) {
// estract date parts
list($y, $m, $d) = explode('-', date('Y-m-d', strtotime($date)));
// current week, min 1
$w = 1;
// for each day since the start of the month
for ($i = 1; $i < $d; ++$i) {
// if that day was a sunday and is not the first day of month
if ($i > 1 && date('w', strtotime("$y-$m-$i")) == 0) {
// increment current week
++$w;
}
}
// now return
return $w;
}
The corect way is
function weekOfMonth($date) {
$firstOfMonth = date("Y-m-01", strtotime($date));
return intval(date("W", strtotime($date))) - intval(date("W", strtotime($firstOfMonth)));
}
I have created this function on my own, which seems to work correctly. In case somebody else have a better way of doing this, please share.. Here is what I have done.
function weekOfMonth($qDate) {
$dt = strtotime($qDate);
$day = date('j',$dt);
$month = date('m',$dt);
$year = date('Y',$dt);
$totalDays = date('t',$dt);
$weekCnt = 1;
$retWeek = 0;
for($i=1;$i<=$totalDays;$i++) {
$curDay = date("N", mktime(0,0,0,$month,$i,$year));
if($curDay==7) {
if($i==$day) {
$retWeek = $weekCnt+1;
}
$weekCnt++;
} else {
if($i==$day) {
$retWeek = $weekCnt;
}
}
}
return $retWeek;
}
echo weekOfMonth('2015-09-08') // gives me 2;
function getWeekOfMonth(DateTime $date) {
$firstDayOfMonth = new DateTime($date->format('Y-m-1'));
return ceil(($firstDayOfMonth->format('N') + $date->format('j') - 1) / 7);
}
Goendg solution does not work for 2016-10-31.
function weekOfMonth($strDate) {
$dateArray = explode("-", $strDate);
$date = new DateTime();
$date->setDate($dateArray[0], $dateArray[1], $dateArray[2]);
return floor((date_format($date, 'j') - 1) / 7) + 1;
}
weekOfMonth ('2015-09-17') // returns 3
Given the time_t wday (0=Sunday through 6=Saturday) of the first of the month in firstWday, this returns the (Sunday-based) week number within the month:
weekOfMonth = floor((dayOfMonth + firstWday - 1)/7) + 1
Translated into PHP:
function weekOfMonth($dateString) {
list($year, $month, $mday) = explode("-", $dateString);
$firstWday = date("w",strtotime("$year-$month-1"));
return floor(($mday + $firstWday - 1)/7) + 1;
}
You can also use this simple formula for finding week of the month
$currentWeek = ceil((date("d",strtotime($today_date)) - date("w",strtotime($today_date)) - 1) / 7) + 1;
ALGORITHM :
Date = '2018-08-08' => Y-m-d
Find out day of the month eg. 08
Find out Numeric representation of the day of the week minus 1 (number of days in week) eg. (3-1)
Take difference and store in result
Subtract 1 from result
Divide it by 7 to result and ceil the value of result
Add 1 to result eg. ceil(( 08 - 3 ) - 1 ) / 7) + 1 = 2
My function. The main idea: we would count amount of weeks passed from the month's first date to current. And the current week number would be the next one. Works on rule: "Week starts from monday" (for sunday-based type we need to transform the increasing algorithm)
function GetWeekNumberOfMonth ($date){
echo $date -> format('d.m.Y');
//define current year, month and day in numeric
$_year = $date -> format('Y');
$_month = $date -> format('n');
$_day = $date -> format('j');
$_week = 0; //count of weeks passed
for ($i = 1; $i < $_day; $i++){
echo "\n\n-->";
$_newDate = mktime(0,0,1, $_month, $i, $_year);
echo "\n";
echo date("d.m.Y", $_newDate);
echo "-->";
echo date("N", $_newDate);
//on sunday increasing weeks passed count
if (date("N", $_newDate) == 7){
echo "New week";
$_week += 1;
}
}
return $_week + 1; // as we are counting only passed weeks the current one would be on one higher
}
$date = new DateTime("2019-04-08");
echo "\n\nResult: ". GetWeekNumberOfMonth($date);
$month = 6;
$year = 2021;
$week = date("W", strtotime($year . "-" . $month ."-01"));
$str='';
$str .= date("d-m-Y", strtotime($year . "-" . $month ."-01")) ."to";
$unix = strtotime($year."W".$week ."+1 week");
while(date("m", $unix) == $month){
$str .= date("d-m-Y", $unix-86400) . "|";
$str .= date("d-m-Y", $unix) ."to";
$unix = $unix + (86400*7);
}
$str .= date("d-m-Y", strtotime("last day of ".$year . "-" . $month));
$weeks_ar = explode('|',$str);
echo '<pre>'; print_r($weeks_ar);
working fine.
// Current week of the month starts with Sunday
$first_day_of_the_week = 'Sunday';
$start_of_the_week1 = strtotime("Last $first_day_of_the_week");
if (strtolower(date('l')) === strtolower($first_day_of_the_week)) {
$start_of_the_week1 = strtotime('today');
}
$end_of_the_week1 = $start_of_the_week1 + (60 * 60 * 24 * 7) - 1;
// Get the date format
print date('Y-m-d', $start_of_the_week1) . ' 00:00:00';
print date('Y-m-d', $end_of_the_week1) . ' 23:59:59';
// self::DAYS_IN_WEEK = 7;
function getWeeksNumberOfMonth(): int
{
$currentDate = new \DateTime();
$dayNumberInMonth = (int) $currentDate->format('j');
$dayNumberInWeek = (int) $currentDate->format('N');
$dayNumberToLastSunday = $dayNumberInMonth - $dayNumberInWeek;
$daysCountInFirstWeek = $dayNumberToLastSunday % self::DAYS_IN_WEEK;
$weeksCountToLastSunday = ($dayNumberToLastSunday - $daysCountInFirstWeek) / self::DAYS_IN_WEEK;
$weeks = [];
array_push($weeks, $daysCountInFirstWeek);
for ($i = 0; $i < $weeksCountToLastSunday; $i++) {
array_push($weeks, self::DAYS_IN_WEEK);
}
array_push($weeks, $dayNumberInWeek);
if (array_sum($weeks) !== $dayNumberInMonth) {
throw new Exception('Logic is not valid');
}
return count($weeks);
}
Short variant:
(int) (new \DateTime())->format('W') - (int) (new \DateTime('first day of this month'))->format('W') + 1;
There is a many solutions but here is one my solution that working well in the most cases.
function current_week ($date = NULL) {
if($date) {
if(is_numeric($date) && ctype_digit($date) && strtotime(date('Y-m-d H:i:s',$date)) === (int)$date)
$unix_timestamp = $date;
else
$unix_timestamp = strtotime($date);
} else $unix_timestamp = time();
return (ceil((date('d', $unix_timestamp) - date('w', $unix_timestamp) - 1) / 7) + 1);
}
It accept unix timestamp, normal date or return current week from the time() if you not pass any value.
Enjoy!
I know this an old post but i have an idea!
$datetime0 = date_create("1970-01-01");
$datetime1 = date_create(date("Y-m-d",mktime(0,0,0,$m,"01",$Y)));
$datetime2 = date_create(date("Y-m-d",mktime(0,0,0,$m,$d,$Y)));
$interval1 = date_diff($datetime0, $datetime1);
$daysdiff1= $interval1->format('%a');
$interval2 = date_diff($datetime0, $datetime2);
$daysdiff2= $interval2->format('%a');
$week1=round($daysdiff1/7);
$week2=round($daysdiff2/7);
$WeekOfMonth=$week2-$week1+1;
$date = new DateTime('first Monday of this month');
$thisMonth = $date->format('m');
$mondays_arr = [];
// Get all the Mondays in the current month and store in array
while ($date->format('m') === $thisMonth) {
//echo $date->format('Y-m-d'), "\n";
$mondays_arr[] = $date->format('d');
$date->modify('next Monday');
}
// Get the day of the week (1-7 from monday to sunday)
$day_of_week = date('N') - 1;
// Get the day of month (1 to 31)
$current_week_monday_date = date('j') - $day_of_week;
/*$day_of_week = date('N',mktime(0, 0, 0, 2, 11, 2020)) - 1;
$current_week_monday_date = date('j',mktime(0, 0, 0, 2, 11, 2020)) - $day_of_week;*/
$week_no = array_search($current_week_monday_date,$mondays_arr) + 1;
echo "Week No: ". $week_no;
How about this function making use of PHP's relative dates?
This function assumes the week ends on Saturday. But this can be changed easily.
function get_weekNumMonth($date) {
$CI = &get_instance();
$strtotimedate = strtotime($date);
$firstweekEnd = date('j', strtotime("FIRST SATURDAY OF " . date("F", $strtotimedate) . " " . date("Y", $strtotimedate)));
$cutoff = date('j', strtotime($date));
$weekcount = 1;
while ($cutoff > $firstweekEnd) {
$weekcount++;
$firstweekEnd += 7; // move to next week
}
return $weekcount;
}
This function returns the integer week number of the current month. Weeks always start on Monday and counting always starts with 1.
function weekOfmonth(DateTime $date)
{
$dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
}
Example of use
echo weekOfmonth(new DateTime("2020-04-12")); //2
A test for all days from 1900-2038 with the accepted solution from #Anders as a reference:
//reference functions
//integer $date (Timestamp)
function weekOfMonthAnders($date) {
//Get the first day of the month.
$firstOfMonth = strtotime(date("Y-m-01", $date));
//Apply above formula.
return weekOfYear($date) - weekOfYear($firstOfMonth) + 1;
}
function weekOfYear($date) {
$weekOfYear = intval(date("W", $date));
if (date('n', $date) == "1" && $weekOfYear > 51) {
// It's the last week of the previos year.
return 0;
}
else if (date('n', $date) == "12" && $weekOfYear == 1) {
// It's the first week of the next year.
return 53;
}
else {
// It's a "normal" week.
return $weekOfYear;
}
}
//this function
function weekOfmonth(DateTime $date)
{
$dayFirstMonday = date_create('first monday of '.$date->format('F Y'))->format('j');
return (int)(($date->format('j') - $dayFirstMonday +7)/7) + ($dayFirstMonday == 1 ? 0 : 1);
}
$dt = date_create('1900-01-01');
$end = date_create('2038-01-02');
$countOk = 0;
$countError = 0;
for(;$dt < $end; $dt->modify('+1 Day')){
$ts = $dt->getTimestamp();
if(weekOfmonth($dt) === weekOfMonthAnders($ts)){
++$countOk;
}
else {
++$countError;
}
}
echo $countOk.' compare ok, '.$countError.' errors';
Result: 50405 compare ok, 0 errors
I took the visual approach (like how we do it in the real world). Instead of using formulas or what not, I solved it (or at least I think I did) by visualizing a literal calendar and then putting the dates in a multidimensional array. The first dimension corresponds to the week.
I hope someone can check if it stands your tests. Or help someone out with a different approach.
# date in this format 2021-08-03
# week_start is either Sunday or Monday
function getWeekOfMonth($date, $week_start = "Sunday"){
list($year, $month, $day) = explode("-", $date);
$dates = array();
$current_week = 1;
$new_week_signal = $week_start == "Sunday" ? 6 : 0;
for($i = 1; $i <= date("t", strtotime($date)); $i++){
$current_date = strtotime("{$year}-{$month}-".$i);
$dates[$current_week][] = $i;
if(date('w', $current_date) == $new_week_signal){
$current_week++;
}
}
foreach($dates as $week => $days){
if(in_array(intval($day), $days)){
return $week;
}
}
return false;
}
//It's easy, no need to use php function
//Let's say your date is 2017-07-02
$Date = explode("-","2017-07-02");
$DateNo = $Date[2];
$WeekNo = $DateNo / 7; // devide it with 7
if(is_float($WeekNo) == true)
{
$WeekNo = ceil($WeekNo); //So answer will be 1
}
//If value is not float then ,you got your answer directly
I need to Write a function named countDays which takes a single parameter named dateinstring which is string in the form ”MM.DD.YYY” represent a real date value. The function should print to the console the number of days from the beginning of the year specified in dateInString until the date represented in dateInString. If the value of dateInString is invalid, the function should print ”Bad format” to the console.
I have written the code as below :
function countDays($dateInString){
date_default_timezone_set('America/Los_Angeles');
$date = explode('.', $dateInString);
if(count($date) == 3 && checkdate($date[0], $date[1], $date[2])){
$formatted_date = $date[2].'-'.$date[0].'-'.$date[1].'00:00:00';
$diff = strtotime($formatted_date).'-'.strtotime($date[2].'-01-01 00:00:00');
echo round($diff/86400)+1;
}
else {
echo 'Bad format';
}
};
countDays('1.15.2014');
But the above code seems that not giving the correct output. It is about 33% correct. But where is the problem with this code ? Please help me!!!
$diff = strtotime($formatted_date).'-'.strtotime($date[2].'-01-01 00:00:00');
Change to
$diff = strtotime($formatted_date) - strtotime($date[2].'-01-01 00:00:00');
You made the minus symbol a string instead of an operator.
You could try it this way
function countDays($dateInString) {
date_default_timezone_set('America/Los_Angeles');
$date = explode('.', $dateInString);
if (checkdate($date[0], $date[1], $date[2])) {
$year_start = mktime(0, 0, 0, 1, 1, $date[2]);
$your_date = mktime(0,0,0,$date[0], $date[1], $date[2]);
$diff = $your_date - $year_start;
echo floor($diff /(60*60*24));
} else {
echo "Bad date supplied";
}
}
A better approach would be to use the DateTime class. I haven't included the validation in this, but i suggest you use regex for that.
function countDays($dateInString){
$parts = explode('.', $dateInString);
$date = new DateTime($parts[2] . '-' . $parts[0] . '-' . $parts[1]);
$compare = new DateTime( $date->format('Y') . '-01-01' );
$interval = $date->diff($compare);
return $interval->format('%a');
}
echo countDays('09.15.2014');
Check this out.
function countDays($dateInString){
date_default_timezone_set('America/Los_Angeles');
$date = explode('.', $dateInString);
if(count($date) == 3 && checkdate($date[0], $date[1], $date[2])){
$formatted_date = strtotime($date[2].'/'.$date[0].'/'.$date[1]);
$endTimeStamp = strtotime("2014/01/01");
$timeDiff = abs($endTimeStamp - $formatted_date);
echo round(intval($timeDiff/86400));
}
else {
echo 'Bad format';
}
};
countDays('01.01.2014');
okay, I am at my wits end with this. been trying to solve this for 3 days now and I am getting nowhere with this.
I need to get the value of $offset between two locations and take it off of a set time which is (00:00).
here is how I set the $offset value and it works just fine.
<?php
if( isset($_POST['submit']))
{
//be sure to validate and clean your variables
$timezone1 = htmlentities($_POST['timezone1']);
$timezone2 = htmlentities($_POST['timezone2']);
//then you can use them in a PHP function.
function get_timezone_offset( $origin_tz, $remote_tz ) {
$timezone1 = new DateTimeZone ( $origin_tz );
$timezone2 = new DateTimeZone ( $remote_tz );
$datetime1 = new DateTime ("now", $timezone1);
$datetime2 = new DateTime ("now", $timezone2);
$offset = $timezone1->getOffset($datetime1) - $timezone2->getOffset($datetime2);
return $offset;
}
$offset = get_timezone_offset($timezone1, $timezone2);
}
?>
And here is how I've tried to do what i want using DateTime, this code will only echo's the $offset value without taking it off of the 00:00
<?php
if (0 > $offset)
{
// set an object with the current date
$date = new DateTime();
$date->setTime(00, 00);
// the second date
$date2 = new DateTime($offset/3600 * 1);
// apply the diff() method, getting a DateInterval object ($diDiff)
$diDiff = $date->diff($date2) ;
}
echo $diDiff->format("%H:%i");
?>
And i even tried to use strtotime but strtotime returns a wrong value and i have been advised by some guys on stackoverflow to use DateTime.
<?php
$time1 = strtotime('00:00');
if (0 > $offset)
{
// For negative offset (hours behind)
$hour_dif = date('H:i', strtotime($time1 -$offset/3600));
$time1 = "{$hour_dif}";
}
elseif (0 < $offset)
{
// For positive offset (hours ahead)
$hour_dif = date('H:i', strtotime($time1 +$offset/3600));
$time1 = "{$hour_dif}";
}
else
{
// For offsets in the same timezone.
$time1 = "in the same timezone";
}
echo "{$time1}";
?>
Please someone help me out as it is absolutely killing my time.
You can also easily solve this using Carbon, a class that will greatly simplify doing date calculations of any kind:
// example timezones
$timezone1 = 'Europe/Berlin';
$timezone2 = 'Asia/Yakutsk';
$dt1 = Carbon::createFromDate(2000, 1, 1, $timezone1);
$dt2 = Carbon::createFromDate(2000, 1, 1, $timezone2);
// false will force a relative difference, so it can be a negative result
$difference = $dt1->diffInMinutes($dt2, false);
$dtMidnight = Carbon::create(2000, 1, 1, 12, 0, 0);
// get the difference from midnight
$differenceFromMidnight = $dtMidnight->addMinutes($difference);
echo $differenceFromMidnight->hour;
echo $differenceFromMidnight->minute;
This handles both positive and negative offsets:
$sign = $offset >= 0 ? 1 : -1;
$offset = $offset * $sign; // make sure offset is a positive number
// set an object with the current date
$date = new DateTime();
$date->setTime(00, 00);
// the second date
$date2 = new DateTime();
$interval = new DateInterval("PT" . $offset . "S");
if ($sign > 0) {
$date2->add($interval);
} else {
$date2->sub($interval);
}
echo $date2->format("H:i");
The following code will print the input time adjusted by $offset amount of hours.
$date = new DateTime();
$date->setTime(00, 00);
$date->add(DateInterval::createFromDateString("{$offset} hours"));
echo $date->format('H:i');
I have, again, tested this solution (with PHP 5.4.17) and it correctly shifts the time.
PHPFiddle: http://phpfiddle.org/main/code/rhd-pj4
Please bear with me as I try to explain my predicament. I need to somehow get the difference between two dates by reversing a function I have to add months and years?
Problem
The date add function provided with PHP >= 5.3 does not add dates in the manner I require.
Example: +3 Months to 30Nov = 2Mar
Solution
I use the function below (code ref 2) to produce the results I need.
Example: +3 Months to 30Nov = 28Feb
However when using the below (code ref 1) to calculate the difference it does so based on the addition function provide with PHP >= 5.3 in that I get 2 instead of 3 months difference between 30Nov and 28Feb.
If anyone could help come up with an accurate date diff based on the code ref 2 logic I, and I'm sure others in the same boat would be very grateful.
<< CODE REF 1 >>
<?php
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 2
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%m'); // 3
?>
<< CODE REF 2 >>
<?php
$datetime = new DateTime('2000-11-30');
$y = 0;
$m = 3;
$d = 0;
if ($d>0){
$datetime->add(new DateInterval('P'.$d.'D'));
}
if ($d<0){
$datetime->sub(new DateInterval('P'.$d.'D'));
}
if ($y!=0){
$init=clone $datetime;
$modifier=$y.' years';
$datetime->modify($modifier);
while ($datetime->format('m')!=$init->format('m')){
$datetime->modify('-1 day');
}
}
if ($m!=0){
$init=clone $datetime;
$modifier=$m.' months';
$back_modifier =-$m.' months';
$datetime->modify($modifier);
$back_to_init= clone $datetime;
$back_to_init->modify($back_modifier);
while ($init->format('m')!=$back_to_init->format('m')){
$datetime->modify('-1 day');
$back_to_init= clone $datetime;
$back_to_init->modify($back_modifier);
}
}
echo $datetime->format('Y-m-d'); // 2001-02-28
?>
SOLUTION FOUND
By changing the way we use the original function we instead find out the number of years and months as desired, many thanks to all the helpful suggestions. The reason for y=1 and m=4 is because the year starts at one and the month starts at one, otherwise it would be 0 and 3 as originally requested if starting at zero.
<?php
function date_yr_mth($date1='2000-11-30',$date2='2001-02-28'){
$y1 = date("Y", strtotime($date1));
$m1 = date("n", strtotime($date1));
$d1 = date("j", strtotime($date1));
$y2 = date("Y", strtotime($date2));
$m2 = date("n", strtotime($date2));
$d2 = date("j", strtotime($date2));
$t2 = date("t", strtotime($date2));
$cm_diff = $m2-$m1;
$cy_diff = $y2-$y1;
if ($d2>=$d1){
$add_mth1 = 1;
}else{
$add_mth1 = 0;
}
$add_mth2 = 12*$cy_diff+$cm_diff;
if ($d2==$t2 && $d2<$d1){
$add_mth3 = 1;
}else{
$add_mth3 = 0;
}
$total_mths = $add_mth1+$add_mth2+$add_mth3;
$arr = array();
$arr['y'] = floor(($total_mths-1)/12)+1;
$arr['m'] = $total_mths-($arr['y']-1)*12;
print_r($arr);
// [y] => 1
// [m] => 4
}
?>
The way to approach this is to extend DateTime and overide the add() and sub() methods to behave as you want them to. That, after all is one of the advantages of OOP.
The way to get your desired behaviours is to set the day of the month to the 1st before doing calling add() or sub() and then restoring the original or highest possible day afterwards.
My first attempt is below, not thoroughly tested, but adding 1 month to 31st Jan gave 28th Feb, which, I believe is your desired behaviour:-
class MyDateTime extends \DateTime
{
public function add($interval)
{
$oldDay = (int)$this->format('d');
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
parent::add($interval);
$maxDay = (int)$this->format('t');
if($oldDay > $maxDay){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
} else {
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
}
return $this;
}
public function sub($interval)
{
$oldDay = (int)$this->format('d');
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), 1);
parent::sub($interval);
$maxDay = (int)$this->format('t');
if($oldDay > $maxDay){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $maxDay);
} else {
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), $oldDay);
}
return $this;
}
public function diff($dateTime2, $absolute = false)
{
if((int)$this->format('t') > (int)$dateTime2->format('t')){
$this->setDate((int)$this->format('Y'), (int)$this->format('m'), (int)$dateTime2->format('t'));
}
if((int)$this->format('t') < (int)$dateTime2->format('t')){
$dateTime2->setDate((int)$dateTime2->format('Y'), (int)$dateTime2->format('m'), (int)$this->format('t'));
}
return parent::diff($dateTime2, $absolute);
}
}
Here is a working example using your exampe dates
Here is an example using the diff() method as you can see it gives a 3 month difference. You can also see that adding the resulting DateInterval to the original date results in the second date.
The sub() method may require a bit more thought, but I don't have time just now. I'll take a more thorough look if I get a few spare minutes later.
This way you would get the absolute difference between months without taking in account the day.
<?php
function getMonthDiff($firstMonth, $secondMonth)
{
$firstMonth = $firstMonth->format("Y") * 12 + $firstMonth->format("m");
$secondMonth = $secondMonth->format("Y") * 12 + $secondMonth->format("m");
return abs($firstMonth - $secondMonth);
}
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-02-28');
echo getMonthDiff($datetime1, $datetime2);
echo "<br />";
$datetime1 = new DateTime('2000-11-30');
$datetime2 = new DateTime('2001-03-02');
echo getMonthDiff($datetime1, $datetime2);