Skip to content

Commit

Permalink
Merge remote-tracking branch 'GitHub/TimeSpan'
Browse files Browse the repository at this point in the history
  • Loading branch information
uruba committed Sep 5, 2015
2 parents 078e1e7 + d2ab58d commit 4824ed4
Show file tree
Hide file tree
Showing 11 changed files with 424 additions and 9 deletions.
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ The second option is to instantiate the calculator class of your choice directly

```php
use FinanCalc\Calculators\DebtAmortizator;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

...

Expand Down
2 changes: 1 addition & 1 deletion src/Calculators/AnnuityCalculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use FinanCalc\Interfaces\Calculator\CalculatorAbstract;
use FinanCalc\Utils\Helpers;
use FinanCalc\Utils\MathFuncs;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class AnnuityCalculator
Expand Down
2 changes: 1 addition & 1 deletion src/Calculators/DebtAmortizator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use FinanCalc\Interfaces\Calculator\CalculatorAbstract;
use FinanCalc\Utils\Helpers;
use FinanCalc\Utils\MathFuncs;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class DebtAmortizator
Expand Down
2 changes: 1 addition & 1 deletion src/Calculators/Factories/AnnuityCalculatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace FinanCalc\Calculators\Factories {
use FinanCalc\Calculators\AnnuityCalculator;
use FinanCalc\Interfaces\Calculator\CalculatorFactoryAbstract;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class AnnuityCalculatorFactory
Expand Down
2 changes: 1 addition & 1 deletion src/Calculators/Factories/DebtAmortizatorFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace FinanCalc\Calculators\Factories {
use \FinanCalc\Calculators\DebtAmortizator;
use FinanCalc\Interfaces\Calculator\CalculatorFactoryAbstract;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class DebtAmortizatorFactory
Expand Down
222 changes: 222 additions & 0 deletions src/Utils/Time/TimeSpan.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
<?php


namespace FinanCalc\Utils\Time {

use DateInterval;
use DateTime;
use InvalidArgumentException;

/**
* Class TimeSpan
* @package FinanCalc\Utils\Time
*/
class TimeSpan {
/** @var DateTime */
private $startDate, $endDate;
/** @var DateInterval */
private $dateInterval;

/**
* PRIVATE constructor
*/
private function __construct() {

}

/**
* @param integer $years
* @param integer $months
* @param integer $days
* @return TimeSpan
*/
public static function asDuration(
$years,
$months = 0,
$days = 0
) {
$newThis = new TimeSpan();
$newThis->newDateIntervalAbsolute($years, $months, $days);

return $newThis;
}

/**
* @param DateTime $startDate
* @param $years
* @param $months
* @param int $days
* @return TimeSpan
*/
public static function asDurationWithStartDate(
DateTime $startDate,
$years,
$months = 0,
$days = 0
) {
$newThis = TimeSpan::asDuration($years, $months, $days);
$newThis->setStartDate($startDate);

return $newThis;
}

/**
* @param DateTime $startDate
* @param DateTime $endDate
* @return TimeSpan
*/
public static function asInterval(
DateTime $startDate,
DateTime $endDate
) {
$newThis = new TimeSpan();
$newThis->checkStartEndDateAndSetInterval($startDate, $endDate);
$newThis->setStartDate($startDate);
$newThis->setEndDate($endDate);

return $newThis;
}

/**
* @param DateTime $startDate
*/
public function setStartDate(DateTime $startDate) {
$endDate = $this->endDate;
if ($endDate !== null) {
$this->checkStartEndDateAndSetInterval($startDate, $endDate);
} else {
$endDate = clone $startDate;
$this->endDate = $endDate->add($this->dateInterval);
}
$this->startDate = $startDate;
}

/**
* @param DateTime $endDate
*/
public function setEndDate(DateTime $endDate) {
if ($this->startDate !== null) {
$this->checkStartEndDateAndSetInterval($this->startDate, $endDate);
} else {
$dateInterval = $this->dateInterval;
$dateInterval->invert = 1;
$startDate = clone $endDate;
$this->startDate = $startDate->add($dateInterval);
$dateInterval->invert = 0;
}

$this->endDate = $endDate;
}

/**
* @return DateTime
*/
public function getStartDate() {
return $this->startDate;
}

/**
* @return DateTime
*/
public function getEndDate() {
return $this->endDate;
}

/**
* @return int
*/
public function getYears() {
return $this->dateInterval->y;
}

/**
* @return int
*/
public function getMonths() {
return $this->dateInterval->m;
}

/**
* @return int
*/
public function getDays() {
return $this->dateInterval->d;
}

public function clearStartEndDate() {
$this->startDate = $this->endDate = null;
}

/** PRIVATE methods */

/**
* @param DateInterval $dateInterval
*/
private function setDateInterval(DateInterval $dateInterval) {
if($dateInterval->y == 0 && $dateInterval->m == 0 && $dateInterval->d == 0) {
throw new InvalidArgumentException("The duration has to be greater than zero!");
}

$this->dateInterval = $dateInterval;
}

/**
* @param $years
* @param $months
* @param $days
*/
private function newDateIntervalAbsolute($years, $months, $days) {
$this->setdateInterval(
new DateInterval(
"P" .
(string)$years . "Y" .
(string)$months . "M" .
(string)$days . "D"
)
);
}

/**
* @param DateTime $startDate
* @param DateTime $endDate
*/
private function newDateIntervalDifference(DateTime $startDate, DateTime $endDate) {
$this->setDateInterval(
$this->roundDateInterval(
$startDate->diff($endDate)
)
);
}

/**
* @param DateTime $startDate
* @param DateTime $endDate
*/
private function checkStartEndDateAndSetInterval(DateTime $startDate, DateTime $endDate) {
if ($startDate < $endDate) {
$this->newDateIntervalDifference($startDate, $endDate);
} else {
throw new InvalidArgumentException("Start date has to be lower than the end date!");
}
}

/**
* @param DateInterval $dateInterval
* @return DateInterval
*/
private function roundDateInterval(DateInterval $dateInterval) {
// TODO: make more intelligent rounding based on the start and end date
if (in_array($dateInterval->d, [30, 31])) {
$dateInterval->d = 0;
$dateInterval->m += 1;
}

if ($dateInterval->m == 12) {
$dateInterval->y += 1;
$dateInterval->m = 0;
}

return $dateInterval;
}
}
}
63 changes: 62 additions & 1 deletion src/Utils/TimeUtils.php → src/Utils/Time/TimeUtils.php
Original file line number Diff line number Diff line change
@@ -1,16 +1,73 @@
<?php


namespace FinanCalc\Utils {
namespace FinanCalc\Utils\Time {

use Exception;
use FinanCalc\Utils\Config;
use FinanCalc\Utils\MathFuncs;

/**
* Class TimeUtils
* @package FinanCalc\Utils
*/
class TimeUtils {

/**
* @param TimeSpan $timeSpan
* @return string
* @throws Exception
*/
public static function getYearsFromTimeSpan(TimeSpan $timeSpan) {
$monthsComponent = MathFuncs::div(
$timeSpan->getMonths(),
12
);
$daysComponent = self::getCurrentDayCountConvention()['days_in_a_year'] == 0 ?
0 :
MathFuncs::div(
$timeSpan->getDays(),
self::getCurrentDayCountConvention()['days_in_a_year']
);

return MathFuncs::add($timeSpan->getYears(), MathFuncs::add($monthsComponent, $daysComponent));
}

/**
* @param TimeSpan $timeSpan
* @return string
* @throws Exception
*/
public static function getMonthsFromTimeSpan(TimeSpan $timeSpan) {
$yearsComponent = MathFuncs::mul($timeSpan->getYears(), 12);
$daysComponent = self::getCurrentDayCountConvention()['days_in_a_month'] == 0 ?
0 :
MathFuncs::div(
$timeSpan->getDays(),
self::getCurrentDayCountConvention()['days_in_a_month']
);

return MathFuncs::add($timeSpan->getMonths(), MathFuncs::add($yearsComponent, $daysComponent));
}

/**
* @param TimeSpan $timeSpan
* @return string
* @throws Exception
*/
public static function getDaysFromTimeSpan(TimeSpan $timeSpan) {
$yearsComponent = MathFuncs::mul(
$timeSpan->getYears(),
self::getCurrentDayCountConvention()['days_in_a_year']
);
$monthsComponent = MathFuncs::mul(
$timeSpan->getMonths(),
self::getCurrentDayCountConvention()['days_in_a_month']
);

return MathFuncs::add($timeSpan->getDays(), MathFuncs::add($yearsComponent, $monthsComponent));
}

/**
* @param $numberOfDays
* @return string
Expand Down Expand Up @@ -114,6 +171,10 @@ public static function getDaysFromYears($numberOfYears) {
);
}

/**
* @return mixed
* @throws Exception
*/
public static function getCurrentDayCountConvention() {
$dayCountConventionIdentifier = Config::getConfigField('day_count_convention');
$availableDayCountConventions = Config::getConfigField('available_day_count_conventions');
Expand Down
2 changes: 1 addition & 1 deletion tests/AnnuityCalculatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use FinanCalc\Calculators\AnnuityCalculator;
use FinanCalc\Constants\AnnuityPaymentTypes;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class AnnuityCalculatorTest
Expand Down
2 changes: 1 addition & 1 deletion tests/DebtAmortizatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use FinanCalc\Calculators\DebtAmortizator;
use FinanCalc\FinanCalc;
use FinanCalc\Utils\MathFuncs;
use FinanCalc\Utils\TimeUtils;
use FinanCalc\Utils\Time\TimeUtils;

/**
* Class DebtAmortizatorTest
Expand Down
Loading

0 comments on commit 4824ed4

Please sign in to comment.