skip to Main Content

In my application I am using RRD, but in several specific scenarios I want to fetch and group data (by days, weeks, months, years based on timestamps).

Here is an example to understand me better:

We have array with two data sources (all, active). In each data source, keys are timestamps and interval between timestamps is 86400 sec.

$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,
    ]
];

I want to group this data in months.

The example response:

$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,
        ],
    ]
];

Which is the best way I can do this?

My way is to convert each timestamp in date("Y-d", $timestamp) and group by response. (don’t know how effective is)

2

Answers


  1. Chosen as BEST ANSWER

    As often happens, after you ask a question an answer pops into your head.

    The above solution is good, but I need to be able to group this data by hours, days, weeks, months and years

    This is my solution after several days of reflection.

    $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();
        }
    }
    

    This is a better solution for me because it allows me to write more grouping functionality


  2. The simplest approach is to loop over your original array, and compute the correct monthly slot for each 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);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search