279 lines
10 KiB
PHP
279 lines
10 KiB
PHP
<?php
|
|
|
|
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
|
|
|
|
use DateTime;
|
|
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
|
|
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
|
|
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
|
|
|
|
class Week
|
|
{
|
|
use ArrayEnabled;
|
|
|
|
/**
|
|
* 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
|
|
* Or can be an array of date values
|
|
* @param array|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).
|
|
* Or can be an array of methods
|
|
*
|
|
* @return array|int|string Week Number
|
|
* If an array of values is passed as the argument, then the returned result will also be an array
|
|
* with the same dimensions
|
|
*/
|
|
public static function number($dateValue, $method = Constants::STARTWEEK_SUNDAY)
|
|
{
|
|
if (is_array($dateValue) || is_array($method)) {
|
|
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $method);
|
|
}
|
|
|
|
$origDateValueNull = empty($dateValue);
|
|
|
|
try {
|
|
$method = self::validateMethod($method);
|
|
if ($dateValue === null) { // boolean not allowed
|
|
$dateValue = (SharedDateHelper::getExcelCalendar() === SharedDateHelper::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 = SharedDateHelper::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 = (int) $PHPDateObject->format('z');
|
|
$PHPDateObject->modify('-' . $dayOfYear . ' days');
|
|
$firstDayOfFirstWeek = (int) $PHPDateObject->format('w');
|
|
$daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
|
|
$daysInFirstWeek += 7 * !$daysInFirstWeek;
|
|
$endFirstWeek = $daysInFirstWeek - 1;
|
|
$weekOfYear = floor(($dayOfYear - $endFirstWeek + 13) / 7);
|
|
|
|
return (int) $weekOfYear;
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* Or can be an array of date values
|
|
*
|
|
* @return array|int|string Week Number
|
|
* If an array of numbers is passed as the argument, then the returned result will also be an array
|
|
* with the same dimensions
|
|
*/
|
|
public static function isoWeekNumber($dateValue)
|
|
{
|
|
if (is_array($dateValue)) {
|
|
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $dateValue);
|
|
}
|
|
|
|
if (self::apparentBug($dateValue)) {
|
|
return 52;
|
|
}
|
|
|
|
try {
|
|
$dateValue = Helpers::getDateValue($dateValue);
|
|
} catch (Exception $e) {
|
|
return $e->getMessage();
|
|
}
|
|
|
|
// Execute function
|
|
$PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue);
|
|
Helpers::silly1900($PHPDateObject);
|
|
|
|
return (int) $PHPDateObject->format('W');
|
|
}
|
|
|
|
/**
|
|
* 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 null|array|float|int|string $dateValue Excel date serial value (float), PHP date timestamp (integer),
|
|
* PHP DateTime object, or a standard date string
|
|
* Or can be an array of date values
|
|
* @param mixed $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).
|
|
* Or can be an array of styles
|
|
*
|
|
* @return array|int|string Day of the week value
|
|
* If an array of values is passed as the argument, then the returned result will also be an array
|
|
* with the same dimensions
|
|
*/
|
|
public static function day($dateValue, $style = 1)
|
|
{
|
|
if (is_array($dateValue) || is_array($style)) {
|
|
return self::evaluateArrayArguments([self::class, __FUNCTION__], $dateValue, $style);
|
|
}
|
|
|
|
try {
|
|
$dateValue = Helpers::getDateValue($dateValue);
|
|
$style = self::validateStyle($style);
|
|
} catch (Exception $e) {
|
|
return $e->getMessage();
|
|
}
|
|
|
|
// Execute function
|
|
$PHPDateObject = SharedDateHelper::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;
|
|
}
|
|
|
|
/**
|
|
* @param mixed $style expect int
|
|
*/
|
|
private static function validateStyle($style): int
|
|
{
|
|
if (!is_numeric($style)) {
|
|
throw new Exception(ExcelError::VALUE());
|
|
}
|
|
$style = (int) $style;
|
|
if (($style < 1) || ($style > 3)) {
|
|
throw new Exception(ExcelError::NAN());
|
|
}
|
|
|
|
return $style;
|
|
}
|
|
|
|
private static function dow0Becomes7(int $DoW): int
|
|
{
|
|
return ($DoW === 0) ? 7 : $DoW;
|
|
}
|
|
|
|
/**
|
|
* @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
|
|
* PHP DateTime object, or a standard date string
|
|
*/
|
|
private static function apparentBug($dateValue): bool
|
|
{
|
|
if (SharedDateHelper::getExcelCalendar() !== SharedDateHelper::CALENDAR_MAC_1904) {
|
|
if (is_bool($dateValue)) {
|
|
return true;
|
|
}
|
|
if (is_numeric($dateValue) && !((int) $dateValue)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Validate dateValue parameter.
|
|
*
|
|
* @param mixed $dateValue
|
|
*/
|
|
private static function validateDateValue($dateValue): float
|
|
{
|
|
if (is_bool($dateValue)) {
|
|
throw new Exception(ExcelError::VALUE());
|
|
}
|
|
|
|
return Helpers::getDateValue($dateValue);
|
|
}
|
|
|
|
/**
|
|
* Validate method parameter.
|
|
*
|
|
* @param mixed $method
|
|
*/
|
|
private static function validateMethod($method): int
|
|
{
|
|
if ($method === null) {
|
|
$method = Constants::STARTWEEK_SUNDAY;
|
|
}
|
|
|
|
if (!is_numeric($method)) {
|
|
throw new Exception(ExcelError::VALUE());
|
|
}
|
|
|
|
$method = (int) $method;
|
|
if (!array_key_exists($method, Constants::METHODARR)) {
|
|
throw new Exception(ExcelError::NAN());
|
|
}
|
|
$method = Constants::METHODARR[$method];
|
|
|
|
return $method;
|
|
}
|
|
|
|
private static function buggyWeekNum1900(int $method): bool
|
|
{
|
|
return $method === Constants::DOW_SUNDAY && SharedDateHelper::getExcelCalendar() === SharedDateHelper::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 && SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_MAC_1904 &&
|
|
!$origNull && $dateObject->format('Y-m-d') === '1904-01-01';
|
|
}
|
|
}
|