Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions core/src/main/java/org/opensearch/sql/utils/DateTimeUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class DateTimeUtils {
* @return Rounded date/time value in utc millis
*/
public static long roundFloor(long utcMillis, long unitMillis) {
return utcMillis - utcMillis % unitMillis;
long res = utcMillis - utcMillis % unitMillis;
return (utcMillis < 0 && res != utcMillis) ? res - unitMillis : res;
}

/**
Expand Down Expand Up @@ -65,7 +66,9 @@ public static long roundMonth(long utcMillis, int interval) {
(zonedDateTime.getYear() - initDateTime.getYear()) * 12L
+ zonedDateTime.getMonthValue()
- initDateTime.getMonthValue();
long monthToAdd = (monthDiff / interval - 1) * interval;
long multiplier = monthDiff / interval - 1;
if (monthDiff < 0 && monthDiff % interval != 0) --multiplier;
long monthToAdd = multiplier * interval;
return initDateTime.plusMonths(monthToAdd).toInstant().toEpochMilli();
}

Expand All @@ -84,7 +87,9 @@ public static long roundQuarter(long utcMillis, int interval) {
((zonedDateTime.getYear() - initDateTime.getYear()) * 12L
+ zonedDateTime.getMonthValue()
- initDateTime.getMonthValue());
long monthToAdd = (monthDiff / (interval * 3L) - 1) * interval * 3;
long multiplier = monthDiff / (interval * 3L) - 1;
if (monthDiff < 0 && monthDiff % (interval * 3L) != 0) --multiplier;
long monthToAdd = multiplier * interval * 3;
return initDateTime.plusMonths(monthToAdd).toInstant().toEpochMilli();
}

Expand All @@ -99,7 +104,9 @@ public static long roundYear(long utcMillis, int interval) {
ZonedDateTime initDateTime = ZonedDateTime.of(1970, 1, 1, 0, 0, 0, 0, UTC_ZONE_ID);
ZonedDateTime zonedDateTime = Instant.ofEpochMilli(utcMillis).atZone(UTC_ZONE_ID);
int yearDiff = zonedDateTime.getYear() - initDateTime.getYear();
int yearToAdd = (yearDiff / interval) * interval;
int multiplier = yearDiff / interval;
if (yearDiff < 0 && yearDiff % interval != 0) --multiplier;
int yearToAdd = multiplier * interval;
return initDateTime.plusYears(yearToAdd).toInstant().toEpochMilli();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.opensearch.sql.planner.physical.collector.Rounding.DateTimeUnit;

public class DateTimeUtilsTest {
@Test
Expand Down Expand Up @@ -105,4 +106,76 @@ void testRelativeZonedDateTimeWithWrongInput() {
IllegalArgumentException.class, () -> getRelativeZonedDateTime("1d+1y", zonedDateTime));
assertEquals(e.getMessage(), "Unexpected character '1' at position 0 in input: 1d+1y");
}

@Test
void testRoundOnTimestampBeforeEpoch() {
long actual =
LocalDateTime.parse("1961-05-12T23:40:05")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli();
long rounded = DateTimeUnit.MINUTE.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-05-12T23:40:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.HOUR.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-05-12T23:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.DAY.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-05-12T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.DAY.round(actual, 3);
assertEquals(
LocalDateTime.parse("1961-05-12T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.WEEK.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-05-08T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.MONTH.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-05-01T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.QUARTER.round(actual, 1);
assertEquals(
LocalDateTime.parse("1961-04-01T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());

rounded = DateTimeUnit.YEAR.round(actual, 2);
assertEquals(
LocalDateTime.parse("1960-01-01T00:00:00")
.atZone(ZoneOffset.UTC)
.toInstant()
.toEpochMilli(),
Instant.ofEpochMilli(rounded).toEpochMilli());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -502,13 +502,7 @@ public void testCountBySpanForCustomFormats() throws IOException {
actual,
schema("timestamp_span", "timestamp"),
schema("count(custom_no_delimiter_ts)", "bigint"));
// TODO: Span has different behavior between pushdown and non-pushdown for timestamp before
// 1971. V2 engine will have the same issue.
// https://github.com/opensearch-project/sql/issues/3827
verifyDataRows(
actual,
rows(1, isPushdownEnabled() ? "1961-04-12 09:00:00" : "1961-04-12 10:00:00"),
rows(1, "1984-10-20 15:00:00"));
verifyDataRows(actual, rows(1, "1961-04-12 09:00:00"), rows(1, "1984-10-20 15:00:00"));

actual =
executeQuery(
Expand Down
Loading