Complete Breakup Of Calculation/DateTime Functions (#1937)

* Complete Breakup Of Calculation/DateTime Functions

In conjunction with parallel breakups happening in other areas of Calculation, this change breaks up all the DateTime functions into their own classes. All methods remaining in DateTime itself have a doc block deprecation notice, and consist only of stub code to call the replacement methods. Coverage of DateTime itself and all the replacement methods is 100%.

There is only one substantive change to the code (see next paragraph). Among the non-substantive changes, it now adopts the same parsing technique (throwing and catching exceptions) already in use in Engineering and MathTrig. Boolean parameters are allowed in lieu of numbers when Excel allows them. Most of the code changes involve refactoring due to the need to avoid Scrutinizer "complexity" failures in what it will consider to be new methods.

Issue #1936 was opened just as I was staging this. It is now fixed. One existing WORKDAY test was wrong (noted in a comment in the test data file), and a bunch of new tests are added.

I found it confusing to use DateTime as a node of the the class name since most of the methods invoke native DateTime methods. So, everything is moved to directory DateTimeExcel, and that is what is used in the class names.

There are several follow-up activities that I am planning to undertake if this PR is merged.

- ODS supports dates well before 1900. There are exactly 2 assertions for this functionality. More are needed (and some functions might have to change to accept this).
- WEEKDAY has some poorly documented extra options for "style" which are not yet implemented.
- Most tests have been changed to use a formula as entered on a spreadsheet rather than a direct call to the method which implements the formula. There are 3 exceptions at this time. WORKDAY and NETWORKDAYS, which include arrays as part of their parameters, are more complicated than most. YEARFRAC was just too large to deal with now.
- There are direct calls to the now-deprecated methods in both source code and tests, mostly in Financial code, but possibly in others as well. These need to be changed.
- Some constants, none "officially" documented, remain in the original class. These should be either deleted or marked deprecated. I wasn't sure if deprecation was even possible (or desirable), and did not want that to be something which would cause Scrutinizer to fail the change.

* Deprecate Now-unused Constants, Fix Yearfrac bug, Change 3 Tests

Add new DateTime/Constants class, initially populated with constants used in Weeknum.

MS has another inconsistency with how it handles null cells in Yearfrac. Change PhpSpreadsheet to behave compatibly with this bug.

I have modified YearFrac, WorkDay, and NetworkDays tests to be more to my liking. Many tests added to YearFrac because of the bug above. Only minor modifications to the existing tests for the others.
This commit is contained in:
oleibman 2021-03-21 01:12:05 -07:00 committed by GitHub
parent b87d78b206
commit 9beacd21be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
76 changed files with 3874 additions and 3751 deletions

View File

@ -755,17 +755,17 @@ class Calculation
],
'DATE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DATE'],
'functionCall' => [DateTimeExcel\Datefunc::class, 'funcDate'],
'argumentCount' => '3',
],
'DATEDIF' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DATEDIF'],
'functionCall' => [DateTimeExcel\DateDif::class, 'funcDateDif'],
'argumentCount' => '2,3',
],
'DATEVALUE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DATEVALUE'],
'functionCall' => [DateTimeExcel\DateValue::class, 'funcDateValue'],
'argumentCount' => '1',
],
'DAVERAGE' => [
@ -775,17 +775,17 @@ class Calculation
],
'DAY' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DAYOFMONTH'],
'functionCall' => [DateTimeExcel\Day::class, 'funcDay'],
'argumentCount' => '1',
],
'DAYS' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DAYS'],
'functionCall' => [DateTimeExcel\Days::class, 'funcDays'],
'argumentCount' => '2',
],
'DAYS360' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DAYS360'],
'functionCall' => [DateTimeExcel\Days360::class, 'funcDays360'],
'argumentCount' => '2,3',
],
'DB' => [
@ -920,7 +920,7 @@ class Calculation
],
'EDATE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'EDATE'],
'functionCall' => [DateTimeExcel\EDate::class, 'funcEDate'],
'argumentCount' => '2',
],
'EFFECT' => [
@ -935,7 +935,7 @@ class Calculation
],
'EOMONTH' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'EOMONTH'],
'functionCall' => [DateTimeExcel\EoMonth::class, 'funcEoMonth'],
'argumentCount' => '2',
],
'ERF' => [
@ -1237,7 +1237,7 @@ class Calculation
],
'HOUR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'HOUROFDAY'],
'functionCall' => [DateTimeExcel\Hour::class, 'funcHour'],
'argumentCount' => '1',
],
'HYPERLINK' => [
@ -1501,7 +1501,7 @@ class Calculation
],
'ISOWEEKNUM' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'ISOWEEKNUM'],
'functionCall' => [DateTimeExcel\IsoWeekNum::class, 'funcIsoWeekNum'],
'argumentCount' => '1',
],
'ISPMT' => [
@ -1681,7 +1681,7 @@ class Calculation
],
'MINUTE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'MINUTE'],
'functionCall' => [DateTimeExcel\Minute::class, 'funcMinute'],
'argumentCount' => '1',
],
'MINVERSE' => [
@ -1721,7 +1721,7 @@ class Calculation
],
'MONTH' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'MONTHOFYEAR'],
'functionCall' => [DateTimeExcel\Month::class, 'funcMonth'],
'argumentCount' => '1',
],
'MROUND' => [
@ -1761,7 +1761,7 @@ class Calculation
],
'NETWORKDAYS' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'NETWORKDAYS'],
'functionCall' => [DateTimeExcel\NetworkDays::class, 'funcNetworkDays'],
'argumentCount' => '2-3',
],
'NETWORKDAYS.INTL' => [
@ -1821,7 +1821,7 @@ class Calculation
],
'NOW' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DATETIMENOW'],
'functionCall' => [DateTimeExcel\Now::class, 'funcNow'],
'argumentCount' => '0',
],
'NPER' => [
@ -2175,7 +2175,7 @@ class Calculation
],
'SECOND' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'SECOND'],
'functionCall' => [DateTimeExcel\Second::class, 'funcSecond'],
'argumentCount' => '1',
],
'SEQUENCE' => [
@ -2421,12 +2421,12 @@ class Calculation
],
'TIME' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'TIME'],
'functionCall' => [DateTimeExcel\Time::class, 'funcTime'],
'argumentCount' => '3',
],
'TIMEVALUE' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'TIMEVALUE'],
'functionCall' => [DateTimeExcel\TimeValue::class, 'funcTimeValue'],
'argumentCount' => '1',
],
'TINV' => [
@ -2446,7 +2446,7 @@ class Calculation
],
'TODAY' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'DATENOW'],
'functionCall' => [DateTimeExcel\Today::class, 'funcToday'],
'argumentCount' => '0',
],
'TRANSPOSE' => [
@ -2571,12 +2571,12 @@ class Calculation
],
'WEEKDAY' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'WEEKDAY'],
'functionCall' => [DateTimeExcel\WeekDay::class, 'funcWeekDay'],
'argumentCount' => '1,2',
],
'WEEKNUM' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'WEEKNUM'],
'functionCall' => [DateTimeExcel\WeekNum::class, 'funcWeekNum'],
'argumentCount' => '1,2',
],
'WEIBULL' => [
@ -2591,7 +2591,7 @@ class Calculation
],
'WORKDAY' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'WORKDAY'],
'functionCall' => [DateTimeExcel\WorkDay::class, 'funcWorkDay'],
'argumentCount' => '2-3',
],
'WORKDAY.INTL' => [
@ -2626,12 +2626,12 @@ class Calculation
],
'YEAR' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'YEAR'],
'functionCall' => [DateTimeExcel\Year::class, 'funcYear'],
'argumentCount' => '1',
],
'YEARFRAC' => [
'category' => Category::CATEGORY_DATE_AND_TIME,
'functionCall' => [DateTime::class, 'YEARFRAC'],
'functionCall' => [DateTimeExcel\YearFrac::class, 'funcYearFrac'],
'argumentCount' => '2,3',
],
'YIELD' => [

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
class Constants
{
// Constants currently used by WeekNum; will eventually be used by WEEKDAY
const STARTWEEK_SUNDAY = 1;
const STARTWEEK_MONDAY = 2;
const STARTWEEK_MONDAY_ALT = 11;
const STARTWEEK_TUESDAY = 12;
const STARTWEEK_WEDNESDAY = 13;
const STARTWEEK_THURSDAY = 14;
const STARTWEEK_FRIDAY = 15;
const STARTWEEK_SATURDAY = 16;
const STARTWEEK_SUNDAY_ALT = 17;
const DOW_SUNDAY = 1;
const DOW_MONDAY = 2;
const DOW_TUESDAY = 3;
const DOW_WEDNESDAY = 4;
const DOW_THURSDAY = 5;
const DOW_FRIDAY = 6;
const DOW_SATURDAY = 7;
const STARTWEEK_MONDAY_ISO = 21;
const METHODARR = [
self::STARTWEEK_SUNDAY => self::DOW_SUNDAY,
self::DOW_MONDAY,
self::STARTWEEK_MONDAY_ALT => self::DOW_MONDAY,
self::DOW_TUESDAY,
self::DOW_WEDNESDAY,
self::DOW_THURSDAY,
self::DOW_FRIDAY,
self::DOW_SATURDAY,
self::DOW_SUNDAY,
self::STARTWEEK_MONDAY_ISO => self::STARTWEEK_MONDAY_ISO,
];
}

View File

@ -0,0 +1,146 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateInterval;
use DateTime;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class DateDif
{
/**
* DATEDIF.
*
* @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
* or a standard date string
* @param string $unit
*
* @return int|string Interval between the dates
*/
public static function funcDateDif($startDate, $endDate, $unit = 'D')
{
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);
$difference = self::initialDiff($startDate, $endDate);
$unit = strtoupper(Functions::flattenSingleValue($unit));
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPStartDateObject = Date::excelToDateTimeObject($startDate);
$startDays = (int) $PHPStartDateObject->format('j');
$startMonths = (int) $PHPStartDateObject->format('n');
$startYears = (int) $PHPStartDateObject->format('Y');
$PHPEndDateObject = Date::excelToDateTimeObject($endDate);
$endDays = (int) $PHPEndDateObject->format('j');
$endMonths = (int) $PHPEndDateObject->format('n');
$endYears = (int) $PHPEndDateObject->format('Y');
$PHPDiffDateObject = $PHPEndDateObject->diff($PHPStartDateObject);
$retVal = false;
$retVal = self::replaceRetValue($retVal, $unit, 'D') ?? self::datedifD($difference);
$retVal = self::replaceRetValue($retVal, $unit, 'M') ?? self::datedifM($PHPDiffDateObject);
$retVal = self::replaceRetValue($retVal, $unit, 'MD') ?? self::datedifMD($startDays, $endDays, $PHPEndDateObject, $PHPDiffDateObject);
$retVal = self::replaceRetValue($retVal, $unit, 'Y') ?? self::datedifY($PHPDiffDateObject);
$retVal = self::replaceRetValue($retVal, $unit, 'YD') ?? self::datedifYD($difference, $startYears, $endYears, $PHPStartDateObject, $PHPEndDateObject);
$retVal = self::replaceRetValue($retVal, $unit, 'YM') ?? self::datedifYM($PHPDiffDateObject);
return is_bool($retVal) ? Functions::VALUE() : $retVal;
}
private static function initialDiff(float $startDate, float $endDate): float
{
// Validate parameters
if ($startDate > $endDate) {
throw new Exception(Functions::NAN());
}
return $endDate - $startDate;
}
/**
* Decide whether it's time to set retVal.
*
* @param bool|int $retVal
*
* @return null|bool|int
*/
private static function replaceRetValue($retVal, string $unit, string $compare)
{
if ($retVal !== false || $unit !== $compare) {
return $retVal;
}
return null;
}
private static function datedifD(float $difference): int
{
return (int) $difference;
}
private static function datedifM(DateInterval $PHPDiffDateObject): int
{
return (int) 12 * $PHPDiffDateObject->format('%y') + $PHPDiffDateObject->format('%m');
}
private static function datedifMD(int $startDays, int $endDays, DateTime $PHPEndDateObject, DateInterval $PHPDiffDateObject): int
{
if ($endDays < $startDays) {
$retVal = $endDays;
$PHPEndDateObject->modify('-' . $endDays . ' days');
$adjustDays = (int) $PHPEndDateObject->format('j');
$retVal += ($adjustDays - $startDays);
} else {
$retVal = (int) $PHPDiffDateObject->format('%d');
}
return $retVal;
}
private static function datedifY(DateInterval $PHPDiffDateObject): int
{
return (int) $PHPDiffDateObject->format('%y');
}
private static function datedifYD(float $difference, int $startYears, int $endYears, DateTime $PHPStartDateObject, DateTime $PHPEndDateObject): int
{
$retVal = (int) $difference;
if ($endYears > $startYears) {
$isLeapStartYear = $PHPStartDateObject->format('L');
$wasLeapEndYear = $PHPEndDateObject->format('L');
// Adjust end year to be as close as possible as start year
while ($PHPEndDateObject >= $PHPStartDateObject) {
$PHPEndDateObject->modify('-1 year');
$endYears = $PHPEndDateObject->format('Y');
}
$PHPEndDateObject->modify('+1 year');
// Get the result
$retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days;
// Adjust for leap years cases
$isLeapEndYear = $PHPEndDateObject->format('L');
$limit = new DateTime($PHPEndDateObject->format('Y-02-29'));
if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) {
--$retVal;
}
}
return (int) $retVal;
}
private static function datedifYM(DateInterval $PHPDiffDateObject): int
{
return (int) $PHPDiffDateObject->format('%m');
}
}

View File

@ -0,0 +1,151 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class DateValue
{
/**
* DATEVALUE.
*
* Returns a value that represents a particular date.
* Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
* value.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
* format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* DATEVALUE(dateValue)
*
* @param string $dateValue Text that represents a date in a Microsoft Excel date format.
* For example, "1/30/2008" or "30-Jan-2008" are text strings within
* quotation marks that represent dates. Using the default date
* system in Excel for Windows, date_text must represent a date from
* January 1, 1900, to December 31, 9999. Using the default date
* system in Excel for the Macintosh, date_text must represent a date
* from January 1, 1904, to December 31, 9999. DATEVALUE returns the
* #VALUE! error value if date_text is out of this range.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcDateValue($dateValue = 1)
{
$dti = new DateTimeImmutable();
$baseYear = Date::getExcelCalendar();
$dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
// Strip any ordinals because they're allowed in Excel (English only)
$dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
// Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
$dateValue = str_replace(['/', '.', '-', ' '], ' ', $dateValue);
$yearFound = false;
$t1 = explode(' ', $dateValue);
$t = '';
foreach ($t1 as &$t) {
if ((is_numeric($t)) && ($t > 31)) {
if ($yearFound) {
return Functions::VALUE();
}
if ($t < 100) {
$t += 1900;
}
$yearFound = true;
}
}
if (count($t1) === 1) {
// We've been fed a time value without any date
return ((strpos($t, ':') === false)) ? Functions::Value() : 0.0;
}
unset($t);
$dateValue = self::t1ToString($t1, $dti, $yearFound);
$PHPDateArray = self::setUpArray($dateValue, $dti);
return self::finalResults($PHPDateArray, $dti, $baseYear);
}
private static function t1ToString(array $t1, DateTimeImmutable $dti, bool $yearFound): string
{
if (count($t1) == 2) {
// We only have two parts of the date: either day/month or month/year
if ($yearFound) {
array_unshift($t1, 1);
} else {
if (is_numeric($t1[1]) && $t1[1] > 29) {
$t1[1] += 1900;
array_unshift($t1, 1);
} else {
$t1[] = $dti->format('Y');
}
}
}
$dateValue = implode(' ', $t1);
return $dateValue;
}
/**
* Parse date.
*
* @return array|bool
*/
private static function setUpArray(string $dateValue, DateTimeImmutable $dti)
{
$PHPDateArray = date_parse($dateValue);
if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
// If original count was 1, we've already returned.
// If it was 2, we added another.
// Therefore, neither of the first 2 stroks below can fail.
$testVal1 = strtok($dateValue, '- ');
$testVal2 = strtok('- ');
$testVal3 = strtok('- ') ?: $dti->format('Y');
Helpers::adjustYear($testVal1, $testVal2, $testVal3);
$PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3);
if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
$PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3);
}
}
return $PHPDateArray;
}
/**
* Final results.
*
* @param array|false $PHPDateArray
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
private static function finalResults($PHPDateArray, DateTimeImmutable $dti, int $baseYear)
{
$retValue = Functions::Value();
if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
// Execute function
Helpers::replaceIfEmpty($PHPDateArray['year'], $dti->format('Y'));
if ($PHPDateArray['year'] < $baseYear) {
return Functions::VALUE();
}
Helpers::replaceIfEmpty($PHPDateArray['month'], $dti->format('m'));
Helpers::replaceIfEmpty($PHPDateArray['day'], $dti->format('d'));
$PHPDateArray['hour'] = 0;
$PHPDateArray['minute'] = 0;
$PHPDateArray['second'] = 0;
$month = (int) $PHPDateArray['month'];
$day = (int) $PHPDateArray['day'];
$year = (int) $PHPDateArray['year'];
if (!checkdate($month, $day, $year)) {
return ($year === 1900 && $month === 2 && $day === 29) ? Helpers::returnIn3FormatsFloat(60.0) : Functions::VALUE();
}
$retValue = Helpers::returnIn3FormatsArray($PHPDateArray, true);
}
return $retValue;
}
}

View File

@ -0,0 +1,168 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
class Datefunc
{
/**
* DATE.
*
* The DATE function returns a value that represents a particular date.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
* format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* DATE(year,month,day)
*
* PhpSpreadsheet is a lot more forgiving than MS Excel when passing non numeric values to this function.
* A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
* as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
*
* @param int $year The value of the year argument can include one to four digits.
* Excel interprets the year argument according to the configured
* date system: 1900 or 1904.
* If year is between 0 (zero) and 1899 (inclusive), Excel adds that
* value to 1900 to calculate the year. For example, DATE(108,1,2)
* returns January 2, 2008 (1900+108).
* If year is between 1900 and 9999 (inclusive), Excel uses that
* value as the year. For example, DATE(2008,1,2) returns January 2,
* 2008.
* If year is less than 0 or is 10000 or greater, Excel returns the
* #NUM! error value.
* @param int $month A positive or negative integer representing the month of the year
* from 1 to 12 (January to December).
* If month is greater than 12, month adds that number of months to
* the first month in the year specified. For example, DATE(2008,14,2)
* returns the serial number representing February 2, 2009.
* If month is less than 1, month subtracts the magnitude of that
* number of months, plus 1, from the first month in the year
* specified. For example, DATE(2008,-3,2) returns the serial number
* representing September 2, 2007.
* @param int $day A positive or negative integer representing the day of the month
* from 1 to 31.
* If day is greater than the number of days in the month specified,
* day adds that number of days to the first day in the month. For
* example, DATE(2008,1,35) returns the serial number representing
* February 4, 2008.
* If day is less than 1, day subtracts the magnitude that number of
* days, plus one, from the first day of the month specified. For
* example, DATE(2008,1,-15) returns the serial number representing
* December 16, 2007.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcDate($year, $month, $day)
{
$baseYear = Date::getExcelCalendar();
try {
$year = self::getYear($year, $baseYear);
$month = self::getMonth($month);
$day = self::getDay($day);
self::adjustYearMonth($year, $month, $baseYear);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$excelDateValue = Date::formattedPHPToExcel($year, $month, $day);
return Helpers::returnIn3FormatsFloat($excelDateValue);
}
/**
* Convert year from multiple formats to int.
*
* @param mixed $year
*/
private static function getYear($year, int $baseYear): int
{
$year = Functions::flattenSingleValue($year);
$year = ($year !== null) ? StringHelper::testStringAsNumeric($year) : 0;
if (!is_numeric($year)) {
throw new Exception(Functions::VALUE());
}
$year = (int) $year;
if ($year < ($baseYear - 1900)) {
throw new Exception(Functions::NAN());
}
if ((($baseYear - 1900) !== 0) && ($year < $baseYear) && ($year >= 1900)) {
throw new Exception(Functions::NAN());
}
if (($year < $baseYear) && ($year >= ($baseYear - 1900))) {
$year += 1900;
}
return $year;
}
/**
* Convert month from multiple formats to int.
*
* @param mixed $month
*/
private static function getMonth($month): int
{
$month = Functions::flattenSingleValue($month);
if (($month !== null) && (!is_numeric($month))) {
$month = Date::monthStringToNumber($month);
}
$month = ($month !== null) ? StringHelper::testStringAsNumeric($month) : 0;
if (!is_numeric($month)) {
throw new Exception(Functions::VALUE());
}
return (int) $month;
}
/**
* Convert day from multiple formats to int.
*
* @param mixed $day
*/
private static function getDay($day): int
{
$day = Functions::flattenSingleValue($day);
if (($day !== null) && (!is_numeric($day))) {
$day = Date::dayStringToNumber($day);
}
$day = ($day !== null) ? StringHelper::testStringAsNumeric($day) : 0;
if (!is_numeric($day)) {
throw new Exception(Functions::VALUE());
}
return (int) $day;
}
private static function adjustYearMonth(int &$year, int &$month, int $baseYear): void
{
if ($month < 1) {
// Handle year/month adjustment if month < 1
--$month;
$year += ceil($month / 12) - 1;
$month = 13 - abs($month % 12);
} elseif ($month > 12) {
// Handle year/month adjustment if month > 12
$year += floor($month / 12);
$month = ($month % 12);
}
// Re-validate the year parameter after adjustments
if (($year < $baseYear) || ($year >= 10000)) {
throw new Exception(Functions::NAN());
}
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Day
{
/**
* DAYOFMONTH.
*
* Returns the day of the month, for a specified date. The day is given as an integer
* ranging from 1 to 31.
*
* Excel Function:
* DAY(dateValue)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Day of the month
*/
public static function funcDay($dateValue)
{
$weirdResult = self::weirdCondition($dateValue);
if ($weirdResult >= 0) {
return $weirdResult;
}
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
return (int) $PHPDateObject->format('j');
}
private static function weirdCondition($dateValue): int
{
// Excel does not treat 0 consistently for DAY vs. (MONTH or YEAR)
if (Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900 && Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) {
if (is_bool($dateValue)) {
return (int) $dateValue;
}
if ($dateValue === null) {
return 0;
}
if (is_numeric($dateValue) && $dateValue < 1 && $dateValue >= 0) {
return 0;
}
}
return -1;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeInterface;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Days
{
/**
* DAYS.
*
* Returns the number of days between two dates
*
* Excel Function:
* DAYS(endDate, startDate)
*
* @param DateTimeInterface|float|int|string $endDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
* @param DateTimeInterface|float|int|string $startDate Excel date serial value (float),
* PHP date timestamp (integer), PHP DateTime object, or a standard date string
*
* @return int|string Number of days between start date and end date or an error
*/
public static function funcDays($endDate, $startDate)
{
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPStartDateObject = Date::excelToDateTimeObject($startDate);
$PHPEndDateObject = Date::excelToDateTimeObject($endDate);
$days = Functions::VALUE();
$diff = $PHPStartDateObject->diff($PHPEndDateObject);
if ($diff !== false && !is_bool($diff->days)) {
$days = $diff->days;
if ($diff->invert) {
$days = -$days;
}
}
return $days;
}
}

View File

@ -0,0 +1,106 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Days360
{
/**
* DAYS360.
*
* Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
* which is used in some accounting calculations. Use this function to help compute payments if
* your accounting system is based on twelve 30-day months.
*
* Excel Function:
* DAYS360(startDate,endDate[,method])
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param bool $method US or European Method
* FALSE or omitted: U.S. (NASD) method. If the starting date is
* the last day of a month, it becomes equal to the 30th of the
* same month. If the ending date is the last day of a month and
* the starting date is earlier than the 30th of a month, the
* ending date becomes equal to the 1st of the next month;
* otherwise the ending date becomes equal to the 30th of the
* same month.
* TRUE: European method. Starting dates and ending dates that
* occur on the 31st of a month become equal to the 30th of the
* same month.
*
* @return int|string Number of days between start date and end date
*/
public static function funcDays360($startDate = 0, $endDate = 0, $method = false)
{
try {
$startDate = Helpers::getDateValue($startDate);
$endDate = Helpers::getDateValue($endDate);
} catch (Exception $e) {
return $e->getMessage();
}
if (!is_bool($method)) {
return Functions::VALUE();
}
// Execute function
$PHPStartDateObject = Date::excelToDateTimeObject($startDate);
$startDay = $PHPStartDateObject->format('j');
$startMonth = $PHPStartDateObject->format('n');
$startYear = $PHPStartDateObject->format('Y');
$PHPEndDateObject = Date::excelToDateTimeObject($endDate);
$endDay = $PHPEndDateObject->format('j');
$endMonth = $PHPEndDateObject->format('n');
$endYear = $PHPEndDateObject->format('Y');
return self::dateDiff360((int) $startDay, (int) $startMonth, (int) $startYear, (int) $endDay, (int) $endMonth, (int) $endYear, !$method);
}
/**
* Return the number of days between two dates based on a 360 day calendar.
*/
private static function dateDiff360(int $startDay, int $startMonth, int $startYear, int $endDay, int $endMonth, int $endYear, bool $methodUS): int
{
$startDay = self::getStartDay($startDay, $startMonth, $startYear, $methodUS);
$endDay = self::getEndDay($endDay, $endMonth, $endYear, $startDay, $methodUS);
return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
}
private static function getStartDay(int $startDay, int $startMonth, int $startYear, bool $methodUS): int
{
if ($startDay == 31) {
--$startDay;
} elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !Helpers::isLeapYear($startYear))))) {
$startDay = 30;
}
return $startDay;
}
private static function getEndDay(int $endDay, int &$endMonth, int &$endYear, int $startDay, bool $methodUS): int
{
if ($endDay == 31) {
if ($methodUS && $startDay != 30) {
$endDay = 1;
if ($endMonth == 12) {
++$endYear;
$endMonth = 1;
} else {
++$endMonth;
}
} else {
$endDay = 30;
}
}
return $endDay;
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class EDate
{
/**
* EDATE.
*
* Returns the serial number that represents the date that is the indicated number of months
* before or after a specified date (the start_date).
* Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
* as the date of issue.
*
* Excel Function:
* EDATE(dateValue,adjustmentMonths)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcEDate($dateValue, $adjustmentMonths)
{
try {
$dateValue = Helpers::getDateValue($dateValue, false);
$adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths);
} catch (Exception $e) {
return $e->getMessage();
}
$adjustmentMonths = floor($adjustmentMonths);
// Execute function
$PHPDateObject = Helpers::adjustDateByMonths($dateValue, $adjustmentMonths);
return Helpers::returnIn3FormatsObject($PHPDateObject);
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class EoMonth
{
/**
* EOMONTH.
*
* Returns the date value for the last day of the month that is the indicated number of months
* before or after start_date.
* Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
*
* Excel Function:
* EOMONTH(dateValue,adjustmentMonths)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $adjustmentMonths The number of months before or after start_date.
* A positive value for months yields a future date;
* a negative value yields a past date.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcEoMonth($dateValue, $adjustmentMonths)
{
try {
$dateValue = Helpers::getDateValue($dateValue, false);
$adjustmentMonths = Helpers::validateNumericNull($adjustmentMonths);
} catch (Exception $e) {
return $e->getMessage();
}
$adjustmentMonths = floor($adjustmentMonths);
// Execute function
$PHPDateObject = Helpers::adjustDateByMonths($dateValue, $adjustmentMonths + 1);
$adjustDays = (int) $PHPDateObject->format('d');
$adjustDaysString = '-' . $adjustDays . ' days';
$PHPDateObject->modify($adjustDaysString);
return Helpers::returnIn3FormatsObject($PHPDateObject);
}
}

View File

@ -0,0 +1,291 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Helpers
{
/**
* Identify if a year is a leap year or not.
*
* @param int|string $year The year to test
*
* @return bool TRUE if the year is a leap year, otherwise FALSE
*/
public static function isLeapYear($year)
{
return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0);
}
/**
* getDateValue.
*
* @param mixed $dateValue
*
* @return float Excel date/time serial value
*/
public static function getDateValue($dateValue, bool $allowBool = true)
{
if (is_object($dateValue)) {
$retval = Date::PHPToExcel($dateValue);
if (is_bool($retval)) {
throw new Exception(Functions::VALUE());
}
return $retval;
}
self::nullFalseTrueToNumber($dateValue, $allowBool);
if (!is_numeric($dateValue)) {
$saveReturnDateType = Functions::getReturnDateType();
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
$dateValue = DateValue::funcDateValue($dateValue);
Functions::setReturnDateType($saveReturnDateType);
if (!is_numeric($dateValue)) {
throw new Exception(Functions::VALUE());
}
}
if ($dateValue < 0 && Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE) {
throw new Exception(Functions::NAN());
}
return (float) $dateValue;
}
/**
* getDateValueNoThrow.
*
* @param mixed $dateValue
*
* @return mixed Excel date/time serial value, or string if error
*/
public static function getDateValueNoThrow($dateValue)
{
try {
return self::getDateValue($dateValue);
} catch (Exception $e) {
return $e->getMessage();
}
}
/**
* getTimeValue.
*
* @param string $timeValue
*
* @return mixed Excel date/time serial value, or string if error
*/
public static function getTimeValue($timeValue)
{
$saveReturnDateType = Functions::getReturnDateType();
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
$timeValue = TimeValue::funcTimeValue($timeValue);
Functions::setReturnDateType($saveReturnDateType);
return $timeValue;
}
public static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0)
{
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
$oMonth = (int) $PHPDateObject->format('m');
$oYear = (int) $PHPDateObject->format('Y');
$adjustmentMonthsString = (string) $adjustmentMonths;
if ($adjustmentMonths > 0) {
$adjustmentMonthsString = '+' . $adjustmentMonths;
}
if ($adjustmentMonths != 0) {
$PHPDateObject->modify($adjustmentMonthsString . ' months');
}
$nMonth = (int) $PHPDateObject->format('m');
$nYear = (int) $PHPDateObject->format('Y');
$monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
if ($monthDiff != $adjustmentMonths) {
$adjustDays = (int) $PHPDateObject->format('d');
$adjustDaysString = '-' . $adjustDays . ' days';
$PHPDateObject->modify($adjustDaysString);
}
return $PHPDateObject;
}
/**
* Help reduce perceived complexity of some tests.
*
* @param mixed $value
* @param mixed $altValue
*/
public static function replaceIfEmpty(&$value, $altValue): void
{
$value = $value ?: $altValue;
}
/**
* Adjust year in ambiguous situations.
*/
public static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void
{
if (!is_numeric($testVal1) || $testVal1 < 31) {
if (!is_numeric($testVal2) || $testVal2 < 12) {
if (is_numeric($testVal3) && $testVal3 < 12) {
$testVal3 += 2000;
}
}
}
}
/**
* Return result in one of three formats.
*
* @return mixed
*/
public static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false)
{
$retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) {
return new DateTime(
$dateArray['year']
. '-' . $dateArray['month']
. '-' . $dateArray['day']
. ' ' . $dateArray['hour']
. ':' . $dateArray['minute']
. ':' . $dateArray['second']
);
}
$excelDateValue =
Date::formattedPHPToExcel(
$dateArray['year'],
$dateArray['month'],
$dateArray['day'],
$dateArray['hour'],
$dateArray['minute'],
$dateArray['second']
);
if ($retType === Functions::RETURNDATE_EXCEL) {
return $noFrac ? floor($excelDateValue) : (float) $excelDateValue;
}
// RETURNDATE_UNIX_TIMESTAMP)
return (int) Date::excelToTimestamp($excelDateValue);
}
/**
* Return result in one of three formats.
*
* @return mixed
*/
public static function returnIn3FormatsFloat(float $excelDateValue)
{
$retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_EXCEL) {
return $excelDateValue;
}
if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) {
return (int) Date::excelToTimestamp($excelDateValue);
}
// RETURNDATE_PHP_DATETIME_OBJECT
return Date::excelToDateTimeObject($excelDateValue);
}
/**
* Return result in one of three formats.
*
* @return mixed
*/
public static function returnIn3FormatsObject(DateTime $PHPDateObject)
{
$retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) {
return $PHPDateObject;
}
if ($retType === Functions::RETURNDATE_EXCEL) {
return (float) Date::PHPToExcel($PHPDateObject);
}
// RETURNDATE_UNIX_TIMESTAMP
return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
}
private static function baseDate(): int
{
if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) {
return 0;
}
if (Date::getExcelCalendar() === Date::CALENDAR_MAC_1904) {
return 0;
}
return 1;
}
/**
* Many functions accept null/false/true argument treated as 0/0/1.
*
* @param mixed $number
*/
public static function nullFalseTrueToNumber(&$number, bool $allowBool = true): void
{
$number = Functions::flattenSingleValue($number);
$nullVal = self::baseDate();
if ($number === null) {
$number = $nullVal;
} elseif ($allowBool && is_bool($number)) {
$number = $nullVal + (int) $number;
}
}
/**
* Many functions accept null argument treated as 0.
*
* @param mixed $number
*
* @return float|int
*/
public static function validateNumericNull($number)
{
$number = Functions::flattenSingleValue($number);
if ($number === null) {
return 0;
}
if (is_numeric($number)) {
return $number;
}
throw new Exception(Functions::VALUE());
}
/**
* Many functions accept null/false/true argument treated as 0/0/1.
*
* @param mixed $number
*
* @return float
*/
public static function validateNotNegative($number)
{
if (!is_numeric($number)) {
throw new Exception(Functions::VALUE());
}
if ($number >= 0) {
return (float) $number;
}
throw new Exception(Functions::NAN());
}
public static function silly1900(DateTime $PHPDateObject, string $mod = '-1 day'): void
{
$isoDate = $PHPDateObject->format('c');
if ($isoDate < '1900-03-01') {
$PHPDateObject->modify($mod);
}
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Hour
{
/**
* HOUROFDAY.
*
* Returns the hour of a time value.
* The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
*
* Excel Function:
* HOUR(timeValue)
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Hour
*/
public static function funcHour($timeValue)
{
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$timeValue = fmod($timeValue, 1);
$timeValue = Date::excelToDateTimeObject($timeValue);
return (int) $timeValue->format('H');
}
}

View File

@ -0,0 +1,55 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class IsoWeekNum
{
/**
* ISOWEEKNUM.
*
* Returns the ISO 8601 week number of the year for a specified date.
*
* Excel Function:
* ISOWEEKNUM(dateValue)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Week Number
*/
public static function funcIsoWeekNum($dateValue)
{
if (self::apparentBug($dateValue)) {
return 52;
}
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
Helpers::silly1900($PHPDateObject);
return (int) $PHPDateObject->format('W');
}
private static function apparentBug($dateValue): bool
{
if (Date::getExcelCalendar() !== DATE::CALENDAR_MAC_1904) {
if (is_bool($dateValue)) {
return true;
}
if (is_numeric($dateValue) && !((int) $dateValue)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Minute
{
/**
* MINUTE.
*
* Returns the minutes of a time value.
* The minute is given as an integer, ranging from 0 to 59.
*
* Excel Function:
* MINUTE(timeValue)
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Minute
*/
public static function funcMinute($timeValue)
{
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$timeValue = fmod($timeValue, 1);
$timeValue = Date::excelToDateTimeObject($timeValue);
return (int) $timeValue->format('i');
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Month
{
/**
* MONTHOFYEAR.
*
* Returns the month of a date represented by a serial number.
* The month is given as an integer, ranging from 1 (January) to 12 (December).
*
* Excel Function:
* MONTH(dateValue)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Month of the year
*/
public static function funcMonth($dateValue)
{
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {
return $e->getMessage();
}
if ($dateValue < 1 && Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900) {
return 1;
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
return (int) $PHPDateObject->format('n');
}
}

View File

@ -0,0 +1,102 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class NetworkDays
{
/**
* NETWORKDAYS.
*
* Returns the number of whole working days between start_date and end_date. Working days
* exclude weekends and any dates identified in holidays.
* Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
* worked during a specific term.
*
* Excel Function:
* NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Interval between the dates
*/
public static function funcNetworkDays($startDate, $endDate, ...$dateArgs)
{
try {
// Retrieve the mandatory start and end date that are referenced in the function definition
$sDate = Helpers::getDateValue($startDate);
$eDate = Helpers::getDateValue($endDate);
$startDate = min($sDate, $eDate);
$endDate = max($sDate, $eDate);
// Get the optional days
$dateArgs = Functions::flattenArray($dateArgs);
// Test any extra holiday parameters
$holidayArray = [];
foreach ($dateArgs as $holidayDate) {
$holidayArray[] = Helpers::getDateValue($holidayDate);
}
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$startDow = self::calcStartDow($startDate);
$endDow = self::calcEndDow($endDate);
$wholeWeekDays = (int) floor(($endDate - $startDate) / 7) * 5;
$partWeekDays = self::calcPartWeekDays($startDow, $endDow);
// Test any extra holiday parameters
$holidayCountedArray = [];
foreach ($holidayArray as $holidayDate) {
if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
if ((WeekDay::funcWeekDay($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
--$partWeekDays;
$holidayCountedArray[] = $holidayDate;
}
}
}
return self::applySign($wholeWeekDays + $partWeekDays, $sDate, $eDate);
}
private static function calcStartDow(float $startDate): int
{
$startDow = 6 - (int) WeekDay::funcWeekDay($startDate, 2);
if ($startDow < 0) {
$startDow = 5;
}
return $startDow;
}
private static function calcEndDow(float $endDate): int
{
$endDow = (int) WeekDay::funcWeekDay($endDate, 2);
if ($endDow >= 6) {
$endDow = 0;
}
return $endDow;
}
private static function calcPartWeekDays(int $startDow, int $endDow): int
{
$partWeekDays = $endDow + $startDow;
if ($partWeekDays > 5) {
$partWeekDays -= 5;
}
return $partWeekDays;
}
private static function applySign(int $result, float $sDate, float $eDate)
{
return ($sDate > $eDate) ? -$result : $result;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Now
{
/**
* DATETIMENOW.
*
* Returns the current date and time.
* The NOW function is useful when you need to display the current date and time on a worksheet or
* calculate a value based on the current date and time, and have that value updated each time you
* open the worksheet.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
* and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* NOW()
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcNow()
{
$dti = new DateTimeImmutable();
$dateArray = date_parse($dti->format('c'));
return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray) : Functions::VALUE();
}
}

View File

@ -0,0 +1,44 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Second
{
/**
* MINUTE.
*
* Returns the minutes of a time value.
* The minute is given as an integer, ranging from 0 to 59.
*
* Excel Function:
* MINUTE(timeValue)
*
* @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard time string
*
* @return int|string Minute
*/
public static function funcSecond($timeValue)
{
try {
$timeValue = Functions::flattenSingleValue($timeValue);
Helpers::nullFalseTrueToNumber($timeValue);
if (!is_numeric($timeValue)) {
$timeValue = Helpers::getTimeValue($timeValue);
}
Helpers::validateNotNegative($timeValue);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$timeValue = fmod($timeValue, 1);
$timeValue = Date::excelToDateTimeObject($timeValue);
return (int) $timeValue->format('s');
}
}

View File

@ -0,0 +1,116 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Time
{
/**
* TIME.
*
* The TIME function returns a value that represents a particular time.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
* format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* TIME(hour,minute,second)
*
* @param int $hour A number from 0 (zero) to 32767 representing the hour.
* Any value greater than 23 will be divided by 24 and the remainder
* will be treated as the hour value. For example, TIME(27,0,0) =
* TIME(3,0,0) = .125 or 3:00 AM.
* @param int $minute A number from 0 to 32767 representing the minute.
* Any value greater than 59 will be converted to hours and minutes.
* For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
* @param int $second A number from 0 to 32767 representing the second.
* Any value greater than 59 will be converted to hours, minutes,
* and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
* or 12:33:20 AM
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcTime($hour, $minute, $second)
{
try {
$hour = self::toIntWithNullBool($hour);
$minute = self::toIntWithNullBool($minute);
$second = self::toIntWithNullBool($second);
} catch (Exception $e) {
return $e->getMessage();
}
self::adjustSecond($second, $minute);
self::adjustMinute($minute, $hour);
if ($hour > 23) {
$hour = $hour % 24;
} elseif ($hour < 0) {
return Functions::NAN();
}
// Execute function
$retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_EXCEL) {
$calendar = Date::getExcelCalendar();
$date = (int) ($calendar !== Date::CALENDAR_WINDOWS_1900);
return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
}
if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) {
return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; // -2147472000 + 3600
}
// RETURNDATE_PHP_DATETIME_OBJECT
// Hour has already been normalized (0-23) above
$phpDateObject = new DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second);
return $phpDateObject;
}
private static function adjustSecond(int &$second, int &$minute): void
{
if ($second < 0) {
$minute += floor($second / 60);
$second = 60 - abs($second % 60);
if ($second == 60) {
$second = 0;
}
} elseif ($second >= 60) {
$minute += floor($second / 60);
$second = $second % 60;
}
}
private static function adjustMinute(int &$minute, int &$hour): void
{
if ($minute < 0) {
$hour += floor($minute / 60);
$minute = 60 - abs($minute % 60);
if ($minute == 60) {
$minute = 0;
}
} elseif ($minute >= 60) {
$hour += floor($minute / 60);
$minute = $minute % 60;
}
}
private static function toIntWithNullBool($value): int
{
$value = Functions::flattenSingleValue($value);
$value = $value ?? 0;
if (is_bool($value)) {
$value = (int) $value;
}
if (!is_numeric($value)) {
throw new Exception(Functions::VALUE());
}
return (int) $value;
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Datetime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class TimeValue
{
/**
* TIMEVALUE.
*
* Returns a value that represents a particular time.
* Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
* value.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
* format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* TIMEVALUE(timeValue)
*
* @param string $timeValue A text string that represents a time in any one of the Microsoft
* Excel time formats; for example, "6:45 PM" and "18:45" text strings
* within quotation marks that represent time.
* Date information in time_text is ignored.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcTimeValue($timeValue)
{
$timeValue = trim(Functions::flattenSingleValue($timeValue), '"');
$timeValue = str_replace(['/', '.'], '-', $timeValue);
$arraySplit = preg_split('/[\/:\-\s]/', $timeValue);
if ((count($arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) {
$arraySplit[0] = ($arraySplit[0] % 24);
$timeValue = implode(':', $arraySplit);
}
$PHPDateArray = date_parse($timeValue);
$retValue = Functions::VALUE();
if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
// OpenOffice-specific code removed - it works just like Excel
$excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
$retType = Functions::getReturnDateType();
if ($retType === Functions::RETURNDATE_EXCEL) {
$retValue = (float) $excelDateValue;
} elseif ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) {
$retValue = (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600;
} else {
$retValue = new DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
}
}
return $retValue;
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
class Today
{
/**
* DATENOW.
*
* Returns the current date.
* The NOW function is useful when you need to display the current date and time on a worksheet or
* calculate a value based on the current date and time, and have that value updated each time you
* open the worksheet.
*
* NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
* and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
*
* Excel Function:
* TODAY()
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcToday()
{
$dti = new DateTimeImmutable();
$dateArray = date_parse($dti->format('c'));
return is_array($dateArray) ? Helpers::returnIn3FormatsArray($dateArray, true) : Functions::VALUE();
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class WeekDay
{
/**
* WEEKDAY.
*
* Returns the day of the week for a specified date. The day is given as an integer
* ranging from 0 to 7 (dependent on the requested style).
*
* Excel Function:
* WEEKDAY(dateValue[,style])
*
* @param float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $style A number that determines the type of return value
* 1 or omitted Numbers 1 (Sunday) through 7 (Saturday).
* 2 Numbers 1 (Monday) through 7 (Sunday).
* 3 Numbers 0 (Monday) through 6 (Sunday).
*
* @return int|string Day of the week value
*/
public static function funcWeekDay($dateValue, $style = 1)
{
try {
$dateValue = Helpers::getDateValue($dateValue);
$style = self::validateStyle($style);
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
Helpers::silly1900($PHPDateObject);
$DoW = (int) $PHPDateObject->format('w');
switch ($style) {
case 1:
++$DoW;
break;
case 2:
$DoW = self::dow0Becomes7($DoW);
break;
case 3:
$DoW = self::dow0Becomes7($DoW) - 1;
break;
}
return $DoW;
}
private static function validateStyle($style): int
{
$style = Functions::flattenSingleValue($style);
if (!is_numeric($style)) {
throw new Exception(Functions::VALUE());
}
$style = (int) $style;
if (($style < 1) || ($style > 3)) {
throw new Exception(Functions::NAN());
}
return $style;
}
private static function dow0Becomes7(int $DoW): int
{
return ($DoW === 0) ? 7 : $DoW;
}
}

View File

@ -0,0 +1,130 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use DateTime;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class WeekNum
{
/**
* WEEKNUM.
*
* Returns the week of the year for a specified date.
* The WEEKNUM function considers the week containing January 1 to be the first week of the year.
* However, there is a European standard that defines the first week as the one with the majority
* of days (four or more) falling in the new year. This means that for years in which there are
* three days or less in the first week of January, the WEEKNUM function returns week numbers
* that are incorrect according to the European standard.
*
* Excel Function:
* WEEKNUM(dateValue[,style])
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $method Week begins on Sunday or Monday
* 1 or omitted Week begins on Sunday.
* 2 Week begins on Monday.
* 11 Week begins on Monday.
* 12 Week begins on Tuesday.
* 13 Week begins on Wednesday.
* 14 Week begins on Thursday.
* 15 Week begins on Friday.
* 16 Week begins on Saturday.
* 17 Week begins on Sunday.
* 21 ISO (Jan. 4 is week 1, begins on Monday).
*
* @return int|string Week Number
*/
public static function funcWeekNum($dateValue, $method = Constants::STARTWEEK_SUNDAY)
{
$origDateValueNull = empty($dateValue);
try {
$method = self::validateMethod($method);
if ($dateValue === null) { // boolean not allowed
$dateValue = (Date::getExcelCalendar() === DATE::CALENDAR_MAC_1904 || $method === Constants::DOW_SUNDAY) ? 0 : 1;
}
$dateValue = self::validateDateValue($dateValue);
if (!$dateValue && self::buggyWeekNum1900($method)) {
// This seems to be an additional Excel bug.
return 0;
}
} catch (Exception $e) {
return $e->getMessage();
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
if ($method == Constants::STARTWEEK_MONDAY_ISO) {
Helpers::silly1900($PHPDateObject);
return (int) $PHPDateObject->format('W');
}
if (self::buggyWeekNum1904($method, $origDateValueNull, $PHPDateObject)) {
return 0;
}
Helpers::silly1900($PHPDateObject, '+ 5 years'); // 1905 calendar matches
$dayOfYear = $PHPDateObject->format('z');
$PHPDateObject->modify('-' . $dayOfYear . ' days');
$firstDayOfFirstWeek = $PHPDateObject->format('w');
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
$daysInFirstWeek += 7 * !$daysInFirstWeek;
$endFirstWeek = $daysInFirstWeek - 1;
$weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7);
return (int) $weekOfYear;
}
/**
* Validate dateValue parameter.
*
* @param mixed $dateValue
*/
private static function validateDateValue($dateValue): float
{
if (is_bool($dateValue)) {
throw new Exception(Functions::VALUE());
}
return Helpers::getDateValue($dateValue);
}
/**
* Validate method parameter.
*
* @param mixed $method
*/
private static function validateMethod($method): int
{
if ($method === null) {
$method = Constants::STARTWEEK_SUNDAY;
}
$method = Functions::flattenSingleValue($method);
if (!is_numeric($method)) {
throw new Exception(Functions::VALUE());
}
$method = (int) $method;
if (!array_key_exists($method, Constants::METHODARR)) {
throw new Exception(Functions::NAN());
}
$method = Constants::METHODARR[$method];
return $method;
}
private static function buggyWeekNum1900(int $method): bool
{
return $method === Constants::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_WINDOWS_1900;
}
private static function buggyWeekNum1904(int $method, bool $origNull, DateTime $dateObject): bool
{
// This appears to be another Excel bug.
return $method === Constants::DOW_SUNDAY && Date::getExcelCalendar() === Date::CALENDAR_MAC_1904 && !$origNull && $dateObject->format('Y-m-d') === '1904-01-01';
}
}

View File

@ -0,0 +1,182 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class WorkDay
{
/**
* WORKDAY.
*
* Returns the date that is the indicated number of working days before or after a date (the
* starting date). Working days exclude weekends and any dates identified as holidays.
* Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
* delivery times, or the number of days of work performed.
*
* Excel Function:
* WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $endDays The number of nonweekend and nonholiday days before or after
* startDate. A positive value for days yields a future date; a
* negative value yields a past date.
*
* @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
* depending on the value of the ReturnDateType flag
*/
public static function funcWorkDay($startDate, $endDays, ...$dateArgs)
{
// Retrieve the mandatory start date and days that are referenced in the function definition
try {
$startDate = Helpers::getDateValue($startDate);
$endDays = Helpers::validateNumericNull($endDays);
$dateArgs = Functions::flattenArray($dateArgs);
$holidayArray = [];
foreach ($dateArgs as $holidayDate) {
$holidayArray[] = Helpers::getDateValue($holidayDate);
}
} catch (Exception $e) {
return $e->getMessage();
}
$startDate = (float) floor($startDate);
$endDays = (int) floor($endDays);
// If endDays is 0, we always return startDate
if ($endDays == 0) {
return $startDate;
}
if ($endDays < 0) {
return self::decrementing($startDate, $endDays, $holidayArray);
}
return self::incrementing($startDate, $endDays, $holidayArray);
}
/**
* Use incrementing logic to determine Workday.
*
* @return mixed
*/
private static function incrementing(float $startDate, int $endDays, array $holidayArray)
{
// Adjust the start date if it falls over a weekend
$startDoW = WeekDay::funcWeekDay($startDate, 3);
if (WeekDay::funcWeekDay($startDate, 3) >= 5) {
$startDate += 7 - $startDoW;
--$endDays;
}
// Add endDays
$endDate = (float) $startDate + ((int) ($endDays / 5) * 7);
$endDays = $endDays % 5;
while ($endDays > 0) {
++$endDate;
// Adjust the calculated end date if it falls over a weekend
$endDow = WeekDay::funcWeekDay($endDate, 3);
if ($endDow >= 5) {
$endDate += 7 - $endDow;
}
--$endDays;
}
// Test any extra holiday parameters
if (!empty($holidayArray)) {
$endDate = self::incrementingArray($startDate, $endDate, $holidayArray);
}
return Helpers::returnIn3FormatsFloat($endDate);
}
private static function incrementingArray(float $startDate, float $endDate, array $holidayArray): float
{
$holidayCountedArray = $holidayDates = [];
foreach ($holidayArray as $holidayDate) {
if (WeekDay::funcWeekDay($holidayDate, 3) < 5) {
$holidayDates[] = $holidayDate;
}
}
sort($holidayDates, SORT_NUMERIC);
foreach ($holidayDates as $holidayDate) {
if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
if (!in_array($holidayDate, $holidayCountedArray)) {
++$endDate;
$holidayCountedArray[] = $holidayDate;
}
}
// Adjust the calculated end date if it falls over a weekend
$endDoW = WeekDay::funcWeekDay($endDate, 3);
if ($endDoW >= 5) {
$endDate += 7 - $endDoW;
}
}
return $endDate;
}
/**
* Use decrementing logic to determine Workday.
*
* @return mixed
*/
private static function decrementing(float $startDate, int $endDays, array $holidayArray)
{
// Adjust the start date if it falls over a weekend
$startDoW = WeekDay::funcWeekDay($startDate, 3);
if (WeekDay::funcWeekDay($startDate, 3) >= 5) {
$startDate += -$startDoW + 4;
++$endDays;
}
// Add endDays
$endDate = (float) $startDate + ((int) ($endDays / 5) * 7);
$endDays = $endDays % 5;
while ($endDays < 0) {
--$endDate;
// Adjust the calculated end date if it falls over a weekend
$endDow = WeekDay::funcWeekDay($endDate, 3);
if ($endDow >= 5) {
$endDate += 4 - $endDow;
}
++$endDays;
}
// Test any extra holiday parameters
if (!empty($holidayArray)) {
$endDate = self::decrementingArray($startDate, $endDate, $holidayArray);
}
return Helpers::returnIn3FormatsFloat($endDate);
}
private static function decrementingArray(float $startDate, float $endDate, array $holidayArray): float
{
$holidayCountedArray = $holidayDates = [];
foreach ($holidayArray as $holidayDate) {
if (WeekDay::funcWeekDay($holidayDate, 3) < 5) {
$holidayDates[] = $holidayDate;
}
}
rsort($holidayDates, SORT_NUMERIC);
foreach ($holidayDates as $holidayDate) {
if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
if (!in_array($holidayDate, $holidayCountedArray)) {
--$endDate;
$holidayCountedArray[] = $holidayDate;
}
}
// Adjust the calculated end date if it falls over a weekend
$endDoW = WeekDay::funcWeekDay($endDate, 3);
if ($endDoW >= 5) {
$endDate += -$endDoW + 4;
}
}
return $endDate;
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class Year
{
/**
* YEAR.
*
* Returns the year corresponding to a date.
* The year is returned as an integer in the range 1900-9999.
*
* Excel Function:
* YEAR(dateValue)
*
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
*
* @return int|string Year
*/
public static function funcYear($dateValue)
{
try {
$dateValue = Helpers::getDateValue($dateValue);
} catch (Exception $e) {
return $e->getMessage();
}
if ($dateValue < 1 && Date::getExcelCalendar() === DATE::CALENDAR_WINDOWS_1900) {
return 1900;
}
// Execute function
$PHPDateObject = Date::excelToDateTimeObject($dateValue);
return (int) $PHPDateObject->format('Y');
}
}

View File

@ -0,0 +1,120 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
class YearFrac
{
/**
* YEARFRAC.
*
* Calculates the fraction of the year represented by the number of whole days between two dates
* (the start_date and the end_date).
* Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
* obligations to assign to a specific term.
*
* Excel Function:
* YEARFRAC(startDate,endDate[,method])
* See https://lists.oasis-open.org/archives/office-formula/200806/msg00039.html
* for description of algorithm used in Excel
*
* @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
* PHP DateTime object, or a standard date string
* @param int $method Method used for the calculation
* 0 or omitted US (NASD) 30/360
* 1 Actual/actual
* 2 Actual/360
* 3 Actual/365
* 4 European 30/360
*
* @return float|string fraction of the year, or a string containing an error
*/
public static function funcYearFrac($startDate, $endDate, $method = 0)
{
try {
$method = (int) Helpers::validateNumericNull($method);
$sDate = Helpers::getDateValue($startDate);
$eDate = Helpers::getDateValue($endDate);
$sDate = self::excelBug($sDate, $startDate, $endDate, $method);
$eDate = self::excelBug($eDate, $endDate, $startDate, $method);
$startDate = min($sDate, $eDate);
$endDate = max($sDate, $eDate);
} catch (Exception $e) {
return $e->getMessage();
}
switch ($method) {
case 0:
return Days360::funcDays360($startDate, $endDate) / 360;
case 1:
return self::method1($startDate, $endDate);
case 2:
return DateDif::funcDateDif($startDate, $endDate) / 360;
case 3:
return DateDif::funcDateDif($startDate, $endDate) / 365;
case 4:
return Days360::funcDays360($startDate, $endDate, true) / 360;
}
return Functions::NAN();
}
/**
* Excel 1900 calendar treats date argument of null as 1900-01-00. Really.
*
* @param mixed $startDate
* @param mixed $endDate
*/
private static function excelBug(float $sDate, $startDate, $endDate, int $method): float
{
if (Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE && Date::getExcelCalendar() !== Date::CALENDAR_MAC_1904) {
if ($endDate === null && $startDate !== null) {
if (Month::funcMonth($sDate) == 12 && Day::funcDay($sDate) === 31 && $method === 0) {
$sDate += 2;
} else {
++$sDate;
}
}
}
return $sDate;
}
private static function method1(float $startDate, float $endDate): float
{
$days = DateDif::funcDateDif($startDate, $endDate);
$startYear = Year::funcYear($startDate);
$endYear = Year::funcYear($endDate);
$years = $endYear - $startYear + 1;
$startMonth = Month::funcMonth($startDate);
$startDay = Day::funcDay($startDate);
$endMonth = Month::funcMonth($endDate);
$endDay = Day::funcDay($endDate);
$startMonthDay = 100 * $startMonth + $startDay;
$endMonthDay = 100 * $endMonth + $endDay;
if ($years == 1) {
$tmpCalcAnnualBasis = 365 + (int) Helpers::isLeapYear($endYear);
} elseif ($years == 2 && $startMonthDay >= $endMonthDay) {
if (Helpers::isLeapYear($startYear)) {
$tmpCalcAnnualBasis = 365 + (int) ($startMonthDay <= 229);
} elseif (Helpers::isLeapYear($endYear)) {
$tmpCalcAnnualBasis = 365 + (int) ($endMonthDay >= 229);
} else {
$tmpCalcAnnualBasis = 365;
}
} else {
$tmpCalcAnnualBasis = 0;
for ($year = $startYear; $year <= $endYear; ++$year) {
$tmpCalcAnnualBasis += 365 + (int) Helpers::isLeapYear($year);
}
$tmpCalcAnnualBasis /= $years;
}
return $days / $tmpCalcAnnualBasis;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcException;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class AllSetupTeardown extends TestCase
{
protected $compatibilityMode;
protected $excelCalendar;
protected $returnDateType;
protected $spreadsheet;
protected $sheet;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
$this->excelCalendar = Date::getExcelCalendar();
$this->returnDateType = Functions::getReturnDateType();
$this->spreadsheet = new Spreadsheet();
$this->sheet = $this->spreadsheet->getActiveSheet();
}
protected function tearDown(): void
{
Date::setExcelCalendar($this->excelCalendar);
Functions::setCompatibilityMode($this->compatibilityMode);
Functions::setReturnDateType($this->returnDateType);
$this->spreadsheet->disconnectWorksheets();
$this->spreadsheet = null;
$this->sheet = null;
}
protected static function setMac1904(): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
}
protected static function setUnixReturn(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
}
protected static function setObjectReturn(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
}
protected static function setOpenOffice(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
}
/**
* @param mixed $expectedResult
*/
protected function mightHaveException($expectedResult): void
{
if ($expectedResult === 'exception') {
$this->expectException(CalcException::class);
}
}
}

View File

@ -2,32 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class DateDifTest extends TestCase
class DateDifTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerDATEDIF
*
* @param mixed $expectedResult
* @param $startDate
* @param $endDate
* @param $unit
*/
public function testDATEDIF($expectedResult, $startDate, $endDate, $unit): void
public function testDATEDIF($expectedResult, string $formula): void
{
$result = DateTime::DATEDIF($startDate, $endDate, $unit);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=DATEDIF($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerDATEDIF()

View File

@ -2,42 +2,22 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Datefunc;
class DateTest extends TestCase
class DateTest extends AllSetupTeardown
{
private $returnDateType;
private $excelCalendar;
protected function setUp(): void
{
$this->returnDateType = Functions::getReturnDateType();
$this->excelCalendar = Date::getExcelCalendar();
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
}
protected function tearDown(): void
{
Functions::setReturnDateType($this->returnDateType);
Date::setExcelCalendar($this->excelCalendar);
}
/**
* @dataProvider providerDATE
*
* @param mixed $expectedResult
* @param $year
* @param $month
* @param $day
*/
public function testDATE($expectedResult, $year, $month, $day): void
public function testDATE($expectedResult, string $formula): void
{
$result = DateTime::DATE($year, $month, $day);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=DATE($formula)");
self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerDATE()
@ -47,18 +27,17 @@ class DateTest extends TestCase
public function testDATEtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
self::setUnixReturn();
$result = DateTime::DATE(2012, 1, 31);
$result = Datefunc::funcDate(2012, 1, 31); // 32-bit safe
self::assertEquals(1327968000, $result);
self::assertEqualsWithDelta(1327968000, $result, 1E-8);
}
public function testDATEtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
self::setObjectReturn();
$result = DateTime::DATE(2012, 1, 31);
$result = Datefunc::funcDate(2012, 1, 31);
// Must return an object...
self::assertIsObject($result);
// ... of the correct type
@ -69,17 +48,12 @@ class DateTest extends TestCase
public function testDATEwith1904Calendar(): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
self::setMac1904();
$result = DateTime::DATE(1918, 11, 11);
$result = Datefunc::funcDate(1918, 11, 11);
self::assertEquals($result, 5428);
}
public function testDATEwith1904CalendarError(): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
$result = DateTime::DATE(1901, 1, 31);
$result = Datefunc::funcDate(1901, 1, 31);
self::assertEquals($result, '#NUM!');
}
}

View File

@ -4,50 +4,33 @@ namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\DateValue;
class DateValueTest extends TestCase
class DateValueTest extends AllSetupTeardown
{
private $returnDateType;
private $excelCalendar;
protected function setUp(): void
{
$this->returnDateType = Functions::getReturnDateType();
$this->excelCalendar = Date::getExcelCalendar();
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
}
protected function tearDown(): void
{
Functions::setReturnDateType($this->returnDateType);
Date::setExcelCalendar($this->excelCalendar);
}
/**
* @dataProvider providerDATEVALUE
*
* @param mixed $expectedResult
* @param $dateValue
*/
public function testDATEVALUE($expectedResult, $dateValue): void
public function testDATEVALUE($expectedResult, string $dateValue): void
{
$this->sheet->getCell('B1')->setValue('1954-07-20');
// Loop to avoid extraordinarily rare edge case where first calculation
// and second do not take place on same day.
$row = 0;
do {
++$row;
$dtStart = new DateTimeImmutable();
$startDay = $dtStart->format('d');
if (is_string($expectedResult)) {
$replYMD = str_replace('Y', date('Y'), $expectedResult);
if ($replYMD !== $expectedResult) {
$expectedResult = DateTime::DATEVALUE($replYMD);
$expectedResult = DateValue::funcDateValue($replYMD);
}
}
$result = DateTime::DATEVALUE($dateValue);
$this->sheet->getCell("A$row")->setValue("=DATEVALUE($dateValue)");
$result = $this->sheet->getCell("A$row")->getCalculatedValue();
$dtEnd = new DateTimeImmutable();
$endDay = $dtEnd->format('d');
} while ($startDay !== $endDay);
@ -61,18 +44,18 @@ class DateValueTest extends TestCase
public function testDATEVALUEtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
self::setUnixReturn();
$result = DateTime::DATEVALUE('2012-1-31');
$result = DateValue::funcDateValue('2012-1-31');
self::assertEquals(1327968000, $result);
self::assertEqualsWithDelta(1327968000, $result, 1E-8);
}
public function testDATEVALUEtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
self::setObjectReturn();
$result = DateTime::DATEVALUE('2012-1-31');
$result = DateValue::funcDateValue('2012-1-31');
// Must return an object...
self::assertIsObject($result);
// ... of the correct type
@ -83,10 +66,10 @@ class DateValueTest extends TestCase
public function testDATEVALUEwith1904Calendar(): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
self::assertEquals(5428, DateTime::DATEVALUE('1918-11-11'));
self::assertEquals(0, DateTime::DATEVALUE('1904-01-01'));
self::assertEquals('#VALUE!', DateTime::DATEVALUE('1903-12-31'));
self::assertEquals('#VALUE!', DateTime::DATEVALUE('1900-02-29'));
self::setMac1904();
self::assertEquals(5428, DateValue::funcDateValue('1918-11-11'));
self::assertEquals(0, DateValue::funcDateValue('1904-01-01'));
self::assertEquals('#VALUE!', DateValue::funcDateValue('1903-12-31'));
self::assertEquals('#VALUE!', DateValue::funcDateValue('1900-02-29'));
}
}

View File

@ -2,56 +2,43 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class DayTest extends TestCase
class DayTest extends AllSetupTeardown
{
private $compatibilityMode;
private $returnDateType;
private $excelCalendar;
protected function setUp(): void
{
$this->compatibilityMode = Functions::getCompatibilityMode();
$this->returnDateType = Functions::getReturnDateType();
$this->excelCalendar = Date::getExcelCalendar();
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
protected function tearDown(): void
{
Functions::setCompatibilityMode($this->compatibilityMode);
Functions::setReturnDateType($this->returnDateType);
Date::setExcelCalendar($this->excelCalendar);
}
/**
* @dataProvider providerDAY
*
* @param mixed $expectedResultExcel
* @param mixed $expectedResultOpenOffice
* @param $dateTimeValue
*/
public function testDAY($expectedResultExcel, $expectedResultOpenOffice, $dateTimeValue): void
public function testDAY($expectedResultExcel, string $dateTimeValue): void
{
$resultExcel = DateTime::DAYOFMONTH($dateTimeValue);
self::assertEqualsWithDelta($expectedResultExcel, $resultExcel, 1E-8);
Functions::setCompatibilityMode(Functions::COMPATIBILITY_OPENOFFICE);
$resultOpenOffice = DateTime::DAYOFMONTH($dateTimeValue);
self::assertEqualsWithDelta($expectedResultOpenOffice, $resultOpenOffice, 1E-8);
$this->mightHaveException($expectedResultExcel);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=DAY($dateTimeValue)");
self::assertSame($expectedResultExcel, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerDAY()
{
return require 'tests/data/Calculation/DateTime/DAY.php';
}
/**
* @dataProvider providerDAYOpenOffice
*
* @param mixed $expectedResultOpenOffice
*/
public function testDAYOpenOffice($expectedResultOpenOffice, string $dateTimeValue): void
{
self::setOpenOffice();
$this->mightHaveException($expectedResultOpenOffice);
$sheet = $this->sheet;
$sheet->getCell('A2')->setValue("=DAY($dateTimeValue)");
self::assertSame($expectedResultOpenOffice, $sheet->getCell('A2')->getCalculatedValue());
}
public function providerDAYOpenOffice()
{
return require 'tests/data/Calculation/DateTime/DAYOpenOffice.php';
}
}

View File

@ -2,32 +2,21 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class Days360Test extends TestCase
class Days360Test extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerDAYS360
*
* @param mixed $expectedResult
* @param $startDate
* @param $endDate
* @param $method
*/
public function testDAYS360($expectedResult, $startDate, $endDate, $method): void
public function testDAYS360($expectedResult, string $formula): void
{
$result = DateTime::DAYS360($startDate, $endDate, $method);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('2000-02-29');
$sheet->getCell('C1')->setValue('2000-03-31');
$sheet->getCell('A1')->setValue("=DAYS360($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerDAYS360()

View File

@ -2,35 +2,44 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use DateTime;
use DateTimeImmutable;
use Exception;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Days;
class DaysTest extends TestCase
class DaysTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerDAYS
*
* @param mixed $expectedResult
* @param $endDate
* @param $startDate
*/
public function testDAYS($expectedResult, $endDate, $startDate): void
public function testDAYS($expectedResult, string $formula): void
{
$result = DateTime::DAYS($endDate, $startDate);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('C1')->setValue('1954-11-30');
$sheet->getCell('A1')->setValue("=DAYS($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerDAYS()
{
return require 'tests/data/Calculation/DateTime/DAYS.php';
}
public function testObject(): void
{
$obj1 = new DateTime('2000-3-31');
$obj2 = new DateTimeImmutable('2000-2-29');
self::assertSame(31, Days::funcDays($obj1, $obj2));
}
public function testNonDateObject(): void
{
$obj1 = new Exception();
$obj2 = new DateTimeImmutable('2000-2-29');
self::assertSame('#VALUE!', Days::funcDays($obj1, $obj2));
}
}

View File

@ -2,31 +2,22 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\EDate;
class EDateTest extends TestCase
class EDateTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerEDATE
*
* @param mixed $expectedResult
* @param $dateValue
* @param $adjustmentMonths
*/
public function testEDATE($expectedResult, $dateValue, $adjustmentMonths): void
public function testEDATE($expectedResult, string $formula): void
{
$result = DateTime::EDATE($dateValue, $adjustmentMonths);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=EDATE($formula)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerEDATE()
@ -36,18 +27,18 @@ class EDateTest extends TestCase
public function testEDATEtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
self::setUnixReturn();
$result = DateTime::EDATE('2012-1-26', -1);
$result = EDate::funcEDate('2012-1-26', -1);
self::assertEquals(1324857600, $result);
self::assertEqualsWithDelta(1324857600, $result, 1E-8);
}
public function testEDATEtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
self::setObjectReturn();
$result = DateTime::EDATE('2012-1-26', -1);
$result = EDate::funcEDate('2012-1-26', -1);
// Must return an object...
self::assertIsObject($result);
// ... of the correct type

View File

@ -2,31 +2,22 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\EoMonth;
class EoMonthTest extends TestCase
class EoMonthTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerEOMONTH
*
* @param mixed $expectedResult
* @param $dateValue
* @param $adjustmentMonths
*/
public function testEOMONTH($expectedResult, $dateValue, $adjustmentMonths): void
public function testEOMONTH($expectedResult, string $formula): void
{
$result = DateTime::EOMONTH($dateValue, $adjustmentMonths);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=EOMONTH($formula)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertEquals($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerEOMONTH()
@ -36,23 +27,22 @@ class EoMonthTest extends TestCase
public function testEOMONTHtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
self::setUnixReturn();
$result = DateTime::EOMONTH('2012-1-26', -1);
$result = EoMonth::funcEomonth('2012-1-26', -1);
self::assertEquals(1325289600, $result);
self::assertEqualsWithDelta(1325289600, $result, 1E-8);
}
public function testEOMONTHtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
self::setObjectReturn();
$result = DateTime::EOMONTH('2012-1-26', -1);
$result = EoMonth::funcEomonth('2012-1-26', -1);
// Must return an object...
self::assertIsObject($result);
// ... of the correct type
self::assertTrue(is_a($result, 'DateTimeInterface'));
// ... with the correct value
self::assertEquals($result->format('d-M-Y'), '31-Dec-2011');
self::assertSame($result->format('d-M-Y'), '31-Dec-2011');
}
}

View File

@ -2,30 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class HourTest extends TestCase
class HourTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerHOUR
*
* @param mixed $expectedResult
* @param $dateTimeValue
*/
public function testHOUR($expectedResult, $dateTimeValue): void
public function testHOUR($expectedResult, string $dateTimeValue): void
{
$result = DateTime::HOUROFDAY($dateTimeValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=HOUR($dateTimeValue)");
$sheet->getCell('B1')->setValue('1954-11-23 2:23:46');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerHOUR()

View File

@ -2,34 +2,46 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class IsoWeekNumTest extends TestCase
class IsoWeekNumTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerISOWEEKNUM
*
* @param mixed $expectedResult
* @param mixed $dateValue
* @param string $dateValue
*/
public function testISOWEEKNUM($expectedResult, $dateValue): void
{
$result = DateTime::ISOWEEKNUM($dateValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerISOWEEKNUM()
{
return require 'tests/data/Calculation/DateTime/ISOWEEKNUM.php';
}
/**
* @dataProvider providerISOWEEKNUM1904
*
* @param mixed $expectedResult
* @param string $dateValue
*/
public function testISOWEEKNUM1904($expectedResult, $dateValue): void
{
$this->mightHaveException($expectedResult);
self::setMac1904();
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=ISOWEEKNUM($dateValue)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerISOWEEKNUM1904()
{
return require 'tests/data/Calculation/DateTime/ISOWEEKNUM1904.php';
}
}

View File

@ -2,30 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class MinuteTest extends TestCase
class MinuteTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerMINUTE
*
* @param mixed $expectedResult
* @param $dateTimeValue
*/
public function testMINUTE($expectedResult, $dateTimeValue): void
public function testMINUTE($expectedResult, string $dateTimeValue): void
{
$result = DateTime::MINUTE($dateTimeValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=MINUTE($dateTimeValue)");
$sheet->getCell('B1')->setValue('1954-11-23 2:23:46');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerMINUTE()

View File

@ -2,30 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class MonthTest extends TestCase
class MonthTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerMONTH
*
* @param mixed $expectedResult
* @param $dateTimeValue
*/
public function testMONTH($expectedResult, $dateTimeValue): void
public function testMONTH($expectedResult, string $dateTimeValue): void
{
$result = DateTime::MONTHOFYEAR($dateTimeValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=MONTH($dateTimeValue)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerMONTH()

View File

@ -0,0 +1,63 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PHPUnit\Framework\TestCase;
/**
* Sanity tests for functions which have been moved out of DateTime
* to their own classes. A deprecated version remains in DateTime;
* this class contains cursory tests to ensure that those work properly.
* If Scrutinizer fails the PR because of these deprecations, I will
* remove this class from the PR.
*
* @covers \PhpOffice\PhpSpreadsheet\Calculation\DateTime
*/
class MovedFunctionsTest extends TestCase
{
public function testMovedFunctions(): void
{
self::assertTrue(DateTime::isLeapYear(1904));
self::assertSame('#VALUE!', DateTime::getDateValue('XYZ'));
self::assertSame(61.0, DateTime::getDateValue('1900-03-01'));
self::assertSame(61.0, DateTime::DATE(1900, 3, 1));
self::assertSame(365, DateTime::DATEDIF('2016-01-01', '2016-12-31', 'YD'));
self::assertSame(61.0, DateTime::DATEVALUE('1900-03-01'));
self::assertSame(28, DateTime::DAYOFMONTH('1904-02-28'));
self::assertSame(364, DateTime::DAYS('2007-12-31', '2007-1-1'));
self::assertSame(9, DateTime::DAYS360('2007-1-1', '2007-1-10', false));
self::assertSame(39493.0, DateTime::EDATE('15-Jan-2008', 1));
self::assertSame(39507.0, DateTime::EOMONTH('15-Jan-2008', 1));
self::assertSame(18, DateTime::HOUROFDAY(0.75));
self::assertSame(52, DateTime::ISOWEEKNUM('2000-01-01'));
self::assertSame(24, DateTime::MINUTE(0.6));
self::assertSame(11, DateTime::MONTHOFYEAR('11-Nov-1918'));
self::assertSame(8, DateTime::NETWORKDAYS('1-Jan-2007', '10-Jan-2007'));
self::assertSame(35, DateTime::SECOND('11:15:35'));
self::assertSame(0.5, DateTime::TIME(12, 0, 0));
self::assertSame(0.40625, DateTime::TIMEVALUE('33:45'));
self::assertSame(5, DateTime::WEEKDAY('24-Oct-1968'));
self::assertSame(52, DateTime::WEEKNUM('21-Dec-2000'));
self::assertSame(39094.0, DateTime::WORKDAY('1-Jan-2007', 9));
self::assertSame(1904, DateTime::YEAR('1904-02-28'));
self::assertSame(0.025, DateTime::YEARFRAC('2007-01-10', '2007-01-01', 0));
}
public function testTodayAndNow(): void
{
// Loop to avoid rare edge case where first calculation
// and second do not take place in same second.
do {
$dtStart = new DateTimeImmutable();
$startSecond = $dtStart->format('s');
$nowResult = DateTime::DATETIMENOW();
$todayResult = DateTime::DATENOW();
$dtEnd = new DateTimeImmutable();
$endSecond = $dtEnd->format('s');
} while ($startSecond !== $endSecond);
self::assertSame(DateTime::DAYOFMONTH($nowResult), DateTime::DAYOFMONTH($todayResult));
}
}

View File

@ -2,29 +2,47 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class NetworkDaysTest extends TestCase
class NetworkDaysTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerNETWORKDAYS
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
*/
public function testNETWORKDAYS($expectedResult, ...$args): void
public function testNETWORKDAYS($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', ?array $arg3 = null): void
{
$result = DateTime::NETWORKDAYS(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('A2')->setValue($arg2);
}
$dateArray = [];
if (is_array($arg3)) {
if (array_key_exists(0, $arg3) && is_array($arg3[0])) {
$dateArray = $arg3[0];
} else {
$dateArray = $arg3;
}
}
$dateIndex = 0;
foreach ($dateArray as $date) {
++$dateIndex;
$sheet->getCell("C$dateIndex")->setValue($date);
}
$arrayArg = $dateIndex ? ", C1:C$dateIndex" : '';
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=NETWORKDAYS()');
} elseif ($arg2 === 'omitted') {
$sheet->getCell('B1')->setValue('=NETWORKDAYS(A1)');
} else {
$sheet->getCell('B1')->setValue("=NETWORKDAYS(A1, A2$arrayArg)");
}
self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue());
}
public function providerNETWORKDAYS()

View File

@ -3,15 +3,12 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use DateTimeImmutable;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class NowTest extends TestCase
class NowTest extends AllSetupTeardown
{
public function testNow(): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet = $this->sheet;
// Loop to avoid rare edge case where first calculation
// and second do not take place in same second.
do {
@ -21,7 +18,6 @@ class NowTest extends TestCase
$dtEnd = new DateTimeImmutable();
$endSecond = $dtEnd->format('s');
} while ($startSecond !== $endSecond);
//echo("\n"); var_dump($sheet->getCell('A1')->getCalculatedValue()); echo ("\n");
$sheet->setCellValue('B1', '=YEAR(A1)');
$sheet->setCellValue('C1', '=MONTH(A1)');
$sheet->setCellValue('D1', '=DAY(A1)');

View File

@ -2,30 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class SecondTest extends TestCase
class SecondTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerSECOND
*
* @param mixed $expectedResult
* @param $dateTimeValue
*/
public function testSECOND($expectedResult, $dateTimeValue): void
public function testSECOND($expectedResult, string $dateTimeValue): void
{
$result = DateTime::SECOND($dateTimeValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=SECOND($dateTimeValue)");
$sheet->getCell('B1')->setValue('1954-11-23 2:23:46');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerSECOND()

View File

@ -2,39 +2,24 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Time;
class TimeTest extends TestCase
class TimeTest extends AllSetupTeardown
{
private $returnDateType;
private $calendar;
protected function setUp(): void
{
$this->returnDateType = Functions::getReturnDateType();
$this->calendar = Date::getExcelCalendar();
}
protected function tearDown(): void
{
Functions::setReturnDateType($this->returnDateType);
Date::setExcelCalendar($this->calendar);
}
/**
* @dataProvider providerTIME
*
* @param mixed $expectedResult
*/
public function testTIME($expectedResult, ...$args): void
public function testTIME($expectedResult, string $formula): void
{
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
$result = DateTime::TIME(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('15');
$sheet->getCell('B2')->setValue('32');
$sheet->getCell('B3')->setValue('50');
$sheet->getCell('A1')->setValue("=TIME($formula)");
self::assertEqualsWithDelta($expectedResult, $sheet->getCell('A1')->getCalculatedValue(), 1E-8);
}
public function providerTIME()
@ -44,17 +29,17 @@ class TimeTest extends TestCase
public function testTIMEtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_NUMERIC);
self::setUnixReturn();
$result = DateTime::TIME(7, 30, 20);
$result = Time::funcTime(7, 30, 20);
self::assertEqualsWithDelta(27020, $result, 1E-8);
}
public function testTIMEtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_OBJECT);
self::setObjectReturn();
$result = DateTime::TIME(7, 30, 20);
$result = Time::funcTime(7, 30, 20);
// Must return an object...
self::assertIsObject($result);
// ... of the correct type
@ -65,17 +50,14 @@ class TimeTest extends TestCase
public function testTIME1904(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
$result = DateTime::TIME(0, 0, 0);
self::setMac1904();
$result = Time::funcTime(0, 0, 0);
self::assertEquals(0, $result);
}
public function testTIME1900(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
$result = DateTime::TIME(0, 0, 0);
$result = Time::funcTime(0, 0, 0);
self::assertEquals(0, $result);
}
}

View File

@ -2,20 +2,10 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\TimeValue;
class TimeValueTest extends TestCase
class TimeValueTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerTIMEVALUE
*
@ -24,7 +14,11 @@ class TimeValueTest extends TestCase
*/
public function testTIMEVALUE($expectedResult, $timeValue): void
{
$result = DateTime::TIMEVALUE($timeValue);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('03:45:52');
$sheet->getCell('A1')->setValue("=TIMEVALUE($timeValue)");
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
}
@ -35,18 +29,18 @@ class TimeValueTest extends TestCase
public function testTIMEVALUEtoUnixTimestamp(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_UNIX_TIMESTAMP);
self::setUnixReturn();
$result = DateTime::TIMEVALUE('7:30:20');
$result = TimeValue::funcTimeValue('7:30:20');
self::assertEquals(23420, $result);
self::assertEqualsWithDelta(23420, $result, 1E-8);
}
public function testTIMEVALUEtoDateTimeObject(): void
{
Functions::setReturnDateType(Functions::RETURNDATE_PHP_DATETIME_OBJECT);
self::setObjectReturn();
$result = DateTime::TIMEVALUE('7:30:20');
$result = TimeValue::funcTimeValue('7:30:20');
// Must return an object...
self::assertIsObject($result);
// ... of the correct type

View File

@ -0,0 +1,34 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use DateTimeImmutable;
class TodayTest extends AllSetupTeardown
{
public function testToday(): void
{
$sheet = $this->sheet;
// Loop to avoid rare edge case where first calculation
// and second do not take place in same second.
do {
$dtStart = new DateTimeImmutable();
$startSecond = $dtStart->format('s');
$sheet->setCellValue('A1', '=TODAY()');
$dtEnd = new DateTimeImmutable();
$endSecond = $dtEnd->format('s');
} while ($startSecond !== $endSecond);
$sheet->setCellValue('B1', '=YEAR(A1)');
$sheet->setCellValue('C1', '=MONTH(A1)');
$sheet->setCellValue('D1', '=DAY(A1)');
$sheet->setCellValue('E1', '=HOUR(A1)');
$sheet->setCellValue('F1', '=MINUTE(A1)');
$sheet->setCellValue('G1', '=SECOND(A1)');
self::assertSame((int) $dtStart->format('Y'), $sheet->getCell('B1')->getCalculatedValue());
self::assertSame((int) $dtStart->format('m'), $sheet->getCell('C1')->getCalculatedValue());
self::assertSame((int) $dtStart->format('d'), $sheet->getCell('D1')->getCalculatedValue());
self::assertSame(0, $sheet->getCell('E1')->getCalculatedValue());
self::assertSame(0, $sheet->getCell('F1')->getCalculatedValue());
self::assertSame(0, $sheet->getCell('G1')->getCalculatedValue());
}
}

View File

@ -2,33 +2,22 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel\Weekday;
class WeekDayTest extends TestCase
class WeekDayTest extends AllSetupTeardown
{
private $excelCalendar;
protected function setUp(): void
{
$this->excelCalendar = Date::getExcelCalendar();
}
protected function tearDown(): void
{
Date::setExcelCalendar($this->excelCalendar);
}
/**
* @dataProvider providerWEEKDAY
*
* @param mixed $expectedResult
*/
public function testWEEKDAY($expectedResult, ...$args): void
public function testWEEKDAY($expectedResult, string $formula): void
{
$result = DateTime::WEEKDAY(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=WEEKDAY($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerWEEKDAY()
@ -38,9 +27,9 @@ class WeekDayTest extends TestCase
public function testWEEKDAYwith1904Calendar(): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
self::assertEquals(7, DateTime::WEEKDAY('1904-01-02'));
self::assertEquals(6, DateTime::WEEKDAY('1904-01-01'));
self::assertEquals(6, DateTime::WEEKDAY(null));
self::setMac1904();
self::assertEquals(7, Weekday::funcWeekDay('1904-01-02'));
self::assertEquals(6, Weekday::funcWeekDay('1904-01-01'));
self::assertEquals(6, Weekday::funcWeekDay(null));
}
}

View File

@ -2,33 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class WeekNumTest extends TestCase
class WeekNumTest extends AllSetupTeardown
{
private $excelCalendar;
protected function setUp(): void
{
$this->excelCalendar = Date::getExcelCalendar();
}
protected function tearDown(): void
{
Date::setExcelCalendar($this->excelCalendar);
}
/**
* @dataProvider providerWEEKNUM
*
* @param mixed $expectedResult
*/
public function testWEEKNUM($expectedResult, ...$args): void
public function testWEEKNUM($expectedResult, string $formula): void
{
$result = DateTime::WEEKNUM(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=WEEKNUM($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerWEEKNUM()
@ -36,13 +23,23 @@ class WeekNumTest extends TestCase
return require 'tests/data/Calculation/DateTime/WEEKNUM.php';
}
public function testWEEKNUMwith1904Calendar(): void
/**
* @dataProvider providerWEEKNUM1904
*
* @param mixed $expectedResult
*/
public function testWEEKNUM1904($expectedResult, string $formula): void
{
Date::setExcelCalendar(Date::CALENDAR_MAC_1904);
self::assertEquals(27, DateTime::WEEKNUM('2004-07-02'));
self::assertEquals(1, DateTime::WEEKNUM('1904-01-02'));
self::assertEquals(1, DateTime::WEEKNUM(null));
// The following is a bug in Excel.
self::assertEquals(0, DateTime::WEEKNUM('1904-01-01'));
$this->mightHaveException($expectedResult);
self::setMac1904();
$sheet = $this->sheet;
$sheet->getCell('B1')->setValue('1954-11-23');
$sheet->getCell('A1')->setValue("=WEEKNUM($formula)");
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerWEEKNUM1904()
{
return require 'tests/data/Calculation/DateTime/WEEKNUM1904.php';
}
}

View File

@ -2,29 +2,47 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class WorkDayTest extends TestCase
class WorkDayTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerWORKDAY
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
*/
public function testWORKDAY($expectedResult, ...$args): void
public function testWORKDAY($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', ?array $arg3 = null): void
{
$result = DateTime::WORKDAY(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('A2')->setValue($arg2);
}
$dateArray = [];
if (is_array($arg3)) {
if (array_key_exists(0, $arg3) && is_array($arg3[0])) {
$dateArray = $arg3[0];
} else {
$dateArray = $arg3;
}
}
$dateIndex = 0;
foreach ($dateArray as $date) {
++$dateIndex;
$sheet->getCell("C$dateIndex")->setValue($date);
}
$arrayArg = $dateIndex ? ", C1:C$dateIndex" : '';
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=WORKDAY()');
} elseif ($arg2 === 'omitted') {
$sheet->getCell('B1')->setValue('=WORKDAY(A1)');
} else {
$sheet->getCell('B1')->setValue("=WORKDAY(A1, A2$arrayArg)");
}
self::assertEquals($expectedResult, $sheet->getCell('B1')->getCalculatedValue());
}
public function providerWORKDAY()

View File

@ -2,29 +2,39 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class YearFracTest extends TestCase
class YearFracTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerYEARFRAC
*
* @param mixed $expectedResult
* @param mixed $arg1
* @param mixed $arg2
* @param mixed $arg3
*/
public function testYEARFRAC($expectedResult, ...$args): void
public function testYEARFRAC($expectedResult, $arg1 = 'omitted', $arg2 = 'omitted', $arg3 = 'omitted'): void
{
$result = DateTime::YEARFRAC(...$args);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
if ($arg1 !== null) {
$sheet->getCell('A1')->setValue($arg1);
}
if ($arg2 !== null) {
$sheet->getCell('A2')->setValue($arg2);
}
if ($arg3 !== null) {
$sheet->getCell('A3')->setValue($arg3);
}
if ($arg1 === 'omitted') {
$sheet->getCell('B1')->setValue('=YEARFRAC()');
} elseif ($arg2 === 'omitted') {
$sheet->getCell('B1')->setValue('=YEARFRAC(A1)');
} elseif ($arg3 === 'omitted') {
$sheet->getCell('B1')->setValue('=YEARFRAC(A1, A2)');
} else {
$sheet->getCell('B1')->setValue('=YEARFRAC(A1, A2, A3)');
}
self::assertEqualswithDelta($expectedResult, $sheet->getCell('B1')->getCalculatedValue(), 1E-6);
}
public function providerYEARFRAC()

View File

@ -2,30 +2,20 @@
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\DateTime;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Shared\Date;
use PHPUnit\Framework\TestCase;
class YearTest extends TestCase
class YearTest extends AllSetupTeardown
{
protected function setUp(): void
{
Functions::setCompatibilityMode(Functions::COMPATIBILITY_EXCEL);
Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
Date::setExcelCalendar(Date::CALENDAR_WINDOWS_1900);
}
/**
* @dataProvider providerYEAR
*
* @param mixed $expectedResult
* @param $dateTimeValue
*/
public function testYEAR($expectedResult, $dateTimeValue): void
public function testYEAR($expectedResult, string $dateTimeValue): void
{
$result = DateTime::YEAR($dateTimeValue);
self::assertEqualsWithDelta($expectedResult, $result, 1E-8);
$this->mightHaveException($expectedResult);
$sheet = $this->sheet;
$sheet->getCell('A1')->setValue("=YEAR($dateTimeValue)");
$sheet->getCell('B1')->setValue('1954-11-23');
self::assertSame($expectedResult, $sheet->getCell('A1')->getCalculatedValue());
}
public function providerYEAR()

View File

@ -1,319 +1,84 @@
<?php
return [
'Year without century specified' => [
6890, // '11th November 1918'
18, 11, 11,
],
'Excel 1900 Calendar Base Date' => [
1,
1900, 1, 1,
],
'Day before Excel mythical 1900 leap day' => [
59,
1900, 2, 28,
],
'Excel mythical 1900 leap day' => [
60,
1900, 2, 29,
],
'Day after Excel mythical 1900 leap day' => [
61,
1900, 3, 1,
],
'Day after Excel actual 1904 leap day' => [
713,
1901, 12, 13,
],
'signed 32-bit Unix Timestamp Earliest Date' => [
714,
1901, 12, 14,
],
'Day before Excel 1904 Calendar Base Date' => [
1461,
1903, 12, 31,
],
'Excel 1904 Calendar Base Date' => [
1462,
1904, 1, 1,
],
'Day after Excel 1904 Calendar Base Date' => [
1463,
1904, 1, 2,
],
[
22269,
1960, 12, 19,
],
'Unix Timestamp Base Date' => [
25569,
1970, 1, 1,
],
[
30292,
1982, 12, 7,
],
[
39611,
2008, 6, 12,
],
'32-bit signed Unix Timestamp Latest Date' => [
50424,
2038, 1, 19,
],
'Day after 32-bit signed Unix Timestamp Latest Date' => [
50425,
2038, 1, 20,
],
[
39448,
2008, 1, 1,
],
[
39447,
2008, 1, null,
],
[
39446,
2008, 1, -1,
],
[
39417,
2008, 1, -30,
],
[
39416,
2008, 1, -31,
],
[
39082,
2008, 1, -365,
],
[
39508,
2008, 3, 1,
],
[
39507,
2008, 3, null,
],
[
39506,
2008, 3, -1,
],
[
39142,
2008, 3, -365,
],
[
39417,
2008, null, 1,
],
[
39387,
2008, -1, 1,
],
[
39083,
2008, -11, 1,
],
[
39052,
2008, -12, 1,
],
[
39022,
2008, -13, 1,
],
[
39051,
2008, -13, 30,
],
[
39021,
2008, -13, null,
],
[
38991,
2008, -13, -30,
],
[
38990,
2008, -13, -31,
],
[
39814,
2008, 13, 1,
],
[
39507,
2007, 15, null,
],
[
40210,
2008, 26, 1,
],
[
40199,
2008, 26, -10,
],
[
38686,
2008, -26, 61,
],
[
39641,
2010, -15, -50,
],
[
39741,
2010, -15, 50,
],
[
40552,
2010, 15, -50,
],
[
40652,
2010, 15, 50,
],
[
40179,
2010, 1.5, 1,
],
[
40178,
2010, 1.5, 0,
],
[
40148,
2010, 0, 1.5,
],
[
40179,
2010, 1, 1.5,
],
[
41075,
2012, 6, 15,
],
[
41060,
2012, 6, null,
],
[
40892,
2012, null, 15,
],
[
167,
null, 6, 15,
],
[
3819,
10, 6, 15,
],
[
3622,
10, null, null,
],
[
274,
null, 10, null,
],
[
'#NUM!',
null, null, 10,
],
[
'#NUM!',
-20, null, null,
],
[
'#NUM!',
-20, 6, 15,
],
'Excel Maximum Date' => [
2958465,
9999, 12, 31,
],
'Exceeded Excel Maximum Date' => [
'#NUM!',
10000, 1, 1,
],
[
39670,
2008, 8, 10,
],
[
39813,
2008, 12, 31,
],
[
39692,
2008, 8, 32,
],
[
39844,
2008, 13, 31,
],
[
39813,
2009, 1, 0,
],
[
39812,
2009, 1, -1,
],
[
39782,
2009, 0, 0,
],
[
39781,
2009, 0, -1,
],
[
39752,
2009, -1, 0,
],
[
39751,
2009, -1, -1,
],
[
40146,
2010, 0, -1,
],
[
40329,
2010, 5, 31,
],
[6890, '18, 11, 11'], // year without centure
[1, '1900, 1, 1'], // Excel 1900 Calendar BaseDate
[59, '1900, 2, 28'], // Day before Excel mythical 1900 leap day
[60, '1900, 2, 29'], // Excel mythical 1900 leap day
[61, '1900, 3, 1'], // Day after Excel mythical 1900 leap day
[713, '1901, 12, 13'], // Day after actual 1904 leap day
[714, '1901, 12, 14'], // signed 32-bit Unix Timestamp Earliest Date
[1461, '1903, 12, 31'], // Day before Excel 1904 Calendar Base Date
[1462, '1904, 1, 1'], // Excel 1904 Calendar Base Date
[1463, '1904, 1, 2'], // Day after Excel 1904 Calendar Base Date
[22269, '1960, 12, 19'],
[25569, '1970, 1, 1'], // Unix Timestamp Base Date
[30292, '1982, 12, 7'],
[39611, '2008, 6, 12'],
[50424, '2038, 1, 19'], // 32-bit signed Unix Timestamp Latest Date
[50425, '2038, 1, 20'], // Day after 32-bit signed Unix Timestamp Latest Date
[39448, '2008, 1, 1'],
[39447, '2008, 1, Q15'],
[39446, '2008, 1, -1'],
[39417, '2008, 1, -30'],
[39416, '2008, 1, -31'],
[39082, '2008, 1, -365'],
[39508, '2008, 3, 1'],
[39507, '2008, 3, Q15'],
[39506, '2008, 3, -1'],
[39142, '2008, 3, -365'],
[39417, '2008, Q15, 1'],
[39387, '2008, -1, 1'],
[39083, '2008, -11, 1'],
[39052, '2008, -12, 1'],
[39022, '2008, -13, 1'],
[39051, '2008, -13, 30'],
[39021, '2008, -13, Q15'],
[38991, '2008, -13, -30'],
[38990, '2008, -13, -31'],
[39814, '2008, 13, 1'],
[39507, '2007, 15, Q15'],
[40210, '2008, 26, 1'],
[40199, '2008, 26, -10'],
[38686, '2008, -26, 61'],
[39641, '2010, -15, -50'],
[39741, '2010, -15, 50'],
[40552, '2010, 15, -50'],
[40652, '2010, 15, 50'],
[40179, '2010, 1.5, 1'],
[40178, '2010, 1.5, 0'],
[40148, '2010, 0, 1.5'],
[40179, '2010, 1, 1.5'],
[41075, '2012, 6, 15'],
[41060, '2012, 6, Q15'],
[40892, '2012, Q15, 15'],
[167, 'Q15, 6, 15'],
[3819, '10, 6, 15'],
[3622, '10, Q15, Q16'],
[274, 'Q14, 10, Q15'],
['#NUM!', 'Q14, Q15, 10'],
['#NUM!', '-20, Q14, Q15'],
['#NUM!', '-20, 6, 15'],
[2958465, '9999, 12, 31'], // Excel maximum date
['#NUM!', '10000, 1, 1'], // Exceeded Excel maximum date
[39670, '2008, 8, 10'],
[39813, '2008, 12, 31'],
[39692, '2008, 8, 32'],
[39844, '2008, 13, 31'],
[39813, '2009, 1, 0'],
[39812, '2009, 1, -1'],
[39782, '2009, 0, 0'],
[39781, '2009, 0, -1'],
[39752, '2009, -1, 0'],
[39751, '2009, -1, -1'],
[40146, '2010, 0, -1'],
[40329, '2010, 5, 31'],
[40199, '2010, 1, "21st"'], // Excel can't parse ordinal, PhpSpreadsheet can
[40258, '2010, "March", "21st"'], // ordinal and month name
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40199,
2010, 1, '21st',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40258,
2010, 'March', '21st',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40258,
2010, 'March', 21,
],
[
'#VALUE!',
'ABC', 1, 21,
],
[
'#VALUE!',
2010, 'DEF', 21,
],
[
'#VALUE!',
2010, 3, 'GHI',
],
[40258, '2010, "March", 21'], // Excel can't parse month name, PhpSpreadsheet can
['#VALUE!', '"ABC", 1, 21'],
['#VALUE!', '2010, "DEF", 21'],
['#VALUE!', '2010, 3, "GHI"'],
['exception', '2010, 3'],
];

View File

@ -1,424 +1,112 @@
<?php
return [
[
365,
'2016-01-01', '2016-12-31', 'YD',
],
[
364,
'2015-01-01', '2015-12-31', 'YD',
],
[
364,
'2015-01-01', '2016-12-31', 'YD',
],
[
365,
'2016-01-01', '2017-12-31', 'YD',
],
[
364,
'2017-01-01', '2018-12-31', 'YD',
],
[
'#VALUE!',
'ABC', '2007-1-10', 'Y',
],
[
'#VALUE!',
'2007-1-1', 'DEF', 'Y',
],
[
'#VALUE!',
'2007-1-1', '2007-1-10', 'XYZ',
],
[
'#NUM!',
'2007-1-10', '2007-1-1', 'Y',
],
[
0,
'2007-12-31', '2008-1-10', 'Y',
],
[
0,
'2007-1-1', '2007-1-10', 'Y',
],
[
0,
'2007-1-1', '2007-1-10', 'M',
],
[
9,
'2007-1-1', '2007-1-10', 'D',
],
[
0,
'2007-1-1', '2007-1-10', 'YM',
],
[
9,
'2007-1-1', '2007-1-10', 'YD',
],
[
9,
'2007-1-1', '2007-1-10', 'MD',
],
[
0,
'2007-1-1', '2007-12-31', 'Y',
],
[
11,
'2007-1-1', '2007-12-31', 'M',
],
[
364,
'2007-1-1', '2007-12-31', 'D',
],
[
11,
'2007-1-1', '2007-12-31', 'YM',
],
[
364,
'2007-1-1', '2007-12-31', 'YD',
],
[
30,
'2007-1-1', '2007-12-31', 'MD',
],
[
1,
'2007-1-1', '2008-7-1', 'Y',
],
[
18,
'2007-1-1', '2008-7-1', 'M',
],
[
547,
'2007-1-1', '2008-7-1', 'D',
],
[
6,
'2007-1-1', '2008-7-1', 'YM',
],
[
181,
'2007-1-1', '2008-7-1', 'YD',
],
[
0,
'2007-1-1', '2008-7-1', 'MD',
],
[
0,
'2007-1-1', '2007-1-31', 'Y',
],
[
0,
'2007-1-1', '2007-1-31', 'M',
],
[
30,
'2007-1-1', '2007-1-31', 'D',
],
[
0,
'2007-1-1', '2007-1-31', 'YM',
],
[
30,
'2007-1-1', '2007-1-31', 'YD',
],
[
30,
'2007-1-1', '2007-1-31', 'MD',
],
[
0,
'2007-1-1', '2007-2-1', 'Y',
],
[
1,
'2007-1-1', '2007-2-1', 'M',
],
[
31,
'2007-1-1', '2007-2-1', 'D',
],
[
1,
'2007-1-1', '2007-2-1', 'YM',
],
[
31,
'2007-1-1', '2007-2-1', 'YD',
],
[
0,
'2007-1-1', '2007-2-1', 'MD',
],
[
0,
'2007-1-1', '2007-2-28', 'Y',
],
[
1,
'2007-1-1', '2007-2-28', 'M',
],
[
58,
'2007-1-1', '2007-2-28', 'D',
],
[
1,
'2007-1-1', '2007-2-28', 'YM',
],
[
58,
'2007-1-1', '2007-2-28', 'YD',
],
[
27,
'2007-1-1', '2007-2-28', 'MD',
],
[
0,
'2007-1-31', '2007-2-1', 'Y',
],
[
0,
'2007-1-31', '2007-2-1', 'M',
],
[
1,
'2007-1-31', '2007-2-1', 'D',
],
[
0,
'2007-1-31', '2007-2-1', 'YM',
],
[
1,
'2007-1-31', '2007-2-1', 'YD',
],
[
1,
'2007-1-31', '2007-2-1', 'MD',
],
[
0,
'2007-1-31', '2007-3-1', 'Y',
],
[
1,
'2007-1-31', '2007-3-1', 'M',
],
[
29,
'2007-1-31', '2007-3-1', 'D',
],
[
1,
'2007-1-31', '2007-3-1', 'YM',
],
[
29,
'2007-1-31', '2007-3-1', 'YD',
],
[
-2,
'2007-1-31', '2007-3-1', 'MD',
],
[
0,
'2007-1-31', '2007-3-31', 'Y',
],
[
2,
'2007-1-31', '2007-3-31', 'M',
],
[
59,
'2007-1-31', '2007-3-31', 'D',
],
[
2,
'2007-1-31', '2007-3-31', 'YM',
],
[
59,
'2007-1-31', '2007-3-31', 'YD',
],
[
0,
'2007-1-31', '2007-3-31', 'MD',
],
[
0,
'2008-1-1', '2008-9-1', 'Y',
],
[
8,
'2008-1-1', '2008-9-1', 'M',
],
[
244,
'2008-1-1', '2008-9-1', 'D',
],
[
8,
'2008-1-1', '2008-9-1', 'YM',
],
[
244,
'2008-1-1', '2008-9-1', 'YD',
],
[
0,
'2008-1-1', '2008-9-1', 'MD',
],
[
1,
'2007-2-1', '2008-4-1', 'Y',
],
[
14,
'2007-2-1', '2008-4-1', 'M',
],
[
425,
'2007-2-1', '2008-4-1', 'D',
],
[
2,
'2007-2-1', '2008-4-1', 'YM',
],
[
59,
'2007-2-1', '2008-4-1', 'YD',
],
[
0,
'2007-2-1', '2008-4-1', 'MD',
],
[
47,
'1960-12-19', '2008-6-28', 'Y',
],
[
570,
'1960-12-19', '2008-6-28', 'M',
],
[
17358,
'1960-12-19', '2008-6-28', 'D',
],
[
6,
'1960-12-19', '2008-6-28', 'YM',
],
[
191,
'1960-12-19', '2008-6-28', 'YD',
],
[
9,
'1960-12-19', '2008-6-28', 'MD',
],
[
25,
'1982-12-7', '2008-6-28', 'Y',
],
[
306,
'1982-12-7', '2008-6-28', 'M',
],
[
9335,
'1982-12-7', '2008-6-28', 'D',
],
[
6,
'1982-12-7', '2008-6-28', 'YM',
],
[
203,
'1982-12-7', '2008-6-28', 'YD',
],
[
21,
'1982-12-7', '2008-6-28', 'MD',
],
[
2,
'2007-12-25', '2010-3-17', 'Y',
],
[
26,
'2007-12-25', '2010-3-17', 'M',
],
[
813,
'2007-12-25', '2010-3-17', 'D',
],
[
2,
'2007-12-25', '2010-3-17', 'YM',
],
[
82,
'2007-12-25', '2010-3-17', 'YD',
],
[
20,
'2007-12-25', '2010-3-17', 'MD',
],
[
51,
'19-12-1960', '26-01-2012', 'Y',
],
[
613,
'19-12-1960', '26-01-2012', 'M',
],
[
18665,
'19-12-1960', '26-01-2012', 'D',
],
[
1,
'19-12-1960', '26-01-2012', 'YM',
],
[
11,
'19-12-1960', '26-11-1962', 'YM',
],
[
38,
'19-12-1960', '26-01-2012', 'YD',
],
[
7,
'19-12-1960', '26-01-2012', 'MD',
],
[
0,
'19-12-1960', '12-12-1961', 'Y',
],
[
1,
'19-12-1960', '12-12-1962', 'Y',
],
[
51,
'19-12-1960', '12-12-2012', 'Y',
],
[
0,
'1982-12-07', '1982-12-7', 'D',
],
[365, '"2016-01-01", "2016-12-31", "YD"'],
[364, '"2015-01-01", "2015-12-31", "YD"'],
[364, '"2015-01-01", "2016-12-31", "YD"'],
[365, '"2016-01-01", "2017-12-31", "YD"'],
[364, '"2017-01-01", "2018-12-31", "YD"'],
['#VALUE!', '"ABC", "2007-1-10", "Y"'],
['#VALUE!', '"2007-1-1", "DEF", "Y"'],
['#VALUE!', '"2007-1-1", "2007-1-10", "XYZ"'],
['#NUM!', '"2007-1-10", "2007-1-1", "Y"'],
[0, '"2007-12-31", "2008-1-10", "Y"'],
[0, '"2007-1-1", "2007-1-10", "Y"'],
[0, '"2007-1-1", "2007-1-10", "M"'],
[9, '"2007-1-1", "2007-1-10", "D"'],
[0, '"2007-1-1", "2007-1-10", "YM"'],
[9, '"2007-1-1", "2007-1-10", "YD"'],
[9, '"2007-1-1", "2007-1-10", "MD"'],
[0, '"2007-1-1", "2007-12-31", "Y"'],
[11, '"2007-1-1", "2007-12-31", "M"'],
[364, '"2007-1-1", "2007-12-31", "D"'],
[11, '"2007-1-1", "2007-12-31", "YM"'],
[364, '"2007-1-1", "2007-12-31", "YD"'],
[30, '"2007-1-1", "2007-12-31", "MD"'],
[1, '"2007-1-1", "2008-7-1", "Y"'],
[18, '"2007-1-1", "2008-7-1", "M"'],
[547, '"2007-1-1", "2008-7-1", "D"'],
[6, '"2007-1-1", "2008-7-1", "YM"'],
[181, '"2007-1-1", "2008-7-1", "YD"'],
[0, '"2007-1-1", "2008-7-1", "MD"'],
[0, '"2007-1-1", "2007-1-31", "Y"'],
[0, '"2007-1-1", "2007-1-31", "M"'],
[30, '"2007-1-1", "2007-1-31", "D"'],
[0, '"2007-1-1", "2007-1-31", "YM"'],
[30, '"2007-1-1", "2007-1-31", "YD"'],
[30, '"2007-1-1", "2007-1-31", "MD"'],
[0, '"2007-1-1", "2007-2-1", "Y"'],
[1, '"2007-1-1", "2007-2-1", "M"'],
[31, '"2007-1-1", "2007-2-1", "D"'],
[1, '"2007-1-1", "2007-2-1", "YM"'],
[31, '"2007-1-1", "2007-2-1", "YD"'],
[0, '"2007-1-1", "2007-2-1", "MD"'],
[0, '"2007-1-1", "2007-2-28", "Y"'],
[1, '"2007-1-1", "2007-2-28", "M"'],
[58, '"2007-1-1", "2007-2-28", "D"'],
[1, '"2007-1-1", "2007-2-28", "YM"'],
[58, '"2007-1-1", "2007-2-28", "YD"'],
[27, '"2007-1-1", "2007-2-28", "MD"'],
[0, '"2007-1-31", "2007-2-1", "Y"'],
[0, '"2007-1-31", "2007-2-1", "M"'],
[1, '"2007-1-31", "2007-2-1", "D"'],
[0, '"2007-1-31", "2007-2-1", "YM"'],
[1, '"2007-1-31", "2007-2-1", "YD"'],
[1, '"2007-1-31", "2007-2-1", "MD"'],
[0, '"2007-1-31", "2007-3-1", "Y"'],
[1, '"2007-1-31", "2007-3-1", "M"'],
[29, '"2007-1-31", "2007-3-1", "D"'],
[1, '"2007-1-31", "2007-3-1", "YM"'],
[29, '"2007-1-31", "2007-3-1", "YD"'],
[-2, '"2007-1-31", "2007-3-1", "MD"'],
[0, '"2007-1-31", "2007-3-31", "Y"'],
[2, '"2007-1-31", "2007-3-31", "M"'],
[59, '"2007-1-31", "2007-3-31", "D"'],
[2, '"2007-1-31", "2007-3-31", "YM"'],
[59, '"2007-1-31", "2007-3-31", "YD"'],
[0, '"2007-1-31", "2007-3-31", "MD"'],
[0, '"2008-1-1", "2008-9-1", "Y"'],
[8, '"2008-1-1", "2008-9-1", "M"'],
[244, '"2008-1-1", "2008-9-1", "D"'],
[8, '"2008-1-1", "2008-9-1", "YM"'],
[244, '"2008-1-1", "2008-9-1", "YD"'],
[0, '"2008-1-1", "2008-9-1", "MD"'],
[1, '"2007-2-1", "2008-4-1", "Y"'],
[14, '"2007-2-1", "2008-4-1", "M"'],
[425, '"2007-2-1", "2008-4-1", "D"'],
[2, '"2007-2-1", "2008-4-1", "YM"'],
[59, '"2007-2-1", "2008-4-1", "YD"'],
[0, '"2007-2-1", "2008-4-1", "MD"'],
[47, '"1960-12-19", "2008-6-28", "Y"'],
[570, '"1960-12-19", "2008-6-28", "M"'],
[17358, '"1960-12-19", "2008-6-28", "D"'],
[6, '"1960-12-19", "2008-6-28", "YM"'],
[191, '"1960-12-19", "2008-6-28", "YD"'],
[9, '"1960-12-19", "2008-6-28", "MD"'],
[25, '"1982-12-7", "2008-6-28", "Y"'],
[306, '"1982-12-7", "2008-6-28", "M"'],
[9335, '"1982-12-7", "2008-6-28", "D"'],
[6, '"1982-12-7", "2008-6-28", "YM"'],
[203, '"1982-12-7", "2008-6-28", "YD"'],
[21, '"1982-12-7", "2008-6-28", "MD"'],
[2, '"2007-12-25", "2010-3-17", "Y"'],
[26, '"2007-12-25", "2010-3-17", "M"'],
[813, '"2007-12-25", "2010-3-17", "D"'],
[2, '"2007-12-25", "2010-3-17", "YM"'],
[82, '"2007-12-25", "2010-3-17", "YD"'],
[20, '"2007-12-25", "2010-3-17", "MD"'],
[51, '"19-12-1960", "26-01-2012", "Y"'],
[613, '"19-12-1960", "26-01-2012", "M"'],
[18665, '"19-12-1960", "26-01-2012", "D"'],
[1, '"19-12-1960", "26-01-2012", "YM"'],
[11, '"19-12-1960", "26-11-1962", "YM"'],
[38, '"19-12-1960", "26-01-2012", "YD"'],
[7, '"19-12-1960", "26-01-2012", "MD"'],
[0, '"19-12-1960", "12-12-1961", "Y"'],
[1, '"19-12-1960", "12-12-1962", "Y"'],
[51, '"19-12-1960", "12-12-2012", "Y"'],
[0, '"1982-12-07", "1982-12-7", "D"'],
[244, '"2008-1-1", "2008-9-1"'], // default unit is D
['exception', '"2008-1-1"'],
['exception', ''],
];

View File

@ -1,316 +1,97 @@
<?php
// Date String, Result
// Note that Excel fails ordinal number forms but PhpSpreadsheet parses them
return [
[
'#VALUE!',
'25-Dec-1899',
],
[
'#VALUE!',
'31-Dec-1899',
],
[
1,
'1-Jan-1900',
],
[
59,
'1900/2/28',
],
[
'60',
'29-02-1900',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
'60',
'29th February 1900',
],
[
61,
'1900/3/1',
],
[
713,
'13-12-1901',
],
[
714,
'14-12-1901',
],
[
1461,
'1903/12/31',
],
[
1462,
'1-Jan-1904',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
1463,
'2nd-Jan-1904',
],
[
22269,
'19-12-1960',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
25569,
'1st January 1970',
],
[
30292,
'7-Dec-1982',
],
[
39448,
'1-1-2008',
],
[
50424,
'2038-01-19',
],
[
39601,
'2-6-2008',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
39807,
'December 25th 2008',
],
[
39448,
'1 Jan-2008',
],
['#VALUE!', '"25-Dec-1899"'],
['#VALUE!', '"31-Dec-1899"'],
[1, '"1-Jan-1900"'],
[59, '"1900/2/28"'],
['60', '"29-02-1900"'],
['60', '"29th February 1900"'], // ordinal
[61, '"1900/3/1"'],
[713, '"13-12-1901"'],
[714, '"14-12-1901"'],
[1461, '"1903/12/31"'],
[1462, '"1-Jan-1904"'],
[1463, '"2nd-Jan-1904"'], // ordinal
[22269, '"19-12-1960"'],
[25569, '"1st January 1970"'], // ordinal
[30292, '"7-Dec-1982"'],
[39448, '"1-1-2008"'],
[50424, '"2038-01-19"'],
[39601, '"2-6-2008"'],
[39807, '"December 25th 2008"'], // ordinal
[39448, '"1 Jan-2008"'],
// MS Excel success or failure dependent on country settings
[
39813,
'12-31-2008',
],
[39813, '"12-31-2008"'],
// PhpSpreadsheet tries to handle both US and UK formats, irrespective of country settings
[
39813,
'31-12-2008',
],
[39813, '"31-12-2008"'],
// MS Excel success or failure dependent on country settings
[
39682,
'8/22/2008',
],
[39682, '"8/22/2008"'],
// PhpSpreadsheet tries to handle both US and UK formats, irrespective of country settings
[
39682,
'22/8/2008',
],
[
39682,
'22/8/08',
],
[
39682,
'22-AUG-2008',
],
[
39501,
'2008/02/23',
],
[
39635,
'6-7-2008',
],
[39682, '"22/8/2008"'],
[39682, '"22/8/08"'],
[39682, '"22-AUG-2008"'],
[39501, '"2008/02/23"'],
[39635, '"6-7-2008"'],
// MS Excel success or failure dependent on country settings
[
39141,
'28-2-2007',
],
[39141, '"28-2-2007"'],
// PhpSpreadsheet tries to handle both US and UK formats, irrespective of country settings
[
39141,
'2-28-2007',
],
// Should fail because it's an invalid date, but PhpSpreadsheet currently adjusts to 1-3-2007 - FIX NEEDED
[
'#VALUE!',
'29-2-2007',
],
[
36161,
'1/1/1999',
],
[
19925,
'1954-07-20',
],
[
36029,
'22 August 98',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
39142,
'1st March 2007',
],
[
'#VALUE!',
'The 1st day of March 2007',
],
// Jan 1 of the current year
[
'Y-01-01',
'1 Jan',
],
// Dec 31 of the current year
[
'Y-12-31',
'31/12',
],
[39141, '"2-28-2007"'],
['#VALUE!', '"29-2-2007"'],
[36161, '"1/1/1999"'],
[19925, '"1954-07-20"'],
[36029, '"22 August 98"'],
[39142, '"1st March 2007"'], // ordinal
['#VALUE!', '"The 1st day of March 2007"'],
['Y-01-01', '"1 Jan"'], // Jan 1 of the current year
['Y-12-31', '"31/12"'], // Dec 31 of the current year
// Excel reads as 1st December 1931, not 31st December in current year.
// This result is locale-dependent in Excel, in a manner not
// supported by PhpSpreadsheet.
[
11658,
'12/31',
],
// July 5 of the current year
[
'Y-07-05',
'5-JUL',
],
// July 5 of the current year
[
'Y-07-05',
'5 July',
],
[
39783,
'12/2008',
],
[
11963,
'10/32',
],
[
'#VALUE!',
11,
],
[
'#VALUE!',
true,
],
[
'#VALUE!',
false,
],
[
'#VALUE!',
1,
],
[
'#VALUE!',
12345,
],
[
'#VALUE!',
12,
],
// implicit day of month is 1
[
40210,
'Feb-2010',
],
[
40221,
'12-Feb-2010',
],
[11658, '"12/31"'],
['Y-07-05', '"5-JUL"'], // July 5 of the current year
['Y-07-05', '"5 July"'], // July 5 of the current year
[39783, '"12/2008"'],
[11963, '"10/32"'],
['#VALUE!', '11'],
['#VALUE!', 'true'],
['#VALUE!', 'false'],
['#VALUE!', '1'],
['#VALUE!', '12345'],
['#VALUE!', '12'],
[40210, '"Feb-2010"'], // implicit day of month is 1
[40221, '"12-Feb-2010"'],
[40221, '"Feb-12-2010"'], // MS Excel #VALUE!
[40221, '"February-12-2010"'], // MS Excel #VALUE!
[40221, '"February 12 2010"'], // MS Excel #VALUE!
[40227, '"18 Feb 2010"'],
[40254, '"17th 3rd 2010"'], // MS Excel #VALUE!
[40227, '"Feb 18th 2010"'], // MS Excel #VALUE!
[40210, '"1st Feb 2010"'], // MS Excel #VALUE!
[40210, '"1st-Feb-2010"'], // Excel #VALUE!
['#VALUE!', '"1me Fev 2010"'],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40221,
'Feb-12-2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40221,
'February-12-2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40221,
'February 12 2010',
],
[
40227,
'18 Feb 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40254,
'17th 3rd 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40227,
'Feb 18th 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40210,
'1st Feb 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40210,
'1st-Feb-2010',
],
[
'#VALUE!',
'1me Fev 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40210,
'February 1st 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40211,
'2nd Feb 2010',
],
[
'#VALUE!',
'Second Feb 2010',
],
[
'#VALUE!',
'First August 2010',
],
// MS Excel will fail with a #VALUE return, but PhpSpreadsheet can parse this date
[
40391,
'1st August 2010',
],
[
0,
'15:30:25',
],
[
'#VALUE!',
'ABCDEFGHIJKMNOPQRSTUVWXYZ',
],
[
'#VALUE!',
'1999',
],
['#VALUE!', '32/32'],
['#VALUE!', '1910-'],
['#VALUE!', '10--'],
['#VALUE!', '--10'],
['#VALUE!', '--1910'],
[40210, '"February 1st 2010"'], // Excel #VALUE!
[40211, '"2nd Feb 2010"'], // Excel #VALUE!
['#VALUE!', '"Second Feb 2010"'],
['#VALUE!', '"First August 2010"'],
[40391, '"1st August 2010"'], // Excel #VALUE!
[0, '"15:30:25"'],
['#VALUE!', '"ABCDEFGHIJKMNOPQRSTUVWXYZ"'],
['#VALUE!', '1999'],
['#VALUE!', '"32/32"'],
['#VALUE!', '"1910-"'],
['#VALUE!', '"10--"'],
['#VALUE!', '"--10"'],
['#VALUE!', '"--1910"'],
//['#VALUE!', '-JUL-1910'], We can parse this, Excel can't
['#VALUE!', '2008-08-'],
[36751, '0-08-13'],
['#VALUE!', '"2008-08-"'],
[36751, '"0-08-13"'],
['#VALUE!', 'Q15'],
['#VALUE!', 'false'],
['#VALUE!', 'true'],
[19925, 'B1'],
];

View File

@ -1,71 +1,20 @@
<?php
// Date Value, Result
// Excel Result, Argument
return [
[
19, // Result for Excel
19, // Result for OpenOffice
22269,
],
[
1, // Result for Excel
1, // Result for OpenOffice
30348,
],
[
10, // Result for Excel
10, // Result for OpenOffice
30843,
],
[
11, // Result for Excel
11, // Result for OpenOffice
'11-Nov-1918',
],
[
28, // Result for Excel
28, // Result for OpenOffice
'28-Feb-1904',
],
[
'#VALUE!', // Result for Excel
'#VALUE!', // Result for OpenOffice
'Invalid',
],
[
'#NUM!', // Result for Excel
29, // Result for OpenOffice
-1,
],
[
1, // Result for Excel
31, // Result for OpenOffice
1,
],
[
0, // Result for Excel
30, // Result for OpenOffice
0.5,
],
[
0, // Result for Excel
30, // Result for OpenOffice
0,
],
[
0, // Result for Excel
0, // Result for OpenOffice
null,
],
[
1, // Result for Excel
1, // Result for OpenOffice
true,
],
[
0, // Result for Excel
0, // Result for OpenOffice
false,
],
[19, '22269'],
[1, '30348'],
[10, '30843'],
[11, '"11-Nov-1918"'],
[28, '"28-Feb-1904"'],
['#VALUE!', '"Invalid"'],
// The following will all differ between Excel and OpenOffice
['#NUM!', '-1'],
[1, '1'],
[0, '0.5'],
[0, '0'],
[0, 'Q15'],
[1, 'true'],
[0, 'false'],
];

View File

@ -0,0 +1,19 @@
<?php
// OpenOffice Result, Argument
return [
[19, '22269'],
[1, '30348'],
[10, '30843'],
[11, '"11-Nov-1918"'],
[28, '"28-Feb-1904"'],
['#VALUE!', '"Invalid"'],
[29, '-1'],
[31, '1'],
[30, '0.5'],
[30, '0'],
[30, 'Q15'],
[31, 'true'],
[30, 'false'],
];

View File

@ -1,80 +1,25 @@
<?php
return [
[
'#VALUE!',
'2007-1-10', 'ABC',
],
[
'#VALUE!',
'DEF', '2007-1-1',
],
[
9,
'2007-1-10', '2007-1-1',
],
[
364,
'2007-12-31', '2007-1-1',
],
[
547,
'2008-7-1', '2007-1-1',
],
[
30,
'2007-1-31', '2007-1-1',
],
[
31,
'2007-2-1', '2007-1-1',
],
[
58,
'2007-2-28', '2007-1-1',
],
[
1,
'2007-2-1', '2007-1-31',
],
[
29,
'2007-3-1', '2007-1-31',
],
[
59,
'2007-3-31', '2007-1-31',
],
[
244,
'2008-9-1', '2008-1-1',
],
[
425,
'2008-4-1', '2007-2-1',
],
[
17358,
'2008-6-28', '1960-12-19',
],
[
9335,
'2008-6-28', '1982-12-7',
],
[
32,
'2000-3-31', '2000-2-28',
],
[
31,
'2000-3-31', '2000-2-29',
],
[
31,
new \DateTime('2000-3-31'), new \DateTimeImmutable('2000-2-29'),
],
[
31,
36616, 36585,
],
['exception', ''],
['exception', '"2007-1-10"'],
['#VALUE!', '"2007-1-10", "ABC"'],
['#VALUE!', '"DEF", "2007-1-1"'],
[9, '"2007-1-10", "2007-1-1"'],
[364, '"2007-12-31", "2007-1-1"'],
[547, '"2008-7-1", "2007-1-1"'],
[30, '"2007-1-31", "2007-1-1"'],
[31, '"2007-2-1", "2007-1-1"'],
[58, '"2007-2-28", "2007-1-1"'],
[1, '"2007-2-1", "2007-1-31"'],
[29, '"2007-3-1", "2007-1-31"'],
[59, '"2007-3-31", "2007-1-31"'],
[244, '"2008-9-1", "2008-1-1"'],
[425, '"2008-4-1", "2007-2-1"'],
[17358, '"2008-6-28", "1960-12-19"'],
[9335, '"2008-6-28", "1982-12-7"'],
[32, '"2000-3-31", "2000-2-28"'],
[31, '"2000-3-31", "2000-2-29"'],
[31, '36616, 36585'],
[-7, 'B1,C1'],
];

View File

@ -1,140 +1,42 @@
<?php
return [
[
'#VALUE!',
'ABC', '2007-1-10', false,
],
[
'#VALUE!',
'2007-1-1', 'DEF', true,
],
[
'#VALUE!',
'2007-1-1', '2007-1-10', 'XYZ',
],
[
'#VALUE!',
'2007-1-10', '2007-1-1', 'Y',
],
[
9,
'2007-1-1', '2007-1-10', false,
],
[
9,
'2007-1-1', '2007-1-10', true,
],
[
360,
'2007-1-1', '2007-12-31', false,
],
[
359,
'2007-1-1', '2007-12-31', true,
],
[
540,
'2007-1-1', '2008-7-1', false,
],
[
540,
'2007-1-1', '2008-7-1', true,
],
[
30,
'2007-1-1', '2007-1-31', false,
],
[
29,
'2007-1-1', '2007-1-31', true,
],
[
30,
'2007-1-1', '2007-2-1', false,
],
[
30,
'2007-1-1', '2007-2-1', true,
],
[
57,
'2007-1-1', '2007-2-28', false,
],
[
57,
'2007-1-1', '2007-2-28', true,
],
[
1,
'2007-1-31', '2007-2-1', false,
],
[
1,
'2007-1-31', '2007-2-1', true,
],
[
31,
'2007-1-31', '2007-3-1', false,
],
[
31,
'2007-1-31', '2007-3-1', true,
],
[
60,
'2007-1-31', '2007-3-31', false,
],
[
60,
'2007-1-31', '2007-3-31', true,
],
[
240,
'2008-1-1', '2008-9-1', false,
],
[
240,
'2008-1-1', '2008-9-1', true,
],
[
420,
'2007-2-1', '2008-4-1', false,
],
[
420,
'2007-2-1', '2008-4-1', true,
],
[
17109,
'1960-12-19', '2008-6-28', false,
],
[
17109,
'1960-12-19', '2008-6-28', true,
],
[
9201,
'1982-12-7', '2008-6-28', false,
],
[
9201,
'1982-12-7', '2008-6-28', true,
],
[
33,
'2000-2-28', '2000-3-31', false,
],
[
32,
'2000-2-28', '2000-3-31', true,
],
[
30,
'2000-2-29', '2000-3-31', false,
],
[
31,
'2000-2-29', '2000-3-31', true,
],
['#VALUE!', '"ABC", "2007-1-10", false'],
['#VALUE!', '"2007-1-1", "DEF", true'],
['#VALUE!', '"2007-1-1", "2007-1-10", "XYZ"'],
['#VALUE!', '"2007-1-10", "2007-1-1", 1'],
[9, '"2007-1-1", "2007-1-10", false'],
[9, '"2007-1-1", "2007-1-10", true'],
[360, '"2007-1-1", "2007-12-31"'],
[360, '"2007-1-1", "2007-12-31", false'],
[359, '"2007-1-1", "2007-12-31", true'],
[540, '"2007-1-1", "2008-7-1", false'],
[540, '"2007-1-1", "2008-7-1", true'],
[30, '"2007-1-1", "2007-1-31", false'],
[29, '"2007-1-1", "2007-1-31", true'],
[30, '"2007-1-1", "2007-2-1", false'],
[30, '"2007-1-1", "2007-2-1", true'],
[57, '"2007-1-1", "2007-2-28", false'],
[57, '"2007-1-1", "2007-2-28", true'],
[1, '"2007-1-31", "2007-2-1", false'],
[1, '"2007-1-31", "2007-2-1", true'],
[31, '"2007-1-31", "2007-3-1", false'],
[31, '"2007-1-31", "2007-3-1", true'],
[60, '"2007-1-31", "2007-3-31", false'],
[60, '"2007-1-31", "2007-3-31", true'],
[240, '"2008-1-1", "2008-9-1", false'],
[240, '"2008-1-1", "2008-9-1", true'],
[420, '"2007-2-1", "2008-4-1", false'],
[420, '"2007-2-1", "2008-4-1", true'],
[17109, '"1960-12-19", "2008-6-28", false'],
[17109, '"1960-12-19", "2008-6-28", true'],
[9201, '"1982-12-7", "2008-6-28", false'],
[9201, '"1982-12-7", "2008-6-28", true'],
[33, '"2000-2-28", "2000-3-31", false'],
[32, '"2000-2-28", "2000-3-31", true'],
[30, '"2000-2-29", "2000-3-31", false'],
[31, '"2000-2-29", "2000-3-31", true'],
[30, '"2000-2-29", "2000-3-31"'],
[30, 'B1,C1'],
[31, 'B1,C1,true'],
];

View File

@ -1,64 +1,24 @@
<?php
return [
[
39493,
'15-Jan-2008', 1,
],
[
39431,
'15-Jan-2008', -1,
],
[
39522,
'15-Jan-2008', 2,
],
[
39202,
'31-Mar-2007', 1,
],
[
39141,
'31-Mar-2007', -1,
],
[
39507,
'31-Mar-2008', -1,
],
[
39416,
'31-Mar-2008', -4,
],
[
39141,
'29-Feb-2008', -12,
],
[
39248,
'15-Mar-2007', 3,
],
[
22269,
22269.0, 0,
],
[
22331,
22269.0, 2,
],
[
25618,
22269.0, 110,
],
[
18920,
22269.0, -110,
],
[
'#VALUE!',
'15-Mar-2007', 'ABC',
],
[
'#VALUE!',
'Invalid', 12,
],
[39493, '"15-Jan-2008", 1'],
[39431, '"15-Jan-2008", -1'],
[39522, '"15-Jan-2008", 2'],
[39202, '"31-Mar-2007", 1'],
[39141, '"31-Mar-2007", -1'],
[39507, '"31-Mar-2008", -1'],
[39416, '"31-Mar-2008", -4'],
[39141, '"29-Feb-2008", -12'],
[39248, '"15-Mar-2007", 3'],
[22269, '22269.0, 0'],
[22269, '22269.0, Q15'],
[22331, '22269.0, 2'],
[25618, '22269.0, "110"'],
[18920, '22269.0, -110'],
['#VALUE!', '"15-Mar-2007", "ABC"'],
['#VALUE!', '"Invalid", 12'],
['exception', ''],
['exception', '22269'],
['#VALUE!', 'true, 12'],
['#VALUE!', '"2020-01-01", false'],
];

View File

@ -1,72 +1,28 @@
<?php
return [
[
39507,
'15-Jan-2008', 1,
],
[
39447,
'15-Jan-2008', -1,
],
[
39538,
'15-Jan-2008', 2,
],
[
39202,
'31-Mar-2007', 1,
],
[
39141,
'31-Mar-2007', -1,
],
[
39507,
'31-Mar-2008', -1,
],
[
39416,
'31-Mar-2008', -4,
],
[
39141,
'29-Feb-2008', -12,
],
[
39263,
'15-Mar-2007', 3,
],
[
22281,
22269.0, 0,
],
[
22340,
22269.0, 2,
],
[
25627,
22269.0, 110,
],
[
18932,
22269.0, -110,
],
[
22371,
22269.0, 3,
],
[
22371,
22269.0, 3.75,
],
[
'#VALUE!',
'15-Mar-2007', 'ABC',
],
[
'#VALUE!',
'Invalid', 12,
],
['exception', ''],
['exception', '"15-Jan-2008"'],
[39507, '"15-Jan-2008", 1'],
[39447, '"15-Jan-2008", -1'],
[39538, '"15-Jan-2008", 2'],
[39202, '"31-Mar-2007", 1'],
[39141, '"31-Mar-2007", -1'],
[39507, '"31-Mar-2008", -1'],
[39416, '"31-Mar-2008", -4'],
[39141, '"29-Feb-2008", -12'],
[39263, '"15-Mar-2007", 3'],
[22281, '22269.0, 0'],
[22281, '22269.0, Q15'],
[22340, '"22269.0", 2'],
[25627, '22269.0, 110'],
[18932, '22269.0, -110'],
[22371, '22269.0, 3'],
[22371, '22269.0, 3.75'],
['#VALUE!', '"15-Mar-2007", false'],
['#VALUE!', '"15-Mar-2007", true'],
['#VALUE!', '"15-Mar-2007", "ABC"'],
['#VALUE!', '"Invalid", 12'],
['#VALUE!', 'true, 12'],
['#VALUE!', '"2020-01-01", false'],
];

View File

@ -1,52 +1,21 @@
<?php
return [
[
6,
0.25,
],
[
18,
0.75,
],
[
12,
0.5,
],
[
14,
0.59999999999999998,
],
[
11,
'11-Nov-1918 11:11',
],
[
23,
'11:59 PM',
],
[
23,
'23:59:59',
],
[
0,
3600,
],
[
'#NUM!',
-3600,
],
[
0,
7200,
],
[
0,
65535,
],
[
'#VALUE!',
'1 O\'Clock',
],
[6, '0.25'],
[18, '0.75'],
[12, '0.5'],
[14, '0.6'],
[11, '"11-Nov-1918 11:11"'],
[23, '"11:59 PM"'],
[23, '"23:59:59"'],
[0, '3600'],
['#NUM!', '-3600'],
[0, '7200'],
[0, '65535'],
['#VALUE!', '"1 O\'Clock"'],
[0, 'Q15'],
[0, 'false'],
[0, 'true'],
[2, 'B1'],
['exception', ''],
];

View File

@ -1,46 +1,35 @@
<?php
return [
[
51,
'21-Dec-2000',
],
[
52,
'2000-01-01',
],
[
1,
'2000-01-03',
],
[
52,
'1995-01-01',
],
[
1,
'1995-01-07',
],
[
2,
'1995-01-10',
],
[
1,
'2018-01-01',
],
[
'#VALUE!',
'1800-01-01',
],
['52', null],
['53', '1904-01-01'],
['52', '1900-01-01'],
['1', '1900-01-07'],
['1', '1900-01-08'],
['2', '1900-01-09'],
['9', '1900-03-04'],
['10', '1900-03-05'],
[51, '"21-Dec-2000"'],
[52, '"2000-01-01"'],
[1, '"2000-01-03"'],
[52, '"1995-01-01"'],
[1, '"1995-01-07"'],
[2, '"1995-01-10"'],
[1, '"2018-01-01"'],
['#VALUE!', '"1800-01-01"'],
[47, 'B1'],
[52, 'Q15'],
[52, 'false'],
[52, 'true'],
[52, '0'],
[52, '1'],
[1, '2'],
[1, '8'],
[2, '9'],
[53, '"1904-01-01"'],
[52, '"1900-01-01"'],
[1, '"1900-01-07"'],
[1, '"1900-01-08"'],
[2, '"1900-01-09"'],
[9, '"1900-03-04"'],
[10, '"1900-03-05"'],
['#NUM!', '-1'],
[39, '1000'],
[25, '"2001"'],
[25, '2002'],
[25, '2003'],
[26, '2004'],
['exception', ''],
];

View File

@ -0,0 +1,33 @@
<?php
return [
[51, '"21-Dec-2000"'],
[52, '"2000-01-01"'],
[1, '"2000-01-03"'],
[52, '"1995-01-01"'],
[1, '"1995-01-07"'],
[2, '"1995-01-10"'],
[1, '"2018-01-01"'],
['#VALUE!', '"1800-01-01"'],
[47, 'B1'],
[53, 'Q15'],
[53, 'false'],
[53, 'true'],
[53, '0'],
[53, '1'],
[53, '2'],
[1, '3'],
[2, '10'],
[53, '"1904-01-01"'],
['#VALUE!', '"1900-01-01"'],
['#VALUE!', '"1903-12-31"'],
['#VALUE!', '"1900-01-07"'],
['#NUM!', '-1'],
[39, '1000'],
[25, '"2001"'],
[25, '2002'],
[25, '2003'],
[25, '2004'],
[26, '2005'],
['exception', ''],
];

View File

@ -1,52 +1,21 @@
<?php
return [
[
48,
0.20000000000000001,
],
[
36,
0.40000000000000002,
],
[
24,
0.59999999999999998,
],
[
12,
0.80000000000000004,
],
[
15,
'11-Nov-1918 11:15',
],
[
59,
'11:59 PM',
],
[
59,
'23:59:59',
],
[
0,
3600,
],
[
'#NUM!',
-3600,
],
[
0,
12500,
],
[
0,
65535,
],
[
'#VALUE!',
'Half past 1 O\'Clock',
],
[48, '0.2'],
[36, '"0.4"'],
[24, '0.6'],
[12, '0.8'],
[15, '"11-Nov-1918 11:15"'],
[59, '"11:59 PM"'],
[59, '"23:59:59"'],
[0, '3600'],
['#NUM!', '-3600'],
[0, '12500'],
[0, '65535'],
['#VALUE!', '"Half past 1 O\'Clock"'],
[0, 'Q15'],
[0, 'false'],
[0, 'true'],
[23, 'B1'],
['exception', ''],
];

View File

@ -1,52 +1,24 @@
<?php
return [
[
1,
null,
],
[
1,
0,
],
[
12,
22269.0,
],
[
2,
30348.0,
],
[
6,
30843.0,
],
[
11,
'11-Nov-1918',
],
[
2,
'28-Feb-1904',
],
[
7,
'01 Jul 2003',
],
[
4,
38094,
],
[
12,
'Dec 2003',
],
[
'#NUM!',
-10,
],
[
'#VALUE!',
'ABCD',
],
[1, '0'],
[12, '22269.0'],
[2, '30348.0'],
[6, '30843.0'],
[11, '"11-Nov-1918"'],
[2, '"28-Feb-1904"'],
[7, '"01 Jul 2003"'],
[4, '"38094"'],
[12, '"Dec 2003"'],
['#NUM!', '-10'],
['#VALUE!', '"ABCD"'],
['exception', ''],
[1, 'false'],
[1, 'true'],
[1, 'Q15'],
[11, 'B1'],
[3, '61'],
[2, '60'], // because of fake leap day
[12, '366'], // because of fake leap day
[1, '367'],
];

View File

@ -35,14 +35,13 @@ return [
0,
'20-Jun-2008',
'20-Jun-2008',
'20-Jun-2008',
['20-Jun-2008'],
],
[
0,
'20-Jun-2008',
'20-Jun-2008',
'20-Jun-2008',
'20-Jun-2008',
['20-Jun-2008', '20-Jun-2008'],
],
[
8,
@ -63,17 +62,13 @@ return [
16,
'19-Dec-1960',
'10-Jan-1961',
'25-Dec-1960',
'26-Dec-1960',
'01-Jan-1961',
['25-Dec-1960', '26-Dec-1960', '01-Jan-1961'],
],
[
-16,
'10-Jan-1961',
'19-Dec-1960',
'25-Dec-1960',
'26-Dec-1960',
'01-Jan-1961',
['25-Dec-1960', '26-Dec-1960', '01-Jan-1961'],
],
[
65,
@ -114,8 +109,8 @@ return [
'#VALUE!',
'10-Jan-1961',
'19-Dec-1960',
'25-Dec-1960',
'ABQZ',
'01-Jan-1961',
['25-Dec-1960', 'ABQZ', '01-Jan-1961'],
],
['exception', '2000-01-01', 'omitted'],
['exception', 'omitted'],
];

View File

@ -1,52 +1,21 @@
<?php
return [
[
57,
0.2339930556,
],
[
13,
0.4202893519,
],
[
22,
0.60789351849999995,
],
[
11,
0.80221064809999998,
],
[
35,
'11-Nov-1918 11:15:35',
],
[
0,
'11:59 PM',
],
[
59,
'23:59:59',
],
[
0,
3600,
],
[
'#NUM!',
-3601,
],
[
0,
12500,
],
[
0,
65535,
],
[
'#VALUE!',
'Half past 1 O\'Clock',
],
[57, '0.2339930556'],
[13, '0.4202893519'],
[22, '0.60789351845'],
[11, '0.8022106481'],
[35, '"11-Nov-1918 11:15:35"'],
[0, '"11:59 PM"'],
[59, '"23:59:59"'],
[0, '3600'],
['#NUM!', '-3601'],
[0, '12500'],
[0, '65535'],
['#VALUE!', '"Half past 1 O\'Clock"'],
[0, 'Q15'],
[0, 'false'],
[0, 'true'],
[46, 'B1'],
['exception', ''],
];

View File

@ -1,92 +1,28 @@
<?php
return [
[
0.75776620370400005,
18, 11, 11,
],
[
0.26047453703700002,
6, 15, 5,
],
[
0.52094907407400004,
12, 30, 10,
],
[
0.78153935185199996,
18, 45, 25,
],
[
0.64780092592600003,
15, 32, 50,
],
[
0.50070601851899998,
12, null, 61,
],
[
0.45832175925899998,
11, null, -1,
],
[
0.41589120370400001,
10, null, -67,
],
[
0.58478009259300001,
13, 62, 5,
],
[
0.31964120370400001,
9, -80, 17,
],
[
0.22083333333300001,
8, -162, null,
],
[
'#NUM!',
2, -120, -1,
],
[
0.0,
2, -120, null,
],
[
1.1574074E-5,
2, -120, 1,
],
[
0.50071759259299997,
36, 1, 2,
],
[
'#NUM!',
-1, 2, 3,
],
[
0.001030092593,
-1, 61, 29,
],
[
0.0,
-1, 61, -60,
],
[
'#VALUE!',
'A', null, null,
],
[
0.49930555555599998,
11, 59, 0,
],
[
0.5,
12, 0, 0,
],
[
0.70011574074100003,
16, 48, 10,
],
[0.757766203704, '18, 11, 11'],
[0.260474537037, '6, 15, 5'],
[0.520949074074, '12, 30, 10'],
[0.781539351852, '18, 45, 25'],
[0.647800925926, '15, 32, 50'],
[0.647800925926, 'B1, B2, B3'],
[0.500706018519, '12, Q15, 61'],
[0.458321759259, '11, false, -1'],
[0.415891203704, '10, Q15, -67'],
[0.584780092593, '13, 62, 5'],
[0.319641203704, '9, -80, 17'],
[0.220833333333, '8, -162, Q15'],
['#NUM!', '2, -120, -1'],
[0.0, '2, -120, Q15'],
[1.1574074E-5, '2, -120, 1'],
[0.500717592593, '36, true, 2'],
['#NUM!', '-1, 2, 3'],
[0.001030092593, '-1, 61, 29'],
[0.0, '-1, 61, -60'],
['#VALUE!', '"A", Q15, Q15'],
[0.499305555556, '11, 59, 0'],
[0.5, '12, 0, 0'],
[0.700115740741, '16, 48, 10'],
['exception', '16, 48'],
];

View File

@ -1,56 +1,22 @@
<?php
return [
[
0,
'12:00:00 am',
],
[
0.00071759299999999999,
'12:01:02 am',
],
[
0.50208333299999997,
'12:03 pm',
],
[
0.50498842600000005,
'12:7:11 pm',
],
[
0.176145833,
'4:13:39',
],
[
0.76408564800000001,
'6:20:17 pm',
],
[
0.773229167,
'18:33:27',
],
[
0.14392361100000001,
'31/12/2007 03:27:15',
],
[
0.90619212999999998,
'9:44:55 pm',
],
[
'#VALUE!',
12,
],
[
0.54236111099999995,
'13:01',
],
[
0.40625,
'33:45',
],
[
'#VALUE!',
'13:01PM',
],
[0, '"12:00:00 am"'],
[0.000717593, '"12:01:02 am"'],
[0.502083333, '"12:03 pm"'],
[0.504988426, '"12:7:11 pm"'],
[0.176145833, '"4:13:39"'],
[0.764085648, '"6:20:17 pm"'],
[0.773229167, '"18:33:27"'],
[0.143923611, '"31/12/2007 03:27:15"'],
[0.906192133, '"9:44:55 pm"'],
['#VALUE!', '12'],
[0.5423611101, '"13:01"'],
[0.40625, '"33:45"'],
['#VALUE!', '"13:01PM"'],
['#VALUE!', 'Q15'],
['#VALUE!', 'false'],
['#VALUE!', 'true'],
[0.156851852, 'B1'],
['exception', ''],
];

View File

@ -1,120 +1,44 @@
<?php
return [
[
5,
'24-Oct-1968',
],
[
4,
'24-Oct-1968', 2,
],
[
3,
'24-Oct-1968', 3,
],
[
4,
'2000-06-14',
],
[
3,
'2000-06-14', 2,
],
[
2,
'2000-06-14', 3,
],
[
4,
'1996-07-24',
],
[
3,
'1996-07-24', 2,
],
[
2,
'1996-07-24', 3,
],
[
7,
'1996-07-27',
],
[
6,
'1996-07-27', 2,
],
[
5,
'1996-07-27', 3,
],
[
1,
'1977-7-31',
],
[
7,
'1977-7-31', 2,
],
[
6,
'1977-7-31', 3,
],
[
2,
'1977-8-1',
],
[
1,
'1977-8-1', 2,
],
[
0,
'1977-8-1', 3,
],
[
7,
'1900-2-5', 2,
],
[
4,
'1900-2-1',
],
[
6,
38093,
],
[
5,
38093, 2,
],
[
4,
38093, 3,
],
[
'#VALUE!',
'3/7/1977', 'A',
],
[
'#NUM!',
'3/7/1977', 0,
],
[
'#VALUE!',
'Invalid',
1,
],
[
'#NUM!',
-1,
],
[1, null],
[1, false],
[2, true],
[1, '1900-01-01'],
[7, '1900-01-01', 2],
[7, null, 2],
[7, '1900-02-05', 2],
[5, '"24-Oct-1968"'],
[5, '"24-Oct-1968", 1'],
[4, '"24-Oct-1968", 2'],
[3, '"24-Oct-1968", 3'],
['#NUM!', '"24-Oct-1968", 4'],
['#NUM!', '"24-Oct-1968", 0'],
['#NUM!', '"24-Oct-1968", -1'],
[4, '"2000-06-14"'],
[3, '"2000-06-14", 2'],
[2, '"2000-06-14", 3'],
[4, '"1996-07-24"'],
[3, '"1996-07-24", 2'],
[2, '"1996-07-24", 3'],
[7, '"1996-07-27"'],
[6, '"1996-07-27", 2'],
[5, '"1996-07-27", 3'],
[1, '"1977-7-31"'],
[7, '"1977-7-31", 2'],
[6, '"1977-7-31", 3'],
[2, '"1977-8-1"'],
[1, '"1977-8-1", 2'],
[0, '"1977-8-1", 3'],
[7, '"1900-2-5", 2'],
[4, '"1900-2-1"'],
[6, '38093'],
[6, '38093, 1'],
[5, '38093, 2'],
[4, '38093, 3'],
['#VALUE!', '"3/7/1977", "A"'],
['#NUM!', '"3/7/1977", 0'],
['#VALUE!', '"Invalid", 1'],
['#NUM!', '-1'],
[1, 'Q15'],
[1, 'false'],
[2, 'true'],
[1, '"1900-01-01"'],
[7, '"1900-01-01", 2'],
[7, 'Q15, 2'],
[3, 'B1'],
[7, '"1900-02-05", 2'],
];

View File

@ -1,203 +1,80 @@
<?php
return [
[
52,
'21-Dec-2000', 1,
],
[
1,
'2000-01-01', 1,
],
[
2,
'2000-01-02', 1,
],
[
1,
'2000-01-01', 2,
],
[
2,
'2000-01-03', 2,
],
[
1,
'1995-01-01', 1,
],
[
1,
'1995-01-07', 1,
],
[
2,
'1995-01-08', 1,
],
[
1,
'1995-01-01', 2,
],
[
2,
'1995-01-02', 2,
],
[
28,
'3/7/1977',
],
[
'#VALUE!',
'3/7/1977', 'A',
],
[
'#NUM!',
'3/7/1977', 0,
],
[
'#NUM!',
'3/7/1977', -1,
],
[
'#VALUE!',
'Invalid', 1,
],
[
'#NUM!',
-1,
],
[
53,
'2019-12-29', 1,
],
[
52,
'2019-12-29', 2,
],
[
'#NUM!',
'2019-12-29', 3,
],
[
'#NUM!',
'2019-12-29', 10,
],
[
52,
'2019-12-29', 11,
],
[
52,
'2019-12-29', 12,
],
[
53,
'2019-12-29', 13,
],
[
53,
'2019-12-29', 14,
],
[
53,
'2019-12-29', 15,
],
[
53,
'2019-12-29', 16,
],
[
53,
'2019-12-29', 17,
],
[
'#NUM!',
'2019-12-29', 18,
],
[
'#NUM!',
'2019-12-29', 20,
],
[
'#NUM!',
'2019-12-29', 22,
],
[
52,
'2019-12-29', 21,
],
[
53,
'2020-12-29', 21,
],
[
52,
'2021-12-29', 21,
],
[
52,
'2022-12-29', 21,
],
[
1,
'2020-01-01', 21,
],
[
53,
'2021-01-01', 21,
],
[
52,
'2022-01-01', 21,
],
[
52,
'2023-01-01', 21,
],
[
2,
'2020-01-08', 21,
],
[
1,
'2021-01-08', 21,
],
[
1,
'2022-01-08', 21,
],
[
1,
'2023-01-08', 21,
],
[
1,
'2025-12-29', 21,
],
['9', '1900-03-01'],
['2', '1900-01-07', 2],
['2', '1905-01-07', 2],
['1', '1900-01-01'],
['1', '1900-01-01', 2],
['2', '1900-01-02', 2],
['1', null, 11],
['1', null, 12],
['1', null, 13],
['1', null, 14],
['1', null, 15],
['1', null, 16],
['0', null, 17],
['1', '1905-01-01', 17],
['0', null],
['1', null, 2],
['1', '1906-01-01'],
['#VALUE!', true],
['#VALUE!', false, 21],
['52', null, 21],
['53', '1904-01-01', 21],
['52', '1900-01-01', 21],
['1', '1900-01-07', 21],
['1', '1900-01-08', 21],
['2', '1900-01-09', 21],
['9', '1900-03-04', 21],
['10', '1900-03-05', 21],
[52, '"21-Dec-2000", 1'],
[1, '"2000-01-01", 1'],
[2, '"2000-01-02", 1'],
[1, '"2000-01-01", 2'],
[2, '"2000-01-03", 2'],
[1, '"1995-01-01", 1'],
[1, '"1995-01-07", 1'],
[2, '"1995-01-08", 1'],
[1, '"1995-01-01", 2'],
[2, '"1995-01-02", 2'],
[28, '"3/7/1977"'],
['#VALUE!', '"3/7/1977", "A"'],
['#NUM!', '"3/7/1977", 0'],
['#NUM!', '"3/7/1977", -1'],
['#VALUE!', '"Invalid", 1'],
['#NUM!', '-1'],
[53, '"2019-12-29", 1'],
[52, '"2019-12-29", 2'],
['#NUM!', '"2019-12-29", 3'],
['#NUM!', '"2019-12-29", 10'],
[52, '"2019-12-29", 11'],
[52, '"2019-12-29", 12'],
[53, '"2019-12-29", 13'],
[53, '"2019-12-29", 14'],
[53, '"2019-12-29", 15'],
[53, '"2019-12-29", 16'],
[53, '"2019-12-29", 17'],
['#NUM!', '"2019-12-29", 18'],
['#NUM!', '"2019-12-29", 20'],
['#NUM!', '"2019-12-29", 22'],
[52, '"2019-12-29", 21'],
[53, '"2020-12-29", 21'],
[52, '"2021-12-29", 21'],
[52, '"2022-12-29", 21'],
[1, '"2020-01-01", 21'],
[53, '"2021-01-01", 21'],
[52, '"2022-01-01", 21'],
[52, '"2023-01-01", 21'],
[2, '"2020-01-08", 21'],
[1, '"2021-01-08", 21'],
[1, '"2022-01-08", 21'],
[1, '"2023-01-08", 21'],
[1, '"2025-12-29", 21'],
[9, '"1900-03-01"'],
[2, '"1900-01-07", 2'],
[2, '"1905-01-07", 2'],
[1, '"1900-01-01"'],
[1, '"1900-01-01", 2'],
[2, '"1900-01-02", 2'],
[1, ', 11'],
[1, '0, 11'],
[1, '0, 12'],
[1, '0, 13'],
[1, '0, 14'],
[1, '0, 15'],
[1, '0, 16'],
[0, '0, 17'],
[1, '"1905-01-01", 17'],
[0, '0'],
[0, ','],
[1, ', 2'],
[1, '0, 2'],
[1, '"1906-01-01"'],
['#VALUE!', 'true'],
['#VALUE!', 'false, 21'],
[52, ', 21'],
[53, '"1904-01-01", 21'],
[52, '"1900-01-01", 21'],
[1, '"1900-01-07", 21'],
[1, '"1900-01-08", 21'],
[2, '"1900-01-09", 21'],
[9, '"1900-03-04", 21'],
[10, '"1900-03-05", 21'],
['exception', ''],
[48, 'B1'],
[0, 'Q15'],
];

View File

@ -0,0 +1,92 @@
<?php
return [
[52, '"21-Dec-2000", 1'],
[1, '"2000-01-01", 1'],
[2, '"2000-01-02", 1'],
[1, '"2000-01-01", 2'],
[2, '"2000-01-03", 2'],
[1, '"1995-01-01", 1'],
[1, '"1995-01-07", 1'],
[2, '"1995-01-08", 1'],
[1, '"1995-01-01", 2'],
[2, '"1995-01-02", 2'],
[28, '"3/7/1977"'],
['#VALUE!', '"3/7/1977", "A"'],
['#NUM!', '"3/7/1977", 0'],
['#NUM!', '"3/7/1977", -1'],
['#VALUE!', '"Invalid", 1'],
['#NUM!', '-1'],
[53, '"2019-12-29", 1'],
[52, '"2019-12-29", 2'],
['#NUM!', '"2019-12-29", 3'],
['#NUM!', '"2019-12-29", 10'],
[52, '"2019-12-29", 11'],
[52, '"2019-12-29", 12'],
[53, '"2019-12-29", 13'],
[53, '"2019-12-29", 14'],
[53, '"2019-12-29", 15'],
[53, '"2019-12-29", 16'],
[53, '"2019-12-29", 17'],
['#NUM!', '"2019-12-29", 18'],
['#NUM!', '"2019-12-29", 20'],
['#NUM!', '"2019-12-29", 22'],
[52, '"2019-12-29", 21'],
[53, '"2020-12-29", 21'],
[52, '"2021-12-29", 21'],
[52, '"2022-12-29", 21'],
[1, '"2020-01-01", 21'],
[53, '"2021-01-01", 21'],
[52, '"2022-01-01", 21'],
[52, '"2023-01-01", 21'],
[2, '"2020-01-08", 21'],
[1, '"2021-01-08", 21'],
[1, '"2022-01-08", 21'],
[1, '"2023-01-08", 21'],
[1, '"2025-12-29", 21'],
['#VALUE!', '"1900-03-01"'],
['#VALUE!', '"1900-01-07", 2'],
[2, '"1905-01-07", 2'],
['#VALUE!', '"1900-01-01"'],
['#VALUE!', '"1900-01-01", 2'],
['#VALUE!', '"1900-01-02", 2'],
[1, ', 11'],
[1, '0, 11'],
[1, '0, 12'],
[1, '0, 13'],
[1, '0, 14'],
[1, '0, 15'],
[1, '0, 16'],
[1, '0, 17'],
[1, '"1905-01-01", 17'],
[1, '0'],
[1, ','],
[1, ', 2'],
[1, '0, 2'],
[1, '"1906-01-01"'],
['#VALUE!', 'true'],
['#VALUE!', 'false, 21'],
[53, ', 21'],
[53, '"1904-01-01", 21'],
['#VALUE!', '"1900-01-01", 21'],
['#VALUE!', '"1900-01-07", 21'],
['#VALUE!', '"1900-01-08", 21'],
['#VALUE!', '"1900-01-09", 21'],
['#VALUE!', '"1900-03-04", 21'],
['#VALUE!', '"1900-03-05", 21'],
['exception', ''],
[48, 'B1'],
[1, 'Q15'],
[27, '"2004-07-02"'],
[1, '"1904-01-02"'],
[0, '"1904-01-01"'],
[0, '"1904-01-01", 1'],
[1, '"1904-01-01", 2'],
[1, '"1904-01-01", 11'],
[1, '"1904-01-01", 12'],
[1, '"1904-01-01", 13'],
[1, '"1904-01-01", 14'],
[1, '"1904-01-01", 15'],
[1, '"1904-01-01", 16'],
[0, '"1904-01-01", 17'],
];

View File

@ -50,10 +50,12 @@ return [
39820,
'19-Dec-2008',
10,
[
'25-Dec-2008',
'26-Dec-2008',
'01-Jan-2009',
],
],
[
39820,
'19-Dec-2008',
@ -79,7 +81,7 @@ return [
],
],
[
41010,
41011, // this had been 41010, which is wrong - confirmed with Excel
'5-Apr-2012',
3,
[
@ -105,4 +107,22 @@ return [
],
],
],
[39598, '2008-06-12', -9],
[44273, '2021-03-15', 3], // issue 1936 Monday
[44274, '2021-03-16', 3], // issue 1936 Tuesday
[44277, '2021-03-17', 3], // issue 1936 Wednesday
[44278, '2021-03-18', 3], // issue 1936 Thursday
[44279, '2021-03-19', 3], // issue 1936 Friday
[44279, '2021-03-20', 3], // issue 1936 Saturday
[44279, '2021-03-21', 3], // issue 1936 Sunday
[44276, '2021-03-21', 0], // issue 1936 Sunday doesn't change for 0
[44258, '2021-03-15', -8], // issue 1936 Monday
[44259, '2021-03-16', -8], // issue 1936 Tuesday
[44260, '2021-03-17', -8], // issue 1936 Wednesday
[44263, '2021-03-18', -8], // issue 1936 Thursday
[44264, '2021-03-19', -8], // issue 1936 Friday
[44265, '2021-03-20', -8], // issue 1936 Saturday
[44265, '2021-03-21', -8], // issue 1936 Sunday
['exception', '2000-01-01', 'omitted'],
['exception', 'omitted'],
];

View File

@ -1,48 +1,22 @@
<?php
return [
[
1900,
null,
],
[
1900,
1,
],
[
1991,
33333.330000000002,
],
[
1960,
22269.0,
],
[
1983,
30348.0,
],
[
1984,
30843.0,
],
[
2525,
'01 Jan 2525',
],
[
1918,
'11-Nov-1918',
],
[
1904,
'28-Feb-1904',
],
[
'#NUM!',
-10,
],
[
'#VALUE!',
'ABCD',
],
[1900, '0'],
[1900, '1'],
[1991, '33333.33'],
[1960, '"22269.0"'],
[1983, '30348.0'],
[1984, '30843.0'],
[2525, '"01 Jan 2525"'],
[1918, '"11-Nov-1918"'],
[1904, '"28-Feb-1904"'],
['#NUM!', '-10'],
['#VALUE!', '"ABCD"'],
[1900, 'Q15'],
[1900, 'false'],
[1900, 'true'],
[1954, 'B1'],
['exception', ''],
[1900, '366'], // because of fake leap day
[1901, '367'],
];

View File

@ -7,6 +7,18 @@ return [
'2007-1-10',
0,
],
[
0.025,
'2007-1-1',
'2007-1-10',
null,
],
[
0.025,
'2007-1-1',
'2007-1-10',
'omitted',
],
[
0.025,
'2007-1-10',
@ -561,4 +573,42 @@ return [
],
['#VALUE!', '2023-04-27', 'ABQZ', 1],
['#VALUE!', 'ABQZ', '2023-04-07', 1],
['#NUM!', '2023-04-27', '2025-05-28', 6],
['exception', '2023-04-27', 'omitted'],
['exception', 'omitted'],
[0, null, null],
// Excel 1900 calendar gets all of the following wrong (null second arg).
// PhpSpreadsheet is bug-compatible.
[108, '2007-12-30', null],
[107.11111111, '2007-02-10', null],
[107, '2006-12-30', null],
[107.00277778, '2006-12-31', null],
[107.00277778, '2007-01-01', null],
[106.99722222, null, '2006-12-29'],
[100.419444, '2000-06-01', null, 0],
[100.419572, '2000-06-01', null, 1],
[101.883333, '2000-06-01', null, 2],
[100.487671, '2000-06-01', null, 3],
[100.419444, '2000-06-01', null, 4],
[108.555556, '2006-12-29', null, 2],
[108.558333, '2006-12-30', null, 2],
[108.561111, '2006-12-31', null, 2],
[108.563889, '2007-01-01', null, 2],
[108.566667, '2007-01-02', null, 2],
// Excel 1900 calendar gets all of the following wrong (null first arg).
// PhpSpreadsheet is bug-compatible.
[107, null, '2006-12-30'],
[107.00277778, null, '2006-12-31'],
[107.00277778, null, '2007-01-01'],
[107.00555556, null, '2007-01-02'],
[107.06849315, null, '2006-12-29', 3],
[107.07123288, null, '2006-12-30', 3],
[107.07397260, null, '2006-12-31', 3],
[107.07671233, null, '2007-01-01', 3],
[107.07945205, null, '2007-01-02', 3],
[100.419444, null, '2000-06-01', 0],
[100.419572, null, '2000-06-01', 1],
[101.883333, null, '2000-06-01', 2],
[100.487671, null, '2000-06-01', 3],
[100.419444, null, '2000-06-01', 4],
];