Skip to content

Commit

Permalink
fix: Correctly support flight Date/Time types in JS (#6063)
Browse files Browse the repository at this point in the history
Also removes preview for these types, so they are rendered consistently
in the client.

Fixes #6057
  • Loading branch information
niloc132 authored Sep 13, 2024
1 parent 994d7a5 commit 550b902
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 147 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.jpy.PyListWrapper;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;
Expand Down Expand Up @@ -159,6 +161,7 @@ public static boolean isColumnTypeDisplayable(Class<?> type) {
|| io.deephaven.util.type.TypeUtils.isString(type)
|| NumericTypeUtils.isBigNumeric(type)
|| Instant.class == type || ZonedDateTime.class == type
|| LocalDate.class == type || LocalTime.class == type
|| isOnWhiteList(type);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,20 @@
import com.google.gwt.i18n.client.NumberFormat;
import com.vertispan.tsdefs.annotations.TsInterface;
import com.vertispan.tsdefs.annotations.TsName;
import io.deephaven.web.shared.data.LocalDate;
import jsinterop.annotations.JsMethod;

import javax.annotation.Nonnull;

/**
* Wrap LocalDate values for use in JS. Provides text formatting for display and access to the underlying value.
*/
@TsInterface
@TsName(namespace = "dh")
public class LocalDateWrapper {
private final static NumberFormat YEAR_FORMAT = NumberFormat.getFormat("0000");
private final static NumberFormat MONTH_DAY_FORMAT = NumberFormat.getFormat("00");
private static final NumberFormat YEAR_FORMAT = NumberFormat.getFormat("0000");
private static final NumberFormat MONTH_DAY_FORMAT = NumberFormat.getFormat("00");

private final int year;
private final int monthValue, dayOfMonth;

public LocalDateWrapper(@Nonnull LocalDate localDate) {
year = localDate.getYear();
monthValue = localDate.getMonthValue();
dayOfMonth = localDate.getDayOfMonth();
}

public LocalDateWrapper(int year, int monthValue, int dayOfMonth) {
this.year = year;
this.monthValue = monthValue;
Expand All @@ -55,15 +46,6 @@ public int getDayOfMonth() {
return dayOfMonth;
}

@Deprecated
public LocalDate getWrapped() {
LocalDate localDate = new LocalDate();
localDate.setYear(year);
localDate.setMonthValue((byte) monthValue);
localDate.setDayOfMonth((byte) dayOfMonth);
return localDate;
}

@JsMethod
@Override
public String toString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,63 @@
import com.google.gwt.i18n.client.NumberFormat;
import com.vertispan.tsdefs.annotations.TsInterface;
import com.vertispan.tsdefs.annotations.TsName;
import io.deephaven.web.shared.data.LocalTime;
import io.deephaven.util.QueryConstants;
import jsinterop.annotations.JsMethod;

import javax.annotation.Nonnull;
import java.util.function.IntFunction;
import java.util.function.LongFunction;

/**
* Wrap LocalTime values for use in JS. Provides text formatting for display and access to the underlying value.
*/
@TsInterface
@TsName(namespace = "dh")
public class LocalTimeWrapper {
private final static NumberFormat TWO_DIGIT_FORMAT = NumberFormat.getFormat("00");
private final static NumberFormat NANOS_FORMAT = NumberFormat.getFormat("000000000");
private static final NumberFormat TWO_DIGIT_FORMAT = NumberFormat.getFormat("00");
private static final NumberFormat NANOS_FORMAT = NumberFormat.getFormat("000000000");

private final LocalTime localTime;
private final int hour;
private final int minute;
private final int second;
private final int nano;

public LocalTimeWrapper(@Nonnull LocalTime localTime) {
this.localTime = localTime;
public static IntFunction<LocalTimeWrapper> intCreator(int unitPerMicro) {
int nanoPerUnit = 1_000_000_000 / unitPerMicro;
return val -> {
if (val == QueryConstants.NULL_INT) {
return null;
}
int nano = (val % unitPerMicro) * nanoPerUnit;
int secVal = val / unitPerMicro;
int second = (secVal % 60);
secVal /= 60;
int minute = (secVal % 60);
int hour = (secVal / 60);
return new LocalTimeWrapper(hour, minute, second, nano);
};
}

public static LongFunction<LocalTimeWrapper> longCreator(int unitPerMicro) {
int nanoPerUnit = 1_000_000_000 / unitPerMicro;
return val -> {
if (val == QueryConstants.NULL_LONG) {
return null;
}
int nano = (int) (val % unitPerMicro) * nanoPerUnit;
int secVal = (int) (val / unitPerMicro);
byte second = (byte) (secVal % 60);
secVal /= 60;
byte minute = (byte) (secVal % 60);
byte hour = (byte) (secVal / 60);
return new LocalTimeWrapper(hour, minute, second, nano);
};
}

public LocalTimeWrapper(int hour, int minute, int second, int nano) {
this.hour = hour;
this.minute = minute;
this.second = second;
this.nano = nano;
}

@JsMethod
Expand All @@ -33,34 +72,30 @@ public String valueOf() {

@JsMethod
public int getHour() {
return localTime.getHour();
return hour;
}

@JsMethod
public int getMinute() {
return localTime.getMinute();
return minute;
}

@JsMethod
public int getSecond() {
return localTime.getSecond();
return second;
}

@JsMethod
public int getNano() {
return localTime.getNano();
}

public LocalTime getWrapped() {
return localTime;
return nano;
}

@JsMethod
@Override
public String toString() {
return TWO_DIGIT_FORMAT.format(localTime.getHour())
+ ":" + TWO_DIGIT_FORMAT.format(localTime.getMinute())
+ ":" + TWO_DIGIT_FORMAT.format(localTime.getSecond())
+ "." + NANOS_FORMAT.format(localTime.getNano());
return TWO_DIGIT_FORMAT.format(hour)
+ ":" + TWO_DIGIT_FORMAT.format(minute)
+ ":" + TWO_DIGIT_FORMAT.format(second)
+ "." + NANOS_FORMAT.format(nano);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//
package io.deephaven.web.client.api.barrage;

import elemental2.core.JsDate;
import io.deephaven.base.verify.Assert;
import io.deephaven.chunk.WritableByteChunk;
import io.deephaven.chunk.WritableChunk;
Expand All @@ -23,10 +24,13 @@
import io.deephaven.extensions.barrage.chunk.VarListChunkReader;
import io.deephaven.extensions.barrage.util.StreamReaderOptions;
import io.deephaven.util.BooleanUtils;
import io.deephaven.util.QueryConstants;
import io.deephaven.util.datastructures.LongSizedDataStructure;
import io.deephaven.web.client.api.BigDecimalWrapper;
import io.deephaven.web.client.api.BigIntegerWrapper;
import io.deephaven.web.client.api.DateWrapper;
import io.deephaven.web.client.api.LocalDateWrapper;
import io.deephaven.web.client.api.LocalTimeWrapper;
import io.deephaven.web.client.api.LongWrapper;
import org.apache.arrow.flatbuf.Date;
import org.apache.arrow.flatbuf.DateUnit;
Expand Down Expand Up @@ -170,7 +174,23 @@ public ChunkReader getReader(StreamReaderOptions options, int factor, ChunkReade
typeInfo.arrowField().type(t);
switch (t.unit()) {
case DateUnit.MILLISECOND:
return new LongChunkReader(options).transform(millis -> DateWrapper.of(millis * 1000 * 1000));
return new LongChunkReader(options).transform(millis -> {
if (millis == QueryConstants.NULL_LONG) {
return null;
}
JsDate jsDate = new JsDate((double) (long) millis);
return new LocalDateWrapper(jsDate.getUTCFullYear(), 1 + jsDate.getUTCMonth(),
jsDate.getUTCDate());
});
case DateUnit.DAY:
return new IntChunkReader(options).transform(days -> {
if (days == QueryConstants.NULL_INT) {
return null;
}
JsDate jsDate = new JsDate(((double) (int) days) * 86400000);
return new LocalDateWrapper(jsDate.getUTCFullYear(), 1 + jsDate.getUTCMonth(),
jsDate.getUTCDate());
});
default:
throw new IllegalArgumentException("Unsupported Date unit: " + DateUnit.name(t.unit()));
}
Expand All @@ -179,11 +199,36 @@ public ChunkReader getReader(StreamReaderOptions options, int factor, ChunkReade
Time t = new Time();
typeInfo.arrowField().type(t);
switch (t.bitWidth()) {
case TimeUnit.NANOSECOND: {
return new LongChunkReader(options).transform(DateWrapper::of);
case 32: {
switch (t.unit()) {
case TimeUnit.SECOND: {
return new IntChunkReader(options)
.transform(LocalTimeWrapper.intCreator(1)::apply);
}
case TimeUnit.MILLISECOND: {
return new IntChunkReader(options)
.transform(LocalTimeWrapper.intCreator(1_000)::apply);
}
default:
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
}
}
case 64: {
switch (t.unit()) {
case TimeUnit.NANOSECOND: {
return new LongChunkReader(options)
.transform(LocalTimeWrapper.longCreator(1_000_000_000)::apply);
}
case TimeUnit.MICROSECOND: {
return new LongChunkReader(options)
.transform(LocalTimeWrapper.longCreator(1_000_000)::apply);
}
default:
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
}
}
default:
throw new IllegalArgumentException("Unsupported Time unit: " + TimeUnit.name(t.unit()));
throw new IllegalArgumentException("Unsupported Time bitWidth: " + t.bitWidth());
}
}
case Type.Timestamp: {
Expand Down

This file was deleted.

This file was deleted.

0 comments on commit 550b902

Please sign in to comment.