Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
ReportPeriod
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
7 / 7
8
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 monthContaining
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 start
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 end
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 contains
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 next
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 previous
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4/**
5 * SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
6 * SPDX-License-Identifier: AGPL-3.0-or-later
7 */
8
9namespace OCA\Libresign\Service\UsageStatistics\Model;
10
11/**
12 * A calendar month in UTC, start-inclusive and end-exclusive.
13 */
14final class ReportPeriod {
15    private function __construct(
16        private readonly \DateTimeImmutable $start,
17        private readonly \DateTimeImmutable $end,
18    ) {
19    }
20
21    public static function monthContaining(\DateTimeInterface $instant): self {
22        $utc = \DateTimeImmutable::createFromInterface($instant)->setTimezone(new \DateTimeZone('UTC'));
23        $start = $utc->setDate((int)$utc->format('Y'), (int)$utc->format('n'), 1)->setTime(0, 0);
24        return new self($start, $start->modify('+1 month'));
25    }
26
27    public function start(): \DateTimeImmutable {
28        return $this->start;
29    }
30
31    public function end(): \DateTimeImmutable {
32        return $this->end;
33    }
34
35    public function contains(\DateTimeInterface $instant): bool {
36        return $instant >= $this->start && $instant < $this->end;
37    }
38
39    public function next(): self {
40        return new self($this->end, $this->end->modify('+1 month'));
41    }
42
43    public function previous(): self {
44        return new self($this->start->modify('-1 month'), $this->start);
45    }
46}