如何获取时间戳:当前季度 start/end、上季度 start/end、从 PHP 中的指定日期开始

How to get timestamp of: current year quarter start/end, last quarter start/end, from specified date in PHP

在 PHP 中是否有任何库或随时可用的函数来轻松计算时间戳?

我需要得到:

  1. unixtimestamp: 当前季度的第一秒,
  2. unixtimestamp: 当前季度的最后一秒,
  3. unixtimestamp:上一季度的第一秒,
  4. unixtimestamp:上一季度的最后一秒,

问题:

你是怎么计算的? 我的代码看起来很复杂...

我给你写了一个函数。

function getTimestampFromQuarter(string $quarterName = 'current', string $returnTimestamp = 'start', string $timezone = 'UTC', int $year = null): int {

    $dt = new DateTime();
    $dt->setTimezone(new DateTimeZone($timezone));


    // if year not defined, we use current year
    $year = $year ?? date('Y');

    // current month
    $month = date("n");

    // current quarter number
    $quarter = ceil($month / 3);

    // we are looking for previous quarter
    if (in_array(strtolower($quarterName), ['previous','last'])) {
        $quarter--;
        if (0 == $quarter) {
            $quarter = 4;
            $year--;
        }
    }

    // we are looking for next quarter
    elseif (in_array(strtolower($quarterName), ['next'])) {
        $quarter++;
        if (4 == $quarter) {
            $quarter = 1;
            $year++;
        }
    }

    $quarterFirstMonth = (12 / 4) * ($quarter - 1) + 1; // first month of quarter
    $quarterLastMonth = (12 / 4) * ($quarter - 1) + 3; // last month of quarter


    if ('start'==$returnTimestamp) {
        $dt->setDate($year, $quarterFirstMonth, 1);
        $dt->setTime(0, 0, 0);
    }
    elseif ('end'==$returnTimestamp) {

        // looking for month days count
        $ts = new DateTime();
        $ts->setDate($year, $quarterLastMonth, 1);
        $ts->setTimezone(new DateTimeZone($timezone));
        $day = date('t', $ts->getTimestamp());
        unset($ts);


        $dt->setDate($year, $quarterLastMonth, $day);
        $dt->setTime(23, 59, 59);
    }

    return $dt->getTimestamp();
}

用法很简单:

1.. 当前季度的第一秒:

echo getTimestampFromQuarter('current', 'start');
// output: 1633046400 (equals to Friday 1. October 2021 0:00:00)

2.. 当前季度的最后一秒:

echo getTimestampFromQuarter('current', 'end'); 
// output: 1640995199 (equals to Friday 31. December 2021 23:59:59)

3.. 上一季度第一秒:

echo getTimestampFromQuarter('previous', 'start'); 
// output: 1625097600 (equals to Thursday 1. July 2021 0:00:00)

4.. 上一季度的最后一秒:

echo getTimestampFromQuarter('previous', 'end'); 
// output: 1633046399 (equals to Thursday 30. September 2021 23:59:59)

5.. 下个季度的第一秒:

echo getTimestampFromQuarter('next', 'start'); 
// output: 1640995200 (equals to Saturday 1. January 2022 0:00:00)

6.. 下个季度的最后一秒:

echo getTimestampFromQuarter('next', 'end'); 
// output: 1648771199 (equals to Thursday 31. March 2022 23:59:59)

编辑:我添加了第三个参数,以便可以从时间戳支持的部分时间的任何地方调用该函数。第一个参数现在应该支持数值(偏移量),因此 'previous' 和 -1 应该给出相同的结果。

除此之外..检查我答案底部的测试用例块可能是最简单的。

function getQuarterTimestamp(string $quarter, string $timeOfDay, int $timestamp = null) : int {
    $timestamp = $timestamp ?? time();
    if ($timestamp < 0) {
        throw new InvalidArgumentException("Bad timestamp argument");
    }

    // Offset to start of current quarter
    $currentMonthQuarterOffset = - (date('n', $timestamp) + 2) % 3;

    switch($quarter) {
        case 'next':
            $currentMonthQuarterOffset += 3; // Move forward 1 quarter
            break;
        case 'current':
            break;
        case 'previous':
            $currentMonthQuarterOffset -= 3; // Move back 1 quarter
            break;
        case is_numeric($quarter):
            $currentMonthQuarterOffset += 3*$quarter; // Move the number of quarters in $quarters
            break;
        default:
            throw new InvalidArgumentException("Bad quarter argument");
            break;
    }

    switch($timeOfDay) {
        case 'start':
            $dayOffset = 'first';
            $timeOffset = '00:00:00';
            break;
        case 'end':
            $currentMonthQuarterOffset += 2; // Default is start, move to end of quarter
            $dayOffset = 'last';
            $timeOffset = '23:59:59';
            break;
        default:
            throw new InvalidArgumentException("Bad timeOfDay argument");
            break;
    }

    $dateTimeStr = "{$dayOffset} day of {$currentMonthQuarterOffset} month ".date('Y-m-d', $timestamp)." {$timeOffset}";

    return (new DateTime($dateTimeStr))->getTimeStamp();
}

..这是一些测试代码(注释是在 11 月 28 日 -21 日 运行 之后的输出):

echo date("Y-m-d H:i:s\n", getQuarterTimestamp('previous', 'start')); // 2021-07-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('previous', 'end')); // 2021-09-30 23:59:59
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('current', 'start')); // 2021-10-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('current', 'end')); // 2021-12-31 23:59:59
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('next', 'start')); // 2022-01-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('next', 'end')); // 2022-03-31 23:59:59

echo date("Y-m-d H:i:s\n", getQuarterTimestamp('previous', 'start', strtotime('2021-01-23 01:01:01'))); // 2020-10-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('previous', 'end', strtotime('2021-01-23 01:01:01'))); // 2020-12-31 23:59:59

echo date("Y-m-d H:i:s\n", getQuarterTimestamp(-4, 'start', strtotime('2021-01-23 01:01:01'))); // 2020-01-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp(-4, 'end', strtotime('2021-01-23 01:01:01'))); // 2020-03-31 23:59:59

echo date("Y-m-d H:i:s\n", getQuarterTimestamp('current', 'start', strtotime('2021-01-23 01:01:01'))); // 2021-01-01 00:00:00
echo date("Y-m-d H:i:s\n", getQuarterTimestamp('current', 'end', strtotime('2021-01-23 01:01:01'))); // 2021-03-31 23:59:59

注意: case is_numeric($quarter) 部分有效是因为 case 行的仔细排序,并且在技术上是不正确的语法,最好是将它移到 switch 之外(并删除默认情况下的例外情况)。如果有人要我我可以写一个这样的版本。