use date picker in visualization page
This commit is contained in:
@@ -25,78 +25,98 @@ public class DateTimeRangeParser {
|
||||
|
||||
private static OffsetDateTime parseInternal(final OffsetDateTime offsetTime, final String timeDefinition) {
|
||||
|
||||
final Pattern regex = Pattern.compile("(?<beginEnd>[BE]?)(?<amount>\\-?[0-9]*)(?<unit>[mHDWMY])");
|
||||
final Pattern regex = Pattern.compile("(?<beginEnd>[BE])(?<amountUnit>(\\-?[0-9]*[mHDWMY])+)",
|
||||
Pattern.MULTILINE);
|
||||
|
||||
final Matcher matcher = regex.matcher(timeDefinition);
|
||||
|
||||
if (matcher.matches()) {
|
||||
|
||||
final String beginEnd = matcher.group("beginEnd");
|
||||
final boolean begin = "B".equals(beginEnd);
|
||||
final String amountString = matcher.group("amount");
|
||||
final int amount = amountString.equals("") ? 0 : Integer.parseInt(amountString);
|
||||
final String unitString = matcher.group("unit");
|
||||
|
||||
switch (unitString) {
|
||||
case "m": {
|
||||
final ChronoUnit unit = ChronoUnit.MINUTES;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
OffsetDateTime result = offsetTime;
|
||||
|
||||
final String amountUnitString = matcher.group("amountUnit");
|
||||
final Pattern regexAmountUnit = Pattern.compile("(?<amount>\\-?[0-9]*)(?<unit>[mHDWMY])");
|
||||
final Matcher m = regexAmountUnit.matcher(amountUnitString);
|
||||
while (m.find()) {
|
||||
final String amountString = m.group("amount");
|
||||
final String unitString = m.group("unit");
|
||||
final int amount = amountString.equals("") ? 0 : Integer.parseInt(amountString);
|
||||
|
||||
switch (unitString) {
|
||||
case "m": {
|
||||
final ChronoUnit unit = ChronoUnit.MINUTES;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "H": {
|
||||
final ChronoUnit unit = ChronoUnit.HOURS;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "D": {
|
||||
final ChronoUnit unit = ChronoUnit.DAYS;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
result = result.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "W": {
|
||||
final DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY;
|
||||
final DayOfWeek lastDayOfWeek = DayOfWeek
|
||||
.of(((firstDayOfWeek.getValue() - 1 + 6) % DayOfWeek.values().length) + 1); // weird
|
||||
// computation,
|
||||
// because
|
||||
// DayOfWeek
|
||||
// goes from 1
|
||||
// to 7
|
||||
final ChronoUnit unit = ChronoUnit.WEEKS;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).with(TemporalAdjusters.previousOrSame(firstDayOfWeek))
|
||||
.truncatedTo(ChronoUnit.DAYS);
|
||||
} else {
|
||||
result = result.plus(amount, unit).with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
|
||||
.plus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "M": {
|
||||
final ChronoUnit unit = ChronoUnit.MONTHS;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
|
||||
} else {
|
||||
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1)
|
||||
.plus(1, ChronoUnit.MONTHS).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "Y": {
|
||||
final ChronoUnit unit = ChronoUnit.YEARS;
|
||||
if (begin) {
|
||||
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
|
||||
} else {
|
||||
result = result.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1)
|
||||
.plus(1, ChronoUnit.YEARS).minusSeconds(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + unitString);
|
||||
}
|
||||
}
|
||||
case "H": {
|
||||
final ChronoUnit unit = ChronoUnit.HOURS;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
}
|
||||
}
|
||||
case "D": {
|
||||
final ChronoUnit unit = ChronoUnit.DAYS;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(unit);
|
||||
} else {
|
||||
return offsetTime.plus(amount + 1, unit).truncatedTo(unit).minusSeconds(1);
|
||||
}
|
||||
}
|
||||
case "W": {
|
||||
final DayOfWeek firstDayOfWeek = DayOfWeek.MONDAY;
|
||||
final DayOfWeek lastDayOfWeek = DayOfWeek
|
||||
.of(((firstDayOfWeek.getValue() - 1 + 6) % DayOfWeek.values().length) + 1); // weird
|
||||
// computation,
|
||||
// because DayOfWeek
|
||||
// goes from 1 to 7
|
||||
final ChronoUnit unit = ChronoUnit.WEEKS;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).with(TemporalAdjusters.previousOrSame(firstDayOfWeek))
|
||||
.truncatedTo(ChronoUnit.DAYS);
|
||||
} else {
|
||||
return offsetTime.plus(amount, unit).with(TemporalAdjusters.nextOrSame(lastDayOfWeek))
|
||||
.plus(1, ChronoUnit.DAYS).truncatedTo(ChronoUnit.DAYS).minusSeconds(1);
|
||||
}
|
||||
}
|
||||
case "M": {
|
||||
final ChronoUnit unit = ChronoUnit.MONTHS;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
|
||||
} else {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1)
|
||||
.plus(1, ChronoUnit.MONTHS).minusSeconds(1);
|
||||
}
|
||||
}
|
||||
case "Y": {
|
||||
final ChronoUnit unit = ChronoUnit.YEARS;
|
||||
if (begin) {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
|
||||
} else {
|
||||
return offsetTime.plus(amount, unit).truncatedTo(ChronoUnit.DAYS).withDayOfYear(1)
|
||||
.plus(1, ChronoUnit.YEARS).minusSeconds(1);
|
||||
}
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected value: " + unitString);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("invalid input: " + timeDefinition);
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.lucares.pdb.plot.api;
|
||||
|
||||
public class DateValue {
|
||||
public enum DateType {
|
||||
QUICK, RELATIVE, ABSOLUTE
|
||||
}
|
||||
|
||||
private DateType type;
|
||||
|
||||
private String display;
|
||||
|
||||
private String value;
|
||||
|
||||
public DateType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final DateType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getDisplay() {
|
||||
return display;
|
||||
}
|
||||
|
||||
public void setDisplay(final String display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(final String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import org.lucares.utils.Preconditions;
|
||||
|
||||
public class PlotSettings {
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
public static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private String query;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class PlotSettings {
|
||||
|
||||
private int limit;
|
||||
|
||||
private String dateRangeAsString;
|
||||
private DateValue dateValue;
|
||||
|
||||
private YAxisDefinition y1;
|
||||
private YAxisDefinition y2;
|
||||
@@ -80,30 +80,37 @@ public class PlotSettings {
|
||||
this.limit = limit;
|
||||
}
|
||||
|
||||
public String getDateRange() {
|
||||
return dateRangeAsString;
|
||||
public DateValue getDateRange() {
|
||||
return dateValue;
|
||||
}
|
||||
|
||||
public void setDateRange(final String dateRangeAsString) {
|
||||
this.dateRangeAsString = dateRangeAsString;
|
||||
public void setDateRange(final DateValue dateValue) {
|
||||
this.dateValue = dateValue;
|
||||
}
|
||||
|
||||
public DateTimeRange dateRange() {
|
||||
|
||||
final String[] startEnd = dateRangeAsString.split(Pattern.quote(" - "));
|
||||
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateRangeAsString);
|
||||
switch (this.dateValue.getType()) {
|
||||
case RELATIVE:
|
||||
case QUICK:
|
||||
final DateTimeRange dateTimeRange = DateTimeRangeParser.parse(OffsetDateTime.now(), dateValue.getValue());
|
||||
return dateTimeRange;
|
||||
case ABSOLUTE:
|
||||
final String[] startEnd = dateValue.getValue().split(Pattern.quote(" - "));
|
||||
Preconditions.checkEqual(startEnd.length, 2, "invalid date range: ''{0}''", dateValue);
|
||||
|
||||
final OffsetDateTime startDate = LocalDateTime.parse(startEnd[0], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||
final OffsetDateTime endDate = LocalDateTime.parse(startEnd[1], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||
|
||||
return new DateTimeRange(startDate, endDate);
|
||||
final OffsetDateTime startDate = LocalDateTime.parse(startEnd[0], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||
final OffsetDateTime endDate = LocalDateTime.parse(startEnd[1], DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||
return new DateTimeRange(startDate, endDate);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PlotSettings [query=" + query + ", groupBy=" + groupBy + ", limitBy=" + limitBy + ", limit=" + limit
|
||||
+ ", dateRangeAsString=" + dateRangeAsString + ", y1=" + y1 + " y2=" + y2 + ", aggregates=" + aggregates
|
||||
+ ", dateRangeAsString=" + dateValue + ", y1=" + y1 + " y2=" + y2 + ", aggregates=" + aggregates
|
||||
+ ", renders=" + renders + "]";
|
||||
}
|
||||
|
||||
|
||||
@@ -81,11 +81,10 @@ public class DateTimeRangeParserTest {
|
||||
Arguments.of("2024-03-29 12:00:00", "BY/EY", "2024-01-01 00:00:00", "2024-12-31 23:59:59"),
|
||||
|
||||
// previous year
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1Y/E-1Y", "2023-01-01 00:00:00", "2023-12-31 23:59:59")
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1Y/E-1Y", "2023-01-01 00:00:00", "2023-12-31 23:59:59"),
|
||||
|
||||
//
|
||||
// Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00",
|
||||
// "2024-03-29 12:00:00")
|
||||
//
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00", "2024-03-29 12:00:00")
|
||||
|
||||
);
|
||||
}
|
||||
@@ -104,4 +103,31 @@ public class DateTimeRangeParserTest {
|
||||
Assertions.assertEquals(expectedStart, actualStart, "start");
|
||||
Assertions.assertEquals(expectedEnd, actualEnd, "end");
|
||||
}
|
||||
|
||||
public static Stream<Arguments> providerDatePeriods_multiple() {
|
||||
|
||||
return Stream.of(//
|
||||
|
||||
//
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/Bm", "2024-03-29 10:45:00", "2024-03-29 12:00:00"),
|
||||
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1H-15m/EH15m", "2024-03-29 10:45:00", "2024-03-29 13:14:59")
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("providerDatePeriods_multiple")
|
||||
public void testDatePeriods_multiple(final String now, final String datePeriod, final String expectedStart,
|
||||
final String expectedEnd) throws Exception {
|
||||
final OffsetDateTime offsetTime = LocalDateTime.parse(now, PlotSettings.DATE_FORMAT).atOffset(ZoneOffset.UTC);
|
||||
|
||||
final DateTimeRange actual = DateTimeRangeParser.parse(offsetTime, datePeriod);
|
||||
|
||||
final String actualStart = PlotSettings.DATE_FORMAT.format(actual.getStart());
|
||||
final String actualEnd = PlotSettings.DATE_FORMAT.format(actual.getEnd());
|
||||
System.out.println("at " + now + " " + datePeriod + " -> " + actualStart + " - " + actualEnd);
|
||||
Assertions.assertEquals(expectedStart, actualStart, "start");
|
||||
Assertions.assertEquals(expectedEnd, actualEnd, "end");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user