add date parser for relative time notation
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
package org.lucares.pdb.plot.api;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.lucares.pdb.api.DateTimeRange;
|
||||
|
||||
public class DateTimeRangeParser {
|
||||
|
||||
public static DateTimeRange parse(final OffsetDateTime offsetTime, final String datePeriod) {
|
||||
|
||||
final String[] startEnd = datePeriod.split(Pattern.quote("/"));
|
||||
final String start = startEnd[0];
|
||||
final String end = startEnd[1];
|
||||
|
||||
final OffsetDateTime startTime = parseInternal(offsetTime, start);
|
||||
final OffsetDateTime endTime = parseInternal(offsetTime, end);
|
||||
|
||||
return new DateTimeRange(startTime, endTime);
|
||||
}
|
||||
|
||||
private static OffsetDateTime parseInternal(final OffsetDateTime offsetTime, final String timeDefinition) {
|
||||
|
||||
final Pattern regex = Pattern.compile("(?<beginEnd>[BE]?)(?<amount>\\-?[0-9]*)(?<unit>[mHDWMY])");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("invalid input: " + timeDefinition);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package org.lucares.pdb.plot.api;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.lucares.pdb.api.DateTimeRange;
|
||||
|
||||
public class DateTimeRangeParserTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
}
|
||||
|
||||
public static Stream<Arguments> providerDatePeriods() {
|
||||
|
||||
return Stream.of(//
|
||||
|
||||
// last 15 minutes
|
||||
Arguments.of("2000-01-02 12:59:59", "B-14m/Em", "2000-01-02 12:45:00", "2000-01-02 12:59:59"),
|
||||
|
||||
// this hour
|
||||
Arguments.of("2000-01-02 12:00:00", "BH/EH", "2000-01-02 12:00:00", "2000-01-02 12:59:59"),
|
||||
Arguments.of("2000-01-02 12:59:59", "BH/EH", "2000-01-02 12:00:00", "2000-01-02 12:59:59"),
|
||||
|
||||
// previous hour
|
||||
Arguments.of("2000-01-02 12:00:00", "B-1H/E-1H", "2000-01-02 11:00:00", "2000-01-02 11:59:59"),
|
||||
Arguments.of("2000-01-02 12:59:58", "B-1H/E-1H", "2000-01-02 11:00:00", "2000-01-02 11:59:59"),
|
||||
Arguments.of("2000-01-02 12:59:59", "B-1H/E-1H", "2000-01-02 11:00:00", "2000-01-02 11:59:59"),
|
||||
|
||||
// today
|
||||
Arguments.of("2000-01-02 12:00:00", "BD/ED", "2000-01-02 00:00:00", "2000-01-02 23:59:59"),
|
||||
Arguments.of("2000-01-02 00:00:00", "BD/ED", "2000-01-02 00:00:00", "2000-01-02 23:59:59"),
|
||||
Arguments.of("2000-01-02 23:59:59", "BD/ED", "2000-01-02 00:00:00", "2000-01-02 23:59:59"),
|
||||
Arguments.of("2000-01-02 12:00:00", "B0D/E0D", "2000-01-02 00:00:00", "2000-01-02 23:59:59"),
|
||||
|
||||
// tomorrow
|
||||
Arguments.of("2000-01-02 12:00:00", "B1D/E1D", "2000-01-03 00:00:00", "2000-01-03 23:59:59"),
|
||||
|
||||
// yesterday
|
||||
Arguments.of("2000-01-02 12:00:00", "B-1D/E-1D", "2000-01-01 00:00:00", "2000-01-01 23:59:59"),
|
||||
|
||||
// this week
|
||||
Arguments.of("2024-04-22 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-23 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-24 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-25 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-26 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-27 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
Arguments.of("2024-04-28 12:00:00", "BW/EW", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
|
||||
// previous week
|
||||
Arguments.of("2024-04-29 12:00:00", "B-1W/E-1W", "2024-04-22 00:00:00", "2024-04-28 23:59:59"),
|
||||
|
||||
// last 4 week (including this one
|
||||
Arguments.of("2024-04-28 12:00:00", "B-3W/EW", "2024-04-01 00:00:00", "2024-04-28 23:59:59"),
|
||||
|
||||
// this month
|
||||
Arguments.of("2024-04-29 12:00:00", "BM/EM", "2024-04-01 00:00:00", "2024-04-30 23:59:59"),
|
||||
|
||||
// previous month (in a leap year)
|
||||
Arguments.of("2023-03-29 12:00:00", "B-1M/E-1M", "2023-02-01 00:00:00", "2023-02-28 23:59:59"),
|
||||
|
||||
// previous month (in a leap year)
|
||||
Arguments.of("2024-03-29 12:00:00", "B-1M/E-1M", "2024-02-01 00:00:00", "2024-02-29 23:59:59"),
|
||||
|
||||
// last 3 months
|
||||
Arguments.of("2024-03-29 12:00:00", "B-2M/EM", "2024-01-01 00:00:00", "2024-03-31 23:59:59"),
|
||||
|
||||
// previous 3 months (in a leap year)
|
||||
Arguments.of("2024-03-29 12:00:00", "B-3M/E-1M", "2023-12-01 00:00:00", "2024-02-29 23:59:59"),
|
||||
|
||||
// this year
|
||||
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-1H-15m/Bm", "2024-03-29 10:45:00",
|
||||
// "2024-03-29 12:00:00")
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("providerDatePeriods")
|
||||
public void testDatePeriods(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