如何获取时间戳:当前季度 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 中是否有任何库或随时可用的函数来轻松计算时间戳?
我需要得到:
- unixtimestamp: 当前季度的第一秒,
- unixtimestamp: 当前季度的最后一秒,
- unixtimestamp:上一季度的第一秒,
- unixtimestamp:上一季度的最后一秒,
问题:
- 时区,
- 示例 3) 和 4) 中的年初
你是怎么计算的?
我的代码看起来很复杂...
我给你写了一个函数。
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
之外(并删除默认情况下的例外情况)。如果有人要我我可以写一个这样的版本。
在 PHP 中是否有任何库或随时可用的函数来轻松计算时间戳?
我需要得到:
- unixtimestamp: 当前季度的第一秒,
- unixtimestamp: 当前季度的最后一秒,
- unixtimestamp:上一季度的第一秒,
- unixtimestamp:上一季度的最后一秒,
问题:
- 时区,
- 示例 3) 和 4) 中的年初
你是怎么计算的? 我的代码看起来很复杂...
我给你写了一个函数。
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
之外(并删除默认情况下的例外情况)。如果有人要我我可以写一个这样的版本。