[SPARK-29723][SQL] Get date and time parts of an interval as java classes
### What changes were proposed in this pull request? I propose 2 new methods for `CalendarInterval`: - `extractAsPeriod()` returns the date part of an interval as an instance of `java.time.Period` - `extractAsDuration()` returns the time part of an interval as an instance of `java.time.Duration` For example: ```scala scala> import org.apache.spark.unsafe.types.CalendarInterval scala> import java.time._ scala> val i = spark.sql("select interval 1 year 3 months 4 days 10 hours 30 seconds").collect()(0).getAs[CalendarInterval](0) scala> LocalDate.of(2019, 11, 1).plus(i.period()) res8: java.time.LocalDate = 2021-02-05 scala> ZonedDateTime.parse("2019-11-01T12:13:14Z").plus(i.extractAsPeriod()).plus(i.extractAsDuration()) res9: java.time.ZonedDateTime = 2021-02-05T22:13:44Z ``` ### Why are the changes needed? Taking into account that `CalendarInterval` has been already partially exposed to users via the collect operation, and probably it will be fully exposed in the future, it could be convenient for users to get the date and time parts of intervals as java classes: - to avoid unnecessary dependency from Spark's classes in user code - to easily use external libraries that accept standard Java classes. ### Does this PR introduce any user-facing change? No ### How was this patch tested? By new test in `CalendarIntervalSuite`. Closes #26368 from MaxGekk/interval-java-period-duration. Authored-by: Maxim Gekk <max.gekk@gmail.com> Signed-off-by: Dongjoon Hyun <dhyun@apple.com>
This commit is contained in:
parent
326b789340
commit
441d4c953e
|
@ -19,6 +19,9 @@ package org.apache.spark.unsafe.types;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Duration;
|
||||
import java.time.Period;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
@ -112,4 +115,19 @@ public final class CalendarInterval implements Serializable {
|
|||
sb.append(' ').append(value).append(' ').append(unit).append('s');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the date part of the interval.
|
||||
* @return an instance of {@code java.time.Period} based on the months and days fields
|
||||
* of the given interval, not null.
|
||||
*/
|
||||
public Period extractAsPeriod() { return Period.of(0, months, days); }
|
||||
|
||||
/**
|
||||
* Extracts the time part of the interval.
|
||||
* @return an instance of {@code java.time.Duration} based on the microseconds field
|
||||
* of the given interval, not null.
|
||||
* @throws ArithmeticException if a numeric overflow occurs
|
||||
*/
|
||||
public Duration extractAsDuration() { return Duration.of(microseconds, ChronoUnit.MICROS); }
|
||||
}
|
||||
|
|
|
@ -19,6 +19,9 @@ package org.apache.spark.unsafe.types;
|
|||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Period;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.apache.spark.unsafe.types.CalendarInterval.*;
|
||||
|
||||
|
@ -94,4 +97,11 @@ public class CalendarIntervalSuite {
|
|||
input2 = new CalendarInterval(75, 150, 200 * MICROS_PER_HOUR);
|
||||
assertEquals(new CalendarInterval(-85, -180, -281 * MICROS_PER_HOUR), input1.subtract(input2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void periodAndDurationTest() {
|
||||
CalendarInterval interval = new CalendarInterval(120, -40, 123456);
|
||||
assertEquals(Period.of(0, 120, -40), interval.extractAsPeriod());
|
||||
assertEquals(Duration.ofNanos(123456000), interval.extractAsDuration());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue