PHP:按天、周、月、年对时间戳进行分组



在我的应用程序中,我使用RRD,但在几个特定的场景中,我想获取和分组数据(根据时间戳按天、周、月、年)。

这里有一个例子可以让你更好地理解我:

我们有一个包含两个数据源(all, active)的数组。在每个数据源中,键是时间戳,时间戳之间的间隔为86400秒。

$arr = [
"all" => [
"1664236800" => 0,
"1664323200" => 0,
"1664409600" => 0,
"1664496000" => 0,
"1664582400" => 0,
"1664668800" => 0,
"1664755200" => 0,
"1664841600" => 0,
"1664928000" => 0,
"1665014400" => 0,
"1665100800" => 0,
"1665187200" => 0,
"1665273600" => 0,
"1665360000" => 0,
"1665446400" => 0,
"1665532800" => 0,
"1665619200" => 0,
"1665705600" => 0,
"1665792000" => 0,
"1665878400" => 0,
"1665964800" => 0,
"1666051200" => 0,
"1666137600" => 0,
"1666224000" => 0,
"1666310400" => 0,
"1666396800" => 0,
"1666483200" => 0,
"1666569600" => 0,
"1666656000" => 0,
"1666742400" => 0,
"1666828800" => 0,
"1666915200" => 0,
"1667001600" => 0,
"1667088000" => 0,
"1667174400" => 0,
"1667260800" => 0,
"1667347200" => 0,
"1667433600" => 0,
"1667520000" => 0,
"1667606400" => 0,
"1667692800" => 0,
"1667779200" => 0,
"1667865600" => 0,
"1667952000" => 0,
"1668038400" => 0,
"1668124800" => 0,
"1668211200" => 0,
"1668297600" => 0,
"1668384000" => 0,
"1668470400" => 0,
"1668556800" => 0,
"1668643200" => 0,
"1668729600" => 0,
"1668816000" => 0,
"1668902400" => 0,
"1668988800" => 0,
"1669075200" => 0,
"1669161600" => 0,
"1669248000" => 0,
"1669334400" => 0,
"1669420800" => 0,
"1669507200" => 0,
"1669593600" => 0,
"1669680000" => 0,
"1669766400" => 0,
"1669852800" => 0,
"1669939200" => 0,
"1670025600" => 0,
"1670112000" => 0,
"1670198400" => 0,
"1670284800" => 0,
"1670371200" => 0,
"1670457600" => 0,
"1670544000" => 0,
"1670630400" => 0,
"1670716800" => 0,
"1670803200" => 0,
"1670889600" => 0,
"1670976000" => 0,
"1671062400" => 0,
"1671148800" => 0,
"1671235200" => 0,
"1671321600" => 0,
"1671408000" => 0,
"1671494400" => 0,
"1671580800" => 0,
"1671667200" => 0,
"1671753600" => 0,
"1671840000" => 0,
"1671926400" => 0,
"1672012800" => 0,
"1672099200" => 0,
"1672185600" => 0,
"1672272000" => 0,
],
"active" => [
"1664236800" => 0,
"1664323200" => 0,
"1664409600" => 0,
"1664496000" => 0,
"1664582400" => 0,
"1664668800" => 0,
"1664755200" => 0,
"1664841600" => 0,
"1664928000" => 0,
"1665014400" => 0,
"1665100800" => 0,
"1665187200" => 0,
"1665273600" => 0,
"1665360000" => 0,
"1665446400" => 0,
"1665532800" => 0,
"1665619200" => 0,
"1665705600" => 0,
"1665792000" => 0,
"1665878400" => 0,
"1665964800" => 0,
"1666051200" => 0,
"1666137600" => 0,
"1666224000" => 0,
"1666310400" => 0,
"1666396800" => 0,
"1666483200" => 0,
"1666569600" => 0,
"1666656000" => 0,
"1666742400" => 0,
"1666828800" => 0,
"1666915200" => 0,
"1667001600" => 0,
"1667088000" => 0,
"1667174400" => 0,
"1667260800" => 0,
"1667347200" => 0,
"1667433600" => 0,
"1667520000" => 0,
"1667606400" => 0,
"1667692800" => 0,
"1667779200" => 0,
"1667865600" => 0,
"1667952000" => 0,
"1668038400" => 0,
"1668124800" => 0,
"1668211200" => 0,
"1668297600" => 0,
"1668384000" => 0,
"1668470400" => 0,
"1668556800" => 0,
"1668643200" => 0,
"1668729600" => 0,
"1668816000" => 0,
"1668902400" => 0,
"1668988800" => 0,
"1669075200" => 0,
"1669161600" => 0,
"1669248000" => 0,
"1669334400" => 0,
"1669420800" => 0,
"1669507200" => 0,
"1669593600" => 0,
"1669680000" => 0,
"1669766400" => 0,
"1669852800" => 0,
"1669939200" => 0,
"1670025600" => 0,
"1670112000" => 0,
"1670198400" => 0,
"1670284800" => 0,
"1670371200" => 0,
"1670457600" => 0,
"1670544000" => 0,
"1670630400" => 0,
"1670716800" => 0,
"1670803200" => 0,
"1670889600" => 0,
"1670976000" => 0,
"1671062400" => 0,
"1671148800" => 0,
"1671235200" => 0,
"1671321600" => 0,
"1671408000" => 0,
"1671494400" => 0,
"1671580800" => 0,
"1671667200" => 0,
"1671753600" => 0,
"1671840000" => 0,
"1671926400" => 0,
"1672012800" => 0,
"1672099200" => 0,
"1672185600" => 0,
"1672272000" => 0,
]
];

我想把这些数据按月分组。

示例响应:

$arr = [
"1664236800" => [ // 27 September ( this is first value from fetch array)
"all" => [
"1664236800" => 0,
"1664323200" => 0,
"1664409600" => 0,
"1664496000" => 0,
],
"active" => [
"1664236800" => 0,
"1664323200" => 0,
"1664409600" => 0,
"1664496000" => 0,
],
],
"1664582400" => [ // 1st October
"all" => [
"1664582400" => 0,
"1664668800" => 0,
"1664755200" => 0,
"1664841600" => 0,
"1664928000" => 0,
"1665014400" => 0,
"1665100800" => 0,
"1665187200" => 0,
"1665273600" => 0,
"1665360000" => 0,
"1665446400" => 0,
"1665532800" => 0,
"1665619200" => 0,
"1665705600" => 0,
"1665792000" => 0,
"1665878400" => 0,
"1665964800" => 0,
"1666051200" => 0,
"1666137600" => 0,
"1666224000" => 0,
"1666310400" => 0,
"1666396800" => 0,
"1666483200" => 0,
"1666569600" => 0,
"1666656000" => 0,
"1666742400" => 0,
"1666828800" => 0,
"1666915200" => 0,
"1667001600" => 0,
"1667088000" => 0,
"1667174400" => 0,
],
"active" => [
"1664582400" => 0,
"1664668800" => 0,
"1664755200" => 0,
"1664841600" => 0,
"1664928000" => 0,
"1665014400" => 0,
"1665100800" => 0,
"1665187200" => 0,
"1665273600" => 0,
"1665360000" => 0,
"1665446400" => 0,
"1665532800" => 0,
"1665619200" => 0,
"1665705600" => 0,
"1665792000" => 0,
"1665878400" => 0,
"1665964800" => 0,
"1666051200" => 0,
"1666137600" => 0,
"1666224000" => 0,
"1666310400" => 0,
"1666396800" => 0,
"1666483200" => 0,
"1666569600" => 0,
"1666656000" => 0,
"1666742400" => 0,
"1666828800" => 0,
"1666915200" => 0,
"1667001600" => 0,
"1667088000" => 0,
"1667174400" => 0,
],
],
"1667260800" => [ // 1st November
"all" => [
"1667260800" => 0,
"1667347200" => 0,
"1667433600" => 0,
"1667520000" => 0,
"1667606400" => 0,
"1667692800" => 0,
"1667779200" => 0,
"1667865600" => 0,
"1667952000" => 0,
"1668038400" => 0,
"1668124800" => 0,
"1668211200" => 0,
"1668297600" => 0,
"1668384000" => 0,
"1668470400" => 0,
"1668556800" => 0,
"1668643200" => 0,
"1668729600" => 0,
"1668816000" => 0,
"1668902400" => 0,
"1668988800" => 0,
"1669075200" => 0,
"1669161600" => 0,
"1669248000" => 0,
"1669334400" => 0,
"1669420800" => 0,
"1669507200" => 0,
"1669593600" => 0,
"1669680000" => 0,
"1669766400" => 0,
],
"active" => [
"1667260800" => 0,
"1667347200" => 0,
"1667433600" => 0,
"1667520000" => 0,
"1667606400" => 0,
"1667692800" => 0,
"1667779200" => 0,
"1667865600" => 0,
"1667952000" => 0,
"1668038400" => 0,
"1668124800" => 0,
"1668211200" => 0,
"1668297600" => 0,
"1668384000" => 0,
"1668470400" => 0,
"1668556800" => 0,
"1668643200" => 0,
"1668729600" => 0,
"1668816000" => 0,
"1668902400" => 0,
"1668988800" => 0,
"1669075200" => 0,
"1669161600" => 0,
"1669248000" => 0,
"1669334400" => 0,
"1669420800" => 0,
"1669507200" => 0,
"1669593600" => 0,
"1669680000" => 0,
"1669766400" => 0,
],
],
"1669852800" => [ // 1st December
"all" => [
"1669852800" => 0,
"1669939200" => 0,
"1670025600" => 0,
"1670112000" => 0,
"1670198400" => 0,
"1670284800" => 0,
"1670371200" => 0,
"1670457600" => 0,
"1670544000" => 0,
"1670630400" => 0,
"1670716800" => 0,
"1670803200" => 0,
"1670889600" => 0,
"1670976000" => 0,
"1671062400" => 0,
"1671148800" => 0,
"1671235200" => 0,
"1671321600" => 0,
"1671408000" => 0,
"1671494400" => 0,
"1671580800" => 0,
"1671667200" => 0,
"1671753600" => 0,
"1671840000" => 0,
"1671926400" => 0,
"1672012800" => 0,
"1672099200" => 0,
"1672185600" => 0,
"1672272000" => 0,
],
"active" => [
"1669852800" => 0,
"1669939200" => 0,
"1670025600" => 0,
"1670112000" => 0,
"1670198400" => 0,
"1670284800" => 0,
"1670371200" => 0,
"1670457600" => 0,
"1670544000" => 0,
"1670630400" => 0,
"1670716800" => 0,
"1670803200" => 0,
"1670889600" => 0,
"1670976000" => 0,
"1671062400" => 0,
"1671148800" => 0,
"1671235200" => 0,
"1671321600" => 0,
"1671408000" => 0,
"1671494400" => 0,
"1671580800" => 0,
"1671667200" => 0,
"1671753600" => 0,
"1671840000" => 0,
"1671926400" => 0,
"1672012800" => 0,
"1672099200" => 0,
"1672185600" => 0,
"1672272000" => 0,
],
]
];

我能做的最好的方法是什么?

我的方法是转换date("Y-d", $timestamp)中的每个时间戳并按响应分组。(不知道效果如何)

最简单的方法是遍历原始数组,并为每个时间戳计算正确的月槽:

$result = array();
foreach($arr as $type => $items)
{
foreach($items as $timestamp => $value)
{
// compute first day of month
$d = new DateTime();
$d->setTimestamp(intval($timestamp)); // load timestamp into a DateTime object
$d->setTimeZone(new DateTimeZone('UTC'));
$d->setTime(0, 0, 0); // remove hours, minutes and seconds parts (if needed)
$d->modify('first day of this month');
$firstMonthTimestamp = strval($d->getTimestamp());

// create result array structure the first time
if(!array_key_exists($firstMonthTimestamp, $result)) $result[$firstMonthTimestamp] = array();
if(!array_key_exists($type, $result[$firstMonthTimestamp])) $result[$firstMonthTimestamp][$type] = array();

// append element to the month list
$result[$firstMonthTimestamp][$type][$timestamp] = $value ;
}
}
print_r($result);

就像经常发生的那样,在你问了一个问题之后,一个答案就会在你的脑海中闪现。

上面的解决方案很好,但我需要能够按小时、天、周、月和年对这些数据进行分组

这是我经过几天思考后的解决方案。

$groupData = (new Grouper())->group(new GroupByMonth(), $arr);

Grouper.php

class Grouper
{
public function group(GrouperInterface $service, $data)
{
$dataSources     = array_keys($data);
$timestamps      = array_keys($data[$dataSources[0]]);
$groupData       = [];
$lastKey = null;
foreach ($timestamps as $timestamp) {
if ($service->isNewGroup($timestamp)) {
$groupData[$timestamp] = array_fill_keys($dataSources, []);
$lastKey = $timestamp;
}
foreach ($dataSources as $ds) {
$groupData[$lastKey][$ds][$timestamp] = $data[$ds][$timestamp];
}
}
return $groupData;
}
}

GroupByMonth.php

class GroupByMonth implements GrouperInterface
{
private int $endTimestamp = -1;
public function isNewGroup(int $timestamp): bool
{
if ($this->endTimestamp >= $timestamp) {
return false;
}
$this->endTimestamp = $this->calculateEndTimestamp($timestamp);
return true;
}
private function calculateEndTimestamp(int $timestamp): int
{
list($year, $month) = explode('-', date('Y-n', $timestamp));
$daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$date = DateTime::createFromFormat("Y-n-d H:i:s", "{$year}-{$month}-{$daysInMonth} 23:59:59");
return $date->getTimestamp();
}
}

这对我来说是一个更好的解决方案,因为它允许我编写更多的分组功能

最新更新