Skip to content

Commit 21d9a65

Browse files
Chong Gaores-life
authored andcommitted
Add direct ORC from-UTC conversion tests
Signed-off-by: Chong Gao <chongg@nvidia.com>
1 parent cd58bea commit 21d9a65

1 file changed

Lines changed: 124 additions & 0 deletions

File tree

src/test/java/com/nvidia/spark/rapids/jni/GpuTimeZoneDBTest.java

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.time.ZoneOffset;
3232
import java.time.zone.ZoneOffsetTransition;
3333
import java.time.zone.ZoneOffsetTransitionRule;
34+
import java.util.ArrayList;
3435
import java.util.Arrays;
3536
import java.util.List;
3637
import java.util.Random;
@@ -127,6 +128,65 @@ private static ColumnVector convertOrcTimezonesOnCPU(
127128
return ColumnVector.timestampMicroSecondsFromLongs(results);
128129
}
129130

131+
private static ColumnVector convertOrcFromUtcOnCPU(
132+
Long[] microseconds,
133+
String readerTzId) {
134+
Long[] results = new Long[microseconds.length];
135+
TimeZone readerTz = getTimeZoneForOrc(readerTzId);
136+
for (int i = 0; i < microseconds.length; ++i) {
137+
Long valueUs = microseconds[i];
138+
if (valueUs != null) {
139+
long valueMillis = Math.floorDiv(valueUs, microsPerMillis);
140+
int offsetMillis = readerTz.getOffset(valueMillis - readerTz.getRawOffset());
141+
results[i] = (valueMillis - offsetMillis) * microsPerMillis
142+
+ Math.floorMod(valueUs, microsPerMillis);
143+
}
144+
}
145+
return ColumnVector.timestampMicroSecondsFromBoxedLongs(results);
146+
}
147+
148+
private static Long[] getOrcFromUtcBoundaryMicros(String readerTzId) {
149+
List<Long> values = new ArrayList<>(Arrays.asList(
150+
null,
151+
Long.MIN_VALUE,
152+
Long.MIN_VALUE + 1,
153+
-3_649_379_812_521_628L,
154+
-2_957_649_381_472_612L,
155+
-1_501L,
156+
-1_001L,
157+
-999L,
158+
-1L,
159+
0L,
160+
1L,
161+
999L,
162+
1_001L,
163+
514_952_012L,
164+
Long.MAX_VALUE - 1,
165+
Long.MAX_VALUE));
166+
167+
OrcTimezoneInfo readerInfo = OrcTimezoneInfo.get(readerTzId);
168+
if (readerInfo.transitions != null) {
169+
for (long transitionMillis : readerInfo.transitions) {
170+
long localTransitionUs =
171+
TimeUnit.MILLISECONDS.toMicros(transitionMillis + readerInfo.rawOffset);
172+
values.add(localTransitionUs - 1);
173+
values.add(localTransitionUs);
174+
values.add(localTransitionUs + 1);
175+
}
176+
}
177+
178+
for (ZoneOffsetTransitionRule rule :
179+
GpuTimeZoneDB.getZoneId(readerTzId).getRules().getTransitionRules()) {
180+
long transitionMillis = rule.createTransition(2099).getInstant().toEpochMilli();
181+
long localTransitionUs =
182+
TimeUnit.MILLISECONDS.toMicros(transitionMillis + readerInfo.rawOffset);
183+
values.add(localTransitionUs - 1);
184+
values.add(localTransitionUs);
185+
values.add(localTransitionUs + 1);
186+
}
187+
return values.toArray(new Long[0]);
188+
}
189+
130190
@Test
131191
void testIsSupportedTimeZone() {
132192
// Named zones with ZoneRules.
@@ -214,6 +274,70 @@ void testConvertOrcTimezonesFixedOffsetIds() {
214274
}
215275
}
216276

277+
@Test
278+
void testConvertOrcFromUtcAllTimezones() {
279+
GpuTimeZoneDB.cacheDatabase();
280+
GpuTimeZoneDB.verifyDatabaseCached();
281+
282+
List<String> timezones = Arrays.asList(
283+
"UTC",
284+
"America/New_York",
285+
"America/Los_Angeles",
286+
"Europe/Paris",
287+
"Asia/Shanghai",
288+
"Australia/Sydney",
289+
"US/Pacific",
290+
"PST",
291+
"EST",
292+
"+05:30");
293+
294+
for (String readerTzId : timezones) {
295+
Long[] values = getOrcFromUtcBoundaryMicros(readerTzId);
296+
Long[] padded = new Long[values.length + 2];
297+
padded[0] = 123L;
298+
System.arraycopy(values, 0, padded, 1, values.length);
299+
padded[padded.length - 1] = 456L;
300+
301+
try (ColumnVector full = ColumnVector.timestampMicroSecondsFromBoxedLongs(padded);
302+
ColumnVector input = full.subVector(1, values.length + 1);
303+
ColumnVector expected = convertOrcFromUtcOnCPU(values, readerTzId);
304+
GpuTimeZoneDB.OrcTimezoneContext context =
305+
GpuTimeZoneDB.buildOrcTimezoneContext("UTC", readerTzId);
306+
ColumnVector fromContext = GpuTimeZoneDB.convertOrcFromUtc(input, context);
307+
ColumnVector fromTimezone = GpuTimeZoneDB.convertOrcFromUtc(input, readerTzId)) {
308+
assertColumnsAreEqual(expected, fromContext);
309+
assertColumnsAreEqual(expected, fromTimezone);
310+
}
311+
}
312+
313+
try (ColumnVector empty =
314+
ColumnVector.timestampMicroSecondsFromBoxedLongs(new Long[] {});
315+
ColumnVector actual = GpuTimeZoneDB.convertOrcFromUtc(empty, "UTC")) {
316+
assertColumnsAreEqual(empty, actual);
317+
}
318+
}
319+
320+
@Test
321+
void testReaderFirstTransitionUs() {
322+
String transitionTzId = "America/Los_Angeles";
323+
OrcTimezoneInfo transitionInfo = OrcTimezoneInfo.get(transitionTzId);
324+
try (GpuTimeZoneDB.OrcTimezoneContext context =
325+
GpuTimeZoneDB.buildOrcTimezoneContext("UTC", transitionTzId)) {
326+
assertEquals(TimeUnit.MILLISECONDS.toMicros(transitionInfo.transitions[0]),
327+
context.getReaderFirstTransitionUs());
328+
}
329+
330+
try (GpuTimeZoneDB.OrcTimezoneContext context =
331+
GpuTimeZoneDB.buildOrcTimezoneContext("UTC", "+05:30")) {
332+
assertEquals(Long.MIN_VALUE, context.getReaderFirstTransitionUs());
333+
}
334+
335+
GpuTimeZoneDB.OrcTimezoneContext closed =
336+
GpuTimeZoneDB.buildOrcTimezoneContext("UTC", "UTC");
337+
closed.close();
338+
assertThrows(IllegalStateException.class, closed::getReaderFirstTransitionUs);
339+
}
340+
217341
@Test
218342
void testConvertOrcTimezones() {
219343
GpuTimeZoneDB.cacheDatabase();

0 commit comments

Comments
 (0)