Skip to content

Commit 550b902

Browse files
authored
fix: Correctly support flight Date/Time types in JS (deephaven#6063)
Also removes preview for these types, so they are rendered consistently in the client. Fixes deephaven#6057
1 parent 994d7a5 commit 550b902

File tree

6 files changed

+108
-147
lines changed

6 files changed

+108
-147
lines changed

engine/table/src/main/java/io/deephaven/engine/table/impl/preview/ColumnPreviewManager.java

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import org.jpy.PyListWrapper;
1616

1717
import java.time.Instant;
18+
import java.time.LocalDate;
19+
import java.time.LocalTime;
1820
import java.time.ZonedDateTime;
1921
import java.util.*;
2022
import java.util.function.Function;
@@ -159,6 +161,7 @@ public static boolean isColumnTypeDisplayable(Class<?> type) {
159161
|| io.deephaven.util.type.TypeUtils.isString(type)
160162
|| NumericTypeUtils.isBigNumeric(type)
161163
|| Instant.class == type || ZonedDateTime.class == type
164+
|| LocalDate.class == type || LocalTime.class == type
162165
|| isOnWhiteList(type);
163166
}
164167

web/client-api/src/main/java/io/deephaven/web/client/api/LocalDateWrapper.java

+2-20
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,20 @@
66
import com.google.gwt.i18n.client.NumberFormat;
77
import com.vertispan.tsdefs.annotations.TsInterface;
88
import com.vertispan.tsdefs.annotations.TsName;
9-
import io.deephaven.web.shared.data.LocalDate;
109
import jsinterop.annotations.JsMethod;
1110

12-
import javax.annotation.Nonnull;
13-
1411
/**
1512
* Wrap LocalDate values for use in JS. Provides text formatting for display and access to the underlying value.
1613
*/
1714
@TsInterface
1815
@TsName(namespace = "dh")
1916
public class LocalDateWrapper {
20-
private final static NumberFormat YEAR_FORMAT = NumberFormat.getFormat("0000");
21-
private final static NumberFormat MONTH_DAY_FORMAT = NumberFormat.getFormat("00");
17+
private static final NumberFormat YEAR_FORMAT = NumberFormat.getFormat("0000");
18+
private static final NumberFormat MONTH_DAY_FORMAT = NumberFormat.getFormat("00");
2219

2320
private final int year;
2421
private final int monthValue, dayOfMonth;
2522

26-
public LocalDateWrapper(@Nonnull LocalDate localDate) {
27-
year = localDate.getYear();
28-
monthValue = localDate.getMonthValue();
29-
dayOfMonth = localDate.getDayOfMonth();
30-
}
31-
3223
public LocalDateWrapper(int year, int monthValue, int dayOfMonth) {
3324
this.year = year;
3425
this.monthValue = monthValue;
@@ -55,15 +46,6 @@ public int getDayOfMonth() {
5546
return dayOfMonth;
5647
}
5748

58-
@Deprecated
59-
public LocalDate getWrapped() {
60-
LocalDate localDate = new LocalDate();
61-
localDate.setYear(year);
62-
localDate.setMonthValue((byte) monthValue);
63-
localDate.setDayOfMonth((byte) dayOfMonth);
64-
return localDate;
65-
}
66-
6749
@JsMethod
6850
@Override
6951
public String toString() {

web/client-api/src/main/java/io/deephaven/web/client/api/LocalTimeWrapper.java

+54-19
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,63 @@
66
import com.google.gwt.i18n.client.NumberFormat;
77
import com.vertispan.tsdefs.annotations.TsInterface;
88
import com.vertispan.tsdefs.annotations.TsName;
9-
import io.deephaven.web.shared.data.LocalTime;
9+
import io.deephaven.util.QueryConstants;
1010
import jsinterop.annotations.JsMethod;
1111

12-
import javax.annotation.Nonnull;
12+
import java.util.function.IntFunction;
13+
import java.util.function.LongFunction;
1314

1415
/**
1516
* Wrap LocalTime values for use in JS. Provides text formatting for display and access to the underlying value.
1617
*/
1718
@TsInterface
1819
@TsName(namespace = "dh")
1920
public class LocalTimeWrapper {
20-
private final static NumberFormat TWO_DIGIT_FORMAT = NumberFormat.getFormat("00");
21-
private final static NumberFormat NANOS_FORMAT = NumberFormat.getFormat("000000000");
21+
private static final NumberFormat TWO_DIGIT_FORMAT = NumberFormat.getFormat("00");
22+
private static final NumberFormat NANOS_FORMAT = NumberFormat.getFormat("000000000");
2223

23-
private final LocalTime localTime;
24+
private final int hour;
25+
private final int minute;
26+
private final int second;
27+
private final int nano;
2428

25-
public LocalTimeWrapper(@Nonnull LocalTime localTime) {
26-
this.localTime = localTime;
29+
public static IntFunction<LocalTimeWrapper> intCreator(int unitPerMicro) {
30+
int nanoPerUnit = 1_000_000_000 / unitPerMicro;
31+
return val -> {
32+
if (val == QueryConstants.NULL_INT) {
33+
return null;
34+
}
35+
int nano = (val % unitPerMicro) * nanoPerUnit;
36+
int secVal = val / unitPerMicro;
37+
int second = (secVal % 60);
38+
secVal /= 60;
39+
int minute = (secVal % 60);
40+
int hour = (secVal / 60);
41+
return new LocalTimeWrapper(hour, minute, second, nano);
42+
};
43+
}
44+
45+
public static LongFunction<LocalTimeWrapper> longCreator(int unitPerMicro) {
46+
int nanoPerUnit = 1_000_000_000 / unitPerMicro;
47+
return val -> {
48+
if (val == QueryConstants.NULL_LONG) {
49+
return null;
50+
}
51+
int nano = (int) (val % unitPerMicro) * nanoPerUnit;
52+
int secVal = (int) (val / unitPerMicro);
53+
byte second = (byte) (secVal % 60);
54+
secVal /= 60;
55+
byte minute = (byte) (secVal % 60);
56+
byte hour = (byte) (secVal / 60);
57+
return new LocalTimeWrapper(hour, minute, second, nano);
58+
};
59+
}
60+
61+
public LocalTimeWrapper(int hour, int minute, int second, int nano) {
62+
this.hour = hour;
63+
this.minute = minute;
64+
this.second = second;
65+
this.nano = nano;
2766
}
2867

2968
@JsMethod
@@ -33,34 +72,30 @@ public String valueOf() {
3372

3473
@JsMethod
3574
public int getHour() {
36-
return localTime.getHour();
75+
return hour;
3776
}
3877

3978
@JsMethod
4079
public int getMinute() {
41-
return localTime.getMinute();
80+
return minute;
4281
}
4382

4483
@JsMethod
4584
public int getSecond() {
46-
return localTime.getSecond();
85+
return second;
4786
}
4887

4988
@JsMethod
5089
public int getNano() {
51-
return localTime.getNano();
52-
}
53-
54-
public LocalTime getWrapped() {
55-
return localTime;
90+
return nano;
5691
}
5792

5893
@JsMethod
5994
@Override
6095
public String toString() {
61-
return TWO_DIGIT_FORMAT.format(localTime.getHour())
62-
+ ":" + TWO_DIGIT_FORMAT.format(localTime.getMinute())
63-
+ ":" + TWO_DIGIT_FORMAT.format(localTime.getSecond())
64-
+ "." + NANOS_FORMAT.format(localTime.getNano());
96+
return TWO_DIGIT_FORMAT.format(hour)
97+
+ ":" + TWO_DIGIT_FORMAT.format(minute)
98+
+ ":" + TWO_DIGIT_FORMAT.format(second)
99+
+ "." + NANOS_FORMAT.format(nano);
65100
}
66101
}

web/client-api/src/main/java/io/deephaven/web/client/api/barrage/WebChunkReaderFactory.java

+49-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//
44
package io.deephaven.web.client.api.barrage;
55

6+
import elemental2.core.JsDate;
67
import io.deephaven.base.verify.Assert;
78
import io.deephaven.chunk.WritableByteChunk;
89
import io.deephaven.chunk.WritableChunk;
@@ -23,10 +24,13 @@
2324
import io.deephaven.extensions.barrage.chunk.VarListChunkReader;
2425
import io.deephaven.extensions.barrage.util.StreamReaderOptions;
2526
import io.deephaven.util.BooleanUtils;
27+
import io.deephaven.util.QueryConstants;
2628
import io.deephaven.util.datastructures.LongSizedDataStructure;
2729
import io.deephaven.web.client.api.BigDecimalWrapper;
2830
import io.deephaven.web.client.api.BigIntegerWrapper;
2931
import io.deephaven.web.client.api.DateWrapper;
32+
import io.deephaven.web.client.api.LocalDateWrapper;
33+
import io.deephaven.web.client.api.LocalTimeWrapper;
3034
import io.deephaven.web.client.api.LongWrapper;
3135
import org.apache.arrow.flatbuf.Date;
3236
import org.apache.arrow.flatbuf.DateUnit;
@@ -170,7 +174,23 @@ public ChunkReader getReader(StreamReaderOptions options, int factor, ChunkReade
170174
typeInfo.arrowField().type(t);
171175
switch (t.unit()) {
172176
case DateUnit.MILLISECOND:
173-
return new LongChunkReader(options).transform(millis -> DateWrapper.of(millis * 1000 * 1000));
177+
return new LongChunkReader(options).transform(millis -> {
178+
if (millis == QueryConstants.NULL_LONG) {
179+
return null;
180+
}
181+
JsDate jsDate = new JsDate((double) (long) millis);
182+
return new LocalDateWrapper(jsDate.getUTCFullYear(), 1 + jsDate.getUTCMonth(),
183+
jsDate.getUTCDate());
184+
});
185+
case DateUnit.DAY:
186+
return new IntChunkReader(options).transform(days -> {
187+
if (days == QueryConstants.NULL_INT) {
188+
return null;
189+
}
190+
JsDate jsDate = new JsDate(((double) (int) days) * 86400000);
191+
return new LocalDateWrapper(jsDate.getUTCFullYear(), 1 + jsDate.getUTCMonth(),
192+
jsDate.getUTCDate());
193+
});
174194
default:
175195
throw new IllegalArgumentException("Unsupported Date unit: " + DateUnit.name(t.unit()));
176196
}
@@ -179,11 +199,36 @@ public ChunkReader getReader(StreamReaderOptions options, int factor, ChunkReade
179199
Time t = new Time();
180200
typeInfo.arrowField().type(t);
181201
switch (t.bitWidth()) {
182-
case TimeUnit.NANOSECOND: {
183-
return new LongChunkReader(options).transform(DateWrapper::of);
202+
case 32: {
203+
switch (t.unit()) {
204+
case TimeUnit.SECOND: {
205+
return new IntChunkReader(options)
206+
.transform(LocalTimeWrapper.intCreator(1)::apply);
207+
}
208+
case TimeUnit.MILLISECOND: {
209+
return new IntChunkReader(options)
210+
.transform(LocalTimeWrapper.intCreator(1_000)::apply);
211+
}
212+
default:
213+
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
214+
}
215+
}
216+
case 64: {
217+
switch (t.unit()) {
218+
case TimeUnit.NANOSECOND: {
219+
return new LongChunkReader(options)
220+
.transform(LocalTimeWrapper.longCreator(1_000_000_000)::apply);
221+
}
222+
case TimeUnit.MICROSECOND: {
223+
return new LongChunkReader(options)
224+
.transform(LocalTimeWrapper.longCreator(1_000_000)::apply);
225+
}
226+
default:
227+
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
228+
}
184229
}
185230
default:
186-
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
231+
throw new IllegalArgumentException("Unsupported Time bitWidth: " + t.bitWidth());
187232
}
188233
}
189234
case Type.Timestamp: {

web/shared-beans/src/main/java/io/deephaven/web/shared/data/LocalDate.java

-47
This file was deleted.

web/shared-beans/src/main/java/io/deephaven/web/shared/data/LocalTime.java

-57
This file was deleted.

0 commit comments

Comments
 (0)