Days360.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
  3. use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
  4. use PhpOffice\PhpSpreadsheet\Calculation\Exception;
  5. use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
  6. use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
  7. class Days360
  8. {
  9. use ArrayEnabled;
  10. /**
  11. * DAYS360.
  12. *
  13. * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
  14. * which is used in some accounting calculations. Use this function to help compute payments if
  15. * your accounting system is based on twelve 30-day months.
  16. *
  17. * Excel Function:
  18. * DAYS360(startDate,endDate[,method])
  19. *
  20. * @param array|mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
  21. * PHP DateTime object, or a standard date string
  22. * Or can be an array of date values
  23. * @param array|mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
  24. * PHP DateTime object, or a standard date string
  25. * Or can be an array of date values
  26. * @param array|mixed $method US or European Method as a bool
  27. * FALSE or omitted: U.S. (NASD) method. If the starting date is
  28. * the last day of a month, it becomes equal to the 30th of the
  29. * same month. If the ending date is the last day of a month and
  30. * the starting date is earlier than the 30th of a month, the
  31. * ending date becomes equal to the 1st of the next month;
  32. * otherwise the ending date becomes equal to the 30th of the
  33. * same month.
  34. * TRUE: European method. Starting dates and ending dates that
  35. * occur on the 31st of a month become equal to the 30th of the
  36. * same month.
  37. * Or can be an array of methods
  38. *
  39. * @return array|int|string Number of days between start date and end date
  40. * If an array of values is passed for the $startDate or $endDays,arguments, then the returned result
  41. * will also be an array with matching dimensions
  42. */
  43. public static function between($startDate = 0, $endDate = 0, $method = false)
  44. {
  45. if (is_array($startDate) || is_array($endDate) || is_array($method)) {
  46. return self::evaluateArrayArguments([self::class, __FUNCTION__], $startDate, $endDate, $method);
  47. }
  48. try {
  49. $startDate = Helpers::getDateValue($startDate);
  50. $endDate = Helpers::getDateValue($endDate);
  51. } catch (Exception $e) {
  52. return $e->getMessage();
  53. }
  54. if (!is_bool($method)) {
  55. return ExcelError::VALUE();
  56. }
  57. // Execute function
  58. $PHPStartDateObject = SharedDateHelper::excelToDateTimeObject($startDate);
  59. $startDay = $PHPStartDateObject->format('j');
  60. $startMonth = $PHPStartDateObject->format('n');
  61. $startYear = $PHPStartDateObject->format('Y');
  62. $PHPEndDateObject = SharedDateHelper::excelToDateTimeObject($endDate);
  63. $endDay = $PHPEndDateObject->format('j');
  64. $endMonth = $PHPEndDateObject->format('n');
  65. $endYear = $PHPEndDateObject->format('Y');
  66. return self::dateDiff360((int) $startDay, (int) $startMonth, (int) $startYear, (int) $endDay, (int) $endMonth, (int) $endYear, !$method);
  67. }
  68. /**
  69. * Return the number of days between two dates based on a 360 day calendar.
  70. */
  71. private static function dateDiff360(int $startDay, int $startMonth, int $startYear, int $endDay, int $endMonth, int $endYear, bool $methodUS): int
  72. {
  73. $startDay = self::getStartDay($startDay, $startMonth, $startYear, $methodUS);
  74. $endDay = self::getEndDay($endDay, $endMonth, $endYear, $startDay, $methodUS);
  75. return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
  76. }
  77. private static function getStartDay(int $startDay, int $startMonth, int $startYear, bool $methodUS): int
  78. {
  79. if ($startDay == 31) {
  80. --$startDay;
  81. } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !Helpers::isLeapYear($startYear))))) {
  82. $startDay = 30;
  83. }
  84. return $startDay;
  85. }
  86. private static function getEndDay(int $endDay, int &$endMonth, int &$endYear, int $startDay, bool $methodUS): int
  87. {
  88. if ($endDay == 31) {
  89. if ($methodUS && $startDay != 30) {
  90. $endDay = 1;
  91. if ($endMonth == 12) {
  92. ++$endYear;
  93. $endMonth = 1;
  94. } else {
  95. ++$endMonth;
  96. }
  97. } else {
  98. $endDay = 30;
  99. }
  100. }
  101. return $endDay;
  102. }
  103. }