Calculate the years/months/days between two events
Return a gedcom style age string: "1y 2m 3d" (for fact details)

@param Date      $d1
@param Date|null $d2

@return string
180317
public static function getAgeGedcom(Date $d1, Date $d2 = null): string
    {
        if ($d2 === null) {
            return $d1->date1->getAgeFull(Carbon::now()->julianDay());
        }

        if (self::compare($d1, $d2) !== 0) {
            return $d1->date1->getAgeFull($d2->minimumJulianDay());
        }

        if ($d1->minimumJulianDay() == $d2->minimumJulianDay()) {
            return '0d';
        }

        return '';
    }
1169868
public function getExpiryDate($format = null)
    {
        $node = $this->getFirst('//epp:epp/epp:response/epp:resData/domain:trnData/domain:exDate');
        if ($node === null) {
            return null;
        }

        if ($format === null) {
            return $node->nodeValue;
        }

        return date_create_from_format($format, $node->nodeValue);
    }
952725
public static String getDateTimeStrConcise(Date d) {
        if (d == null)
            return "";

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSSZ");
        return sdf.format(d);
    }
1353164
public static function between($date, $date1, $date2) : bool {
		$date = strtotime($date);
		return ($date >= strtotime($date1) && $date <= strtotime($date2));
	}
396271
public function diffInYears(Date $dt = null, $abs = true)
    {
        $dt = $dt ?: static::now($this->getTimezone());

        return (int) $this->diff($dt, $abs)->format('%r%y');
    }
230955
public static function diffDates($date1, $date2)
    {
        $ts1 = strtotime($date1);
        $ts2 = strtotime($date2);
        
        $seconds_diff = $ts2 - $ts1;
        
        return floor($seconds_diff / 3600 / 24);
    }
489584
private static long daysBetween(Date date1, Date date2) {
        long diff;
        if (date2.after(date1)) {
            diff = date2.getTime() - date1.getTime();
        } else {
            diff = date1.getTime() - date2.getTime();
        }
        return diff / (24 * 60 * 60 * 1000);
    }
528444
private static CSLDate merge(CSLDate d1, CSLDate d2) {
		if (d1 == null) {
			return d2;
		} else if (d2 == null) {
			return d1;
		}
		
		CSLDateBuilder builder = new CSLDateBuilder();
		
		//handle date parts
		builder.dateParts(d1.getDateParts()[0], d2.getDateParts()[d2.getDateParts().length - 1]);
		
		//handle circa
		if (d1.getCirca() != null) {
			builder.circa(d1.getCirca());
		}
		if (d2.getCirca() != null && (d1.getCirca() == null || d2.getCirca().booleanValue())) {
			builder.circa(d2.getCirca());
		}
		
		//handle literal strings
		if (d1.getLiteral() != null) {
			builder.literal(d1.getLiteral());
		}
		if (d2.getLiteral() != null) {
			if (d1.getLiteral() != null) {
				builder.literal(d1.getLiteral() + "-" + d2.getLiteral());
			} else {
				builder.literal(d2.getLiteral());
			}
		}
		
		//handle seasons
		if (d1.getSeason() != null) {
			builder.season(d1.getSeason());
		}
		if (d2.getSeason() != null) {
			if (d1.getSeason() != null) {
				builder.season(d1.getSeason() + "-" + d2.getSeason());
			} else {
				builder.season(d2.getSeason());
			}
		}
		
		//handle raw strings
		if (d1.getRaw() != null) {
			builder.raw(d1.getRaw());
		}
		if (d2.getRaw() != null) {
			if (d1.getRaw() != null) {
				builder.raw(d1.getRaw() + "-" + d2.getRaw());
			} else {
				builder.raw(d2.getRaw());
			}
		}
		
		return builder.build();
	}
87314
public function seeDateMatches($d1, $d2) {
        \PHPUnit_Framework_Assert::assertTrue($this->_ParseDate($d1)->eq($this->_ParseDate($d2)));
    }
1157549
private static long dateTimeDifference(final Temporal d1, final Temporal d2) {
      return ChronoUnit.SECONDS.between(d1, d2);
  }
1133884
private function isSameDay(\DateTime $d1, \DateTime $d2)
    {
        return $d1->format('Y') == $d2->format('Y') && $d1->format('z') == $d2->format('z');
    }
880058
public static int getNumOfMonths(Date date1, Date date2) {
		Calendar firstDate = Calendar.getInstance();
		Date date = new Date(date1.getTime());
		firstDate.setTime(date);
		Calendar secondDate = Calendar.getInstance();
		Date date3 = new Date(date2.getTime());
		secondDate.setTime(date3);
		int months = firstDate.get(Calendar.MONTH) - secondDate.get(Calendar.MONTH);

		return months;
	}
483242
@Override
	public double getDaycount(LocalDate startDate, LocalDate endDate) {
		if(startDate.isAfter(endDate)) {
			return -getDaycount(endDate,startDate);
		}

		int startDateDay 	= startDate.getDayOfMonth();
		int startDateMonth 	= startDate.getMonthValue();
		int startDateYear 	= startDate.getYear();

		int endDateDay 		= endDate.getDayOfMonth();
		int endDateMonth 	= endDate.getMonthValue();
		int endDateYear 	= endDate.getYear();

		if(
				isEndOfMonth &&
				startDate.getMonth() == Month.FEBRUARY &&
				startDate.getDayOfMonth() == startDate.lengthOfMonth() &&
				endDate.getMonth() == Month.FEBRUARY &&
				endDate.getDayOfMonth() == endDate.lengthOfMonth()
				) {
			endDateDay = 30;
		}

		if(
				isEndOfMonth &&
				startDate.getMonth() == Month.FEBRUARY &&
				startDate.getDayOfMonth() == startDate.lengthOfMonth()
				) {
			startDateDay = 30;
		}

		if(endDateDay > 30 && startDateDay >= 30) {
			endDateDay = 30;
		}
		startDateDay = Math.min(startDateDay,30);

		return (endDateYear - startDateYear) * 360.0 + (endDateMonth - startDateMonth) * 30.0 + (endDateDay - startDateDay);
	}
350988
function duration2date($startdate=FALSE, $duration=FALSE) {
    if( $startdate && $duration ) {
      $d1               = $startdate;
      $dur              = $duration;
    }
    elseif( isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) {
      $d1               = $this->dtstart['value'];
      $dur              = $this->duration['value'];
    }
    else
      return null;
    $dateOnly         = ( isset( $d1['hour'] ) || isset( $d1['min'] ) || isset( $d1['sec'] )) ? FALSE : TRUE;
    $d1['hour']       = ( isset( $d1['hour'] )) ? $d1['hour'] : 0;
    $d1['min']        = ( isset( $d1['min'] ))  ? $d1['min']  : 0;
    $d1['sec']        = ( isset( $d1['sec'] ))  ? $d1['sec']  : 0;
    $dtend = mktime( $d1['hour']
                    , $d1['min']
                    , $d1['sec']
                    , $d1['month']
                    , $d1['day']
                    , $d1['year'] );
    if( isset( $dur['week'] ))
      $dtend += ( $dur['week'] * 7 * 24 * 60 * 60 );
    if( isset( $dur['day'] ))
      $dtend += ( $dur['day'] * 24 * 60 * 60 );
    if( isset( $dur['hour'] ))
      $dtend += ( $dur['hour'] * 60 *60 );
    if( isset( $dur['min'] ))
      $dtend += ( $dur['min'] * 60 );
    if( isset( $dur['sec'] ))
      $dtend +=   $dur['sec'];
    $dtend2 = array();
    $dtend2['year']   = date('Y', $dtend );
    $dtend2['month']  = date('m', $dtend );
    $dtend2['day']    = date('d', $dtend );
    $dtend2['hour']   = date('H', $dtend );
    $dtend2['min']    = date('i', $dtend );
    $dtend2['sec']    = date('s', $dtend );
    if( isset( $d1['tz'] ))
      $dtend2['tz']   = $d1['tz'];
    if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
      unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
    return $dtend2;
  }
647761
public static function compareTimeWithoutDate($date1, $date2)
    {
        $date1 = DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-01 ' . $date1->format('H:i:s'));
        $date2 = DateTime::createFromFormat('Y-m-d H:i:s', '2000-01-01 ' . $date2->format('H:i:s'));
        if ($date1 == $date2) {
            return 0;
        }
        if ($date1 < $date2) {
            return -1;
        }

        return 1;
    }
1298559
public function getAge($date = null, $months = false)
    {
        $birthDate = $this->getBirthDay();
        
        if (is_null($date)) {
            $date = new \MUtil_Date();
        }        
        
        if (!($birthDate instanceof \MUtil_Date) || !($date instanceof \MUtil_Date)) {
            return null;
        }
        
        // Now calculate age         
        if ($months) {
            $age  = $date->diffMonths($birthDate);                
            $unit = 'dd';        
        } else {
            $age  = $date->diffYears($birthDate);
            $unit = 'MMdd';
        }
        if ($date->get($unit) < $birthDate->get($unit)) {
            $age--;
        } 

        return $age;
    }
443681
public static function ageRange($year, $month = null, $day = null, $steps = 1) {
		if ($month == null && $day == null) {
			$age = (int)date('Y') - $year - 1;
		} elseif ($day == null) {
			if ($month >= (int)date('m')) {
				$age = (int)date('Y') - $year - 1;
			} else {
				$age = (int)date('Y') - $year;
			}
		} else {
			if ($month > (int)date('m') || ($month == (int)date('m') && $day > (int)date('d'))) {
				$age = (int)date('Y') - $year - 1;
			} else {
				$age = (int)date('Y') - $year;
			}
		}
		if ($age % $steps == 0) {
			$lowerRange = $age - $steps + 1;
			$upperRange = $age;
		} else {
			$lowerRange = $age - ($age % $steps) + 1;
			$upperRange = $age - ($age % $steps) + $steps;
		}
		if ($lowerRange == $upperRange) {
			return $upperRange;
		}
		return [$lowerRange, $upperRange];
	}