Browse Source

removed min agg interval type

pull/14253/head
IrynaMatveieva 11 months ago
parent
commit
7000e7318d
  1. 3
      application/src/test/java/org/thingsboard/server/cf/EntityAggregationCalculatedFieldTest.java
  2. 1
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggInterval.java
  3. 1
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/AggIntervalType.java
  4. 125
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/BaseAggInterval.java
  5. 32
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/CustomInterval.java
  6. 30
      common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java

3
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.AggMetric;
import org.thingsboard.server.common.data.cf.configuration.aggregation.single.EntityAggregationCalculatedFieldConfiguration; 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.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.CustomInterval;
import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.Watermark; import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.Watermark;
import org.thingsboard.server.common.data.debug.DebugSettings; import org.thingsboard.server.common.data.debug.DebugSettings;
@ -92,7 +91,7 @@ public class EntityAggregationCalculatedFieldTest extends AbstractControllerTest
public void testCreateCf_checkAggregation() throws Exception { public void testCreateCf_checkAggregation() throws Exception {
Device device = createDevice("Device", "1234567890111"); 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 currentIntervalStartTs = customInterval.getCurrentIntervalStartTs();
long currentIntervalEndTs = customInterval.getCurrentIntervalEndTs(); long currentIntervalEndTs = customInterval.getCurrentIntervalEndTs();

1
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" property = "type"
) )
@JsonSubTypes({ @JsonSubTypes({
@JsonSubTypes.Type(value = MinInterval.class, name = "MIN"),
@JsonSubTypes.Type(value = HourInterval.class, name = "HOUR"), @JsonSubTypes.Type(value = HourInterval.class, name = "HOUR"),
@JsonSubTypes.Type(value = DayInterval.class, name = "DAY"), @JsonSubTypes.Type(value = DayInterval.class, name = "DAY"),
@JsonSubTypes.Type(value = WeekInterval.class, name = "WEEK"), @JsonSubTypes.Type(value = WeekInterval.class, name = "WEEK"),

1
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 { public enum AggIntervalType {
MIN,
HOUR, HOUR,
DAY, DAY,
WEEK, WEEK,

125
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; package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data; import lombok.Data;
import java.time.DayOfWeek; import java.time.DayOfWeek;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
@ -28,127 +28,90 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters; import java.time.temporal.TemporalAdjusters;
@Data @Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public abstract class BaseAggInterval implements AggInterval { public abstract class BaseAggInterval implements AggInterval {
protected String tz; protected String tz;
protected long offsetMillis; // delay millis since start of interval protected Long offsetSec; // delay seconds since start of interval
@Override @Override
public long getIntervalDurationMillis() { public long getIntervalDurationMillis() {
return getIntervalDurationMillis(getType(), 1); return switch (getType()) {
} case HOUR -> Duration.ofHours(1).toMillis();
case DAY -> Duration.ofDays(1).toMillis();
public long getIntervalDurationMillis(AggIntervalType type, int multiplier) { case WEEK, WEEK_SUN_SAT -> Duration.ofDays(7L).toMillis();
return switch (type) { case MONTH -> Duration.ofDays(Math.round(30)).toMillis(); // average
case MIN -> Duration.ofMinutes(multiplier).toMillis(); case YEAR -> Duration.ofDays(Math.round(365)).toMillis();
case HOUR -> Duration.ofHours(multiplier).toMillis(); default -> throw new IllegalArgumentException("Unsupported type: " + getType());
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);
}; };
} }
@Override @Override
public long getCurrentIntervalStartTs() { public long getCurrentIntervalStartTs() {
return getCurrentIntervalStartTs(getType(), 1);
}
protected long getCurrentIntervalStartTs(AggIntervalType type, int multiplier) {
ZoneId zoneId = ZoneId.of(tz); ZoneId zoneId = ZoneId.of(tz);
ZonedDateTime now = ZonedDateTime.now(zoneId); ZonedDateTime now = ZonedDateTime.now(zoneId);
ZonedDateTime shiftedNow = now.minus(Duration.ofMillis(offsetMillis)); ZonedDateTime shiftedNow = now.minusSeconds(offsetSec);
ZonedDateTime alignedStart = getAlignedBoundary(type, multiplier, false, shiftedNow); ZonedDateTime alignedStart = getAlignedBoundary(shiftedNow, false);
ZonedDateTime actualStart = alignedStart.plus(Duration.ofMillis(offsetMillis)); ZonedDateTime actualStart = alignedStart.plusSeconds(offsetSec);
return actualStart.toInstant().toEpochMilli(); return actualStart.toInstant().toEpochMilli();
} }
@Override @Override
public long getCurrentIntervalEndTs() { public long getCurrentIntervalEndTs() {
return getCurrentIntervalEndTs(getType(), 1);
}
protected long getCurrentIntervalEndTs(AggIntervalType type, int multiplier) {
ZoneId zoneId = ZoneId.of(tz); ZoneId zoneId = ZoneId.of(tz);
ZonedDateTime now = ZonedDateTime.now(zoneId); ZonedDateTime now = ZonedDateTime.now(zoneId);
ZonedDateTime shiftedNow = now.minus(Duration.ofMillis(offsetMillis)); ZonedDateTime shiftedNow = now.minusSeconds(offsetSec);
ZonedDateTime alignedEnd = getAlignedBoundary(type, multiplier, true, shiftedNow); ZonedDateTime alignedEnd = getAlignedBoundary(shiftedNow, true);
ZonedDateTime actualEnd = alignedEnd.plus(Duration.ofMillis(offsetMillis)); ZonedDateTime actualEnd = alignedEnd.plusSeconds(offsetSec);
return actualEnd.toInstant().toEpochMilli(); return actualEnd.toInstant().toEpochMilli();
} }
@Override @Override
public long getDelayUntilIntervalEnd() { public long getDelayUntilIntervalEnd() {
return getDelayUntilIntervalEnd(getType(), 1); long currentIntervalEndTs = getCurrentIntervalEndTs();
}
protected long getDelayUntilIntervalEnd(AggIntervalType type, int multiplier) {
long currentIntervalEndTs = getCurrentIntervalEndTs(type, multiplier);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
return currentIntervalEndTs - now; return currentIntervalEndTs - now;
} }
protected ZonedDateTime getAlignedBoundary(AggIntervalType type, int multiplier, boolean next, ZonedDateTime reference) { protected ZonedDateTime getAlignedBoundary(ZonedDateTime reference, boolean next) {
return switch (type) { return switch (getType()) {
case MIN -> alignByMin(reference, multiplier, next); case HOUR -> alignByHours(reference, next);
case HOUR -> alignByHour(reference, multiplier, next); case DAY -> alignByDays(reference, next);
case DAY -> alignByDay(reference, multiplier, next); case WEEK -> alignByWeeks(reference, DayOfWeek.MONDAY, next);
case WEEK -> alignByWeek(reference, multiplier, DayOfWeek.MONDAY, next); case WEEK_SUN_SAT -> alignByWeeks(reference, DayOfWeek.SUNDAY, next);
case WEEK_SUN_SAT -> alignByWeek(reference, multiplier, DayOfWeek.SUNDAY, next); case MONTH -> alignByMonths(reference, next);
case MONTH -> alignByMonth(reference, multiplier, next); case YEAR -> alignByYears(reference, next);
case YEAR -> alignByYear(reference, multiplier, next); default -> throw new IllegalArgumentException("Unsupported interval type: " + getType());
default -> throw new IllegalArgumentException("Unsupported type: " + type);
}; };
} }
private ZonedDateTime alignByMin(ZonedDateTime now, int multiplier, boolean next) { private ZonedDateTime alignByHours(ZonedDateTime now, boolean next) {
ZonedDateTime startOfHour = now.truncatedTo(ChronoUnit.HOURS); ZonedDateTime base = now.truncatedTo(ChronoUnit.HOURS);
long minsSinceHour = Duration.between(startOfHour, now).toMinutes(); return next ? base.plusHours(1) : base;
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 alignByDay(ZonedDateTime now, int multiplier, boolean next) { private ZonedDateTime alignByDays(ZonedDateTime now, boolean next) {
long daysSinceEpoch = now.toLocalDate().toEpochDay(); ZonedDateTime base = now.truncatedTo(ChronoUnit.DAYS);
long aligned = (daysSinceEpoch / multiplier) * multiplier; return next ? base.plusDays(1) : base;
if (next) aligned += multiplier;
long diff = aligned - daysSinceEpoch;
return now.truncatedTo(ChronoUnit.DAYS).plusDays(diff);
} }
private ZonedDateTime alignByWeek(ZonedDateTime now, int multiplier, DayOfWeek startOfWeekDay, boolean next) { private ZonedDateTime alignByWeeks(ZonedDateTime now, DayOfWeek startOfWeek, boolean next) {
ZonedDateTime startOfWeek = now.with(TemporalAdjusters.previousOrSame(startOfWeekDay)) ZonedDateTime startOfWeekDate = now.with(TemporalAdjusters.previousOrSame(startOfWeek))
.truncatedTo(ChronoUnit.DAYS); .truncatedTo(ChronoUnit.DAYS);
long weeksSinceEpoch = ChronoUnit.WEEKS.between( return next ? startOfWeekDate.plusWeeks(1) : startOfWeekDate;
ZonedDateTime.ofInstant(Instant.EPOCH, now.getZone()), startOfWeek);
long aligned = (weeksSinceEpoch / multiplier) * multiplier;
if (next) aligned += multiplier;
return startOfWeek.plusWeeks(aligned - weeksSinceEpoch);
} }
private ZonedDateTime alignByMonth(ZonedDateTime now, int multiplier, boolean next) { private ZonedDateTime alignByMonths(ZonedDateTime now, boolean next) {
ZonedDateTime startOfMonth = now.withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS); ZonedDateTime base = now.withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS);
long monthsSinceEpoch = now.getYear() * 12L + now.getMonthValue() - 1; return next ? base.plusMonths(1) : base;
long aligned = (monthsSinceEpoch / multiplier) * multiplier;
if (next) aligned += multiplier;
return startOfMonth.plusMonths(aligned - monthsSinceEpoch);
} }
private ZonedDateTime alignByYear(ZonedDateTime now, int multiplier, boolean next) { private ZonedDateTime alignByYears(ZonedDateTime now, boolean next) {
int year = now.getYear(); ZonedDateTime base = ZonedDateTime.of(
int aligned = (year / multiplier) * multiplier; LocalDate.of(now.getYear(), 1, 1),
if (next) aligned += multiplier; LocalTime.MIDNIGHT,
return ZonedDateTime.of(LocalDate.of(aligned, 1, 1), LocalTime.MIDNIGHT, now.getZone()); now.getZone());
return next ? base.plusYears(1) : base;
} }
} }

32
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.EqualsAndHashCode;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@Data @Data
@NoArgsConstructor @NoArgsConstructor
public class CustomInterval extends BaseAggInterval { public class CustomInterval extends BaseAggInterval {
private int multiplier; // number of base units (e.g. 2 hours, 5 days) private Long durationSec;
private AggIntervalType internalIntervalType;
public CustomInterval(int multiplier, AggIntervalType internalIntervalType, long offsetMillis, String tz) { public CustomInterval(Long durationSec, Long offsetMillis, String tz) {
this.tz = tz; this.tz = tz;
this.offsetMillis = offsetMillis; this.offsetSec = offsetMillis;
this.multiplier = multiplier; this.durationSec = durationSec;
this.internalIntervalType = internalIntervalType;
} }
@Override @Override
@ -41,22 +44,31 @@ public class CustomInterval extends BaseAggInterval {
@Override @Override
public long getIntervalDurationMillis() { public long getIntervalDurationMillis() {
return getIntervalDurationMillis(internalIntervalType, multiplier); return Duration.ofSeconds(durationSec).toMillis();
} }
@Override @Override
public long getCurrentIntervalStartTs() { 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 @Override
public long getCurrentIntervalEndTs() { public long getCurrentIntervalEndTs() {
return super.getCurrentIntervalEndTs(internalIntervalType, multiplier); return getCurrentIntervalStartTs() + getIntervalDurationMillis();
} }
@Override @Override
public long getDelayUntilIntervalEnd() { public long getDelayUntilIntervalEnd() {
return super.getDelayUntilIntervalEnd(internalIntervalType, multiplier); return getCurrentIntervalEndTs() - System.currentTimeMillis();
} }
} }

30
common/data/src/main/java/org/thingsboard/server/common/data/cf/configuration/aggregation/single/interval/MinInterval.java

@ -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;
}
}
Loading…
Cancel
Save