From 7000e7318d641a477f3a7d78ae03ff2be2f75357 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Mon, 3 Nov 2025 10:53:04 +0200 Subject: [PATCH] removed min agg interval type --- .../EntityAggregationCalculatedFieldTest.java | 3 +- .../single/interval/AggInterval.java | 1 - .../single/interval/AggIntervalType.java | 1 - .../single/interval/BaseAggInterval.java | 125 ++++++------------ .../single/interval/CustomInterval.java | 32 +++-- .../single/interval/MinInterval.java | 30 ----- 6 files changed, 67 insertions(+), 125 deletions(-) delete mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java diff --git a/application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java b/application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java index 2509263dce..5a73b026f0 100644 --- a/application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java +++ b/application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java @@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.cf.configuration.aggregation.AggKeyInp import org.thingsboard.server.common.data.cf.configuration.aggregation.AggMetric; import org.thingsboard.server.common.data.cf.configuration.aggregation.single.EntityAggregationCalculatedFieldConfiguration; import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.AggInterval; -import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.AggIntervalType; import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.CustomInterval; import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.Watermark; import org.thingsboard.server.common.data.debug.DebugSettings; @@ -92,7 +91,7 @@ public class EntityAggregationCalculatedFieldTest extends AbstractControllerTest public void testCreateCf_checkAggregation() throws Exception { Device device = createDevice("Device", "1234567890111"); - CustomInterval customInterval = new CustomInterval(1, AggIntervalType.MIN, 0, "Europe/Kyiv"); + CustomInterval customInterval = new CustomInterval(60L, 0L, "Europe/Kyiv"); long currentIntervalStartTs = customInterval.getCurrentIntervalStartTs(); long currentIntervalEndTs = customInterval.getCurrentIntervalEndTs(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggInterval.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggInterval.java index d923eb5d7a..d6d1aca6a8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggInterval.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggInterval.java @@ -26,7 +26,6 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; property = "type" ) @JsonSubTypes({ - @JsonSubTypes.Type(value = MinInterval.class, name = "MIN"), @JsonSubTypes.Type(value = HourInterval.class, name = "HOUR"), @JsonSubTypes.Type(value = DayInterval.class, name = "DAY"), @JsonSubTypes.Type(value = WeekInterval.class, name = "WEEK"), diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggIntervalType.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggIntervalType.java index 96bac69128..62185127ed 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggIntervalType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggIntervalType.java @@ -17,7 +17,6 @@ package org.thingsboard.server.common.data.cf.configuration.aggregation.single.i public enum AggIntervalType { - MIN, HOUR, DAY, WEEK, diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/BaseAggInterval.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/BaseAggInterval.java index d8df2d9826..e64ec117fd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/BaseAggInterval.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/BaseAggInterval.java @@ -15,11 +15,11 @@ */ package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; +import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import java.time.DayOfWeek; import java.time.Duration; -import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; @@ -28,127 +28,90 @@ import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalAdjusters; @Data +@JsonInclude(JsonInclude.Include.NON_NULL) public abstract class BaseAggInterval implements AggInterval { protected String tz; - protected long offsetMillis; // delay millis since start of interval + protected Long offsetSec; // delay seconds since start of interval @Override public long getIntervalDurationMillis() { - return getIntervalDurationMillis(getType(), 1); - } - - public long getIntervalDurationMillis(AggIntervalType type, int multiplier) { - return switch (type) { - case MIN -> Duration.ofMinutes(multiplier).toMillis(); - case HOUR -> Duration.ofHours(multiplier).toMillis(); - case DAY -> Duration.ofDays(multiplier).toMillis(); - case WEEK, WEEK_SUN_SAT -> Duration.ofDays(7L * multiplier).toMillis(); - case MONTH -> Duration.ofDays(Math.round(30 * multiplier)).toMillis(); // average - case YEAR -> Duration.ofDays(Math.round(365 * multiplier)).toMillis(); - default -> throw new IllegalArgumentException("Unsupported type: " + type); + return switch (getType()) { + case HOUR -> Duration.ofHours(1).toMillis(); + case DAY -> Duration.ofDays(1).toMillis(); + case WEEK, WEEK_SUN_SAT -> Duration.ofDays(7L).toMillis(); + case MONTH -> Duration.ofDays(Math.round(30)).toMillis(); // average + case YEAR -> Duration.ofDays(Math.round(365)).toMillis(); + default -> throw new IllegalArgumentException("Unsupported type: " + getType()); }; } @Override public long getCurrentIntervalStartTs() { - return getCurrentIntervalStartTs(getType(), 1); - } - - protected long getCurrentIntervalStartTs(AggIntervalType type, int multiplier) { ZoneId zoneId = ZoneId.of(tz); ZonedDateTime now = ZonedDateTime.now(zoneId); - ZonedDateTime shiftedNow = now.minus(Duration.ofMillis(offsetMillis)); - ZonedDateTime alignedStart = getAlignedBoundary(type, multiplier, false, shiftedNow); - ZonedDateTime actualStart = alignedStart.plus(Duration.ofMillis(offsetMillis)); + ZonedDateTime shiftedNow = now.minusSeconds(offsetSec); + ZonedDateTime alignedStart = getAlignedBoundary(shiftedNow, false); + ZonedDateTime actualStart = alignedStart.plusSeconds(offsetSec); return actualStart.toInstant().toEpochMilli(); } @Override public long getCurrentIntervalEndTs() { - return getCurrentIntervalEndTs(getType(), 1); - } - - protected long getCurrentIntervalEndTs(AggIntervalType type, int multiplier) { ZoneId zoneId = ZoneId.of(tz); ZonedDateTime now = ZonedDateTime.now(zoneId); - ZonedDateTime shiftedNow = now.minus(Duration.ofMillis(offsetMillis)); - ZonedDateTime alignedEnd = getAlignedBoundary(type, multiplier, true, shiftedNow); - ZonedDateTime actualEnd = alignedEnd.plus(Duration.ofMillis(offsetMillis)); + ZonedDateTime shiftedNow = now.minusSeconds(offsetSec); + ZonedDateTime alignedEnd = getAlignedBoundary(shiftedNow, true); + ZonedDateTime actualEnd = alignedEnd.plusSeconds(offsetSec); return actualEnd.toInstant().toEpochMilli(); } @Override public long getDelayUntilIntervalEnd() { - return getDelayUntilIntervalEnd(getType(), 1); - } - - protected long getDelayUntilIntervalEnd(AggIntervalType type, int multiplier) { - long currentIntervalEndTs = getCurrentIntervalEndTs(type, multiplier); + long currentIntervalEndTs = getCurrentIntervalEndTs(); long now = System.currentTimeMillis(); return currentIntervalEndTs - now; } - protected ZonedDateTime getAlignedBoundary(AggIntervalType type, int multiplier, boolean next, ZonedDateTime reference) { - return switch (type) { - case MIN -> alignByMin(reference, multiplier, next); - case HOUR -> alignByHour(reference, multiplier, next); - case DAY -> alignByDay(reference, multiplier, next); - case WEEK -> alignByWeek(reference, multiplier, DayOfWeek.MONDAY, next); - case WEEK_SUN_SAT -> alignByWeek(reference, multiplier, DayOfWeek.SUNDAY, next); - case MONTH -> alignByMonth(reference, multiplier, next); - case YEAR -> alignByYear(reference, multiplier, next); - default -> throw new IllegalArgumentException("Unsupported type: " + type); + protected ZonedDateTime getAlignedBoundary(ZonedDateTime reference, boolean next) { + return switch (getType()) { + case HOUR -> alignByHours(reference, next); + case DAY -> alignByDays(reference, next); + case WEEK -> alignByWeeks(reference, DayOfWeek.MONDAY, next); + case WEEK_SUN_SAT -> alignByWeeks(reference, DayOfWeek.SUNDAY, next); + case MONTH -> alignByMonths(reference, next); + case YEAR -> alignByYears(reference, next); + default -> throw new IllegalArgumentException("Unsupported interval type: " + getType()); }; } - private ZonedDateTime alignByMin(ZonedDateTime now, int multiplier, boolean next) { - ZonedDateTime startOfHour = now.truncatedTo(ChronoUnit.HOURS); - long minsSinceHour = Duration.between(startOfHour, now).toMinutes(); - long aligned = (minsSinceHour / multiplier) * multiplier; - if (next) aligned += multiplier; - return startOfHour.plusMinutes(aligned); - } - - private ZonedDateTime alignByHour(ZonedDateTime now, int multiplier, boolean next) { - ZonedDateTime startOfDay = now.truncatedTo(ChronoUnit.DAYS); - long hoursSinceMidnight = Duration.between(startOfDay, now).toHours(); - long aligned = (hoursSinceMidnight / multiplier) * multiplier; - if (next) aligned += multiplier; - return startOfDay.plusHours(aligned); + private ZonedDateTime alignByHours(ZonedDateTime now, boolean next) { + ZonedDateTime base = now.truncatedTo(ChronoUnit.HOURS); + return next ? base.plusHours(1) : base; } - private ZonedDateTime alignByDay(ZonedDateTime now, int multiplier, boolean next) { - long daysSinceEpoch = now.toLocalDate().toEpochDay(); - long aligned = (daysSinceEpoch / multiplier) * multiplier; - if (next) aligned += multiplier; - long diff = aligned - daysSinceEpoch; - return now.truncatedTo(ChronoUnit.DAYS).plusDays(diff); + private ZonedDateTime alignByDays(ZonedDateTime now, boolean next) { + ZonedDateTime base = now.truncatedTo(ChronoUnit.DAYS); + return next ? base.plusDays(1) : base; } - private ZonedDateTime alignByWeek(ZonedDateTime now, int multiplier, DayOfWeek startOfWeekDay, boolean next) { - ZonedDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(startOfWeekDay)) + private ZonedDateTime alignByWeeks(ZonedDateTime now, DayOfWeek startOfWeek, boolean next) { + ZonedDateTime startOfWeekDate = now.with(TemporalAdjusters.previousOrSame(startOfWeek)) .truncatedTo(ChronoUnit.DAYS); - long weeksSinceEpoch = ChronoUnit.WEEKS.between( - ZonedDateTime.ofInstant(Instant.EPOCH, now.getZone()), startOfWeek); - long aligned = (weeksSinceEpoch / multiplier) * multiplier; - if (next) aligned += multiplier; - return startOfWeek.plusWeeks(aligned - weeksSinceEpoch); + return next ? startOfWeekDate.plusWeeks(1) : startOfWeekDate; } - private ZonedDateTime alignByMonth(ZonedDateTime now, int multiplier, boolean next) { - ZonedDateTime startOfMonth = now.withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS); - long monthsSinceEpoch = now.getYear() * 12L + now.getMonthValue() - 1; - long aligned = (monthsSinceEpoch / multiplier) * multiplier; - if (next) aligned += multiplier; - return startOfMonth.plusMonths(aligned - monthsSinceEpoch); + private ZonedDateTime alignByMonths(ZonedDateTime now, boolean next) { + ZonedDateTime base = now.withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS); + return next ? base.plusMonths(1) : base; } - private ZonedDateTime alignByYear(ZonedDateTime now, int multiplier, boolean next) { - int year = now.getYear(); - int aligned = (year / multiplier) * multiplier; - if (next) aligned += multiplier; - return ZonedDateTime.of(LocalDate.of(aligned, 1, 1), LocalTime.MIDNIGHT, now.getZone()); + private ZonedDateTime alignByYears(ZonedDateTime now, boolean next) { + ZonedDateTime base = ZonedDateTime.of( + LocalDate.of(now.getYear(), 1, 1), + LocalTime.MIDNIGHT, + now.getZone()); + return next ? base.plusYears(1) : base; } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/CustomInterval.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/CustomInterval.java index cc56b2aef3..3a07029bc8 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/CustomInterval.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/CustomInterval.java @@ -19,19 +19,22 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; +import java.time.Duration; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.concurrent.TimeUnit; + @EqualsAndHashCode(callSuper = true) @Data @NoArgsConstructor public class CustomInterval extends BaseAggInterval { - private int multiplier; // number of base units (e.g. 2 hours, 5 days) - private AggIntervalType internalIntervalType; + private Long durationSec; - public CustomInterval(int multiplier, AggIntervalType internalIntervalType, long offsetMillis, String tz) { + public CustomInterval(Long durationSec, Long offsetMillis, String tz) { this.tz = tz; - this.offsetMillis = offsetMillis; - this.multiplier = multiplier; - this.internalIntervalType = internalIntervalType; + this.offsetSec = offsetMillis; + this.durationSec = durationSec; } @Override @@ -41,22 +44,31 @@ public class CustomInterval extends BaseAggInterval { @Override public long getIntervalDurationMillis() { - return getIntervalDurationMillis(internalIntervalType, multiplier); + return Duration.ofSeconds(durationSec).toMillis(); } @Override public long getCurrentIntervalStartTs() { - return super.getCurrentIntervalStartTs(internalIntervalType, multiplier); + ZoneId zoneId = ZoneId.of(tz); + ZonedDateTime now = ZonedDateTime.now(zoneId); + ZonedDateTime shiftedNow = now.minusSeconds(offsetSec); + + long durationMillis = getIntervalDurationMillis(); + long shiftedNowMillis = shiftedNow.toInstant().toEpochMilli(); + long alignedStartMillis = (shiftedNowMillis / durationMillis) * durationMillis; + + long offsetMillis = TimeUnit.SECONDS.toMillis(offsetSec); + return alignedStartMillis + offsetMillis; } @Override public long getCurrentIntervalEndTs() { - return super.getCurrentIntervalEndTs(internalIntervalType, multiplier); + return getCurrentIntervalStartTs() + getIntervalDurationMillis(); } @Override public long getDelayUntilIntervalEnd() { - return super.getDelayUntilIntervalEnd(internalIntervalType, multiplier); + return getCurrentIntervalEndTs() - System.currentTimeMillis(); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java b/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java deleted file mode 100644 index 066bc230b8..0000000000 --- a/common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Copyright © 2016-2025 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; - -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -public class MinInterval extends BaseAggInterval { - - @Override - public AggIntervalType getType() { - return AggIntervalType.MIN; - } - -}