ArrowFlightJdbcTime.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.arrow.driver.jdbc;
import static org.apache.calcite.avatica.util.DateTimeUtils.MILLIS_PER_DAY;
import com.google.common.collect.ImmutableList;
import java.sql.Time;
import java.time.LocalTime;
import java.time.temporal.ChronoField;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.apache.arrow.util.VisibleForTesting;
/**
* Wrapper class for Time objects to include the milliseconds part in ISO 8601 format in
* this#toString.
*/
public class ArrowFlightJdbcTime extends Time {
private static final List<String> LEADING_ZEROES = ImmutableList.of("", "0", "00");
// Desired length of the millisecond portion should be 3
private static final int DESIRED_MILLIS_LENGTH = 3;
// Millis of the date time object.
private final int millisReprValue;
/**
* Constructs this object based on epoch millis.
*
* @param milliseconds milliseconds representing Time.
*/
public ArrowFlightJdbcTime(final long milliseconds) {
super(milliseconds);
millisReprValue = getMillisReprValue(milliseconds);
}
@VisibleForTesting
ArrowFlightJdbcTime(final LocalTime time) {
// Although the constructor is deprecated, this is the exact same code as
// Time#valueOf(LocalTime)
super(time.getHour(), time.getMinute(), time.getSecond());
millisReprValue = time.get(ChronoField.MILLI_OF_SECOND);
}
private int getMillisReprValue(long milliseconds) {
// Extract the millisecond part from epoch nano day
if (milliseconds >= MILLIS_PER_DAY) {
// Convert to Epoch Day
milliseconds %= MILLIS_PER_DAY;
} else if (milliseconds < 0) {
// LocalTime#ofNanoDay only accepts positive values
milliseconds -= ((milliseconds / MILLIS_PER_DAY) - 1) * MILLIS_PER_DAY;
}
return LocalTime.ofNanoOfDay(TimeUnit.MILLISECONDS.toNanos(milliseconds))
.get(ChronoField.MILLI_OF_SECOND);
}
@Override
public String toString() {
final StringBuilder time = new StringBuilder().append(super.toString());
if (millisReprValue > 0) {
final String millisString = Integer.toString(millisReprValue);
// dot to separate the fractional seconds
time.append(".");
final int millisLength = millisString.length();
if (millisLength < DESIRED_MILLIS_LENGTH) {
// add necessary leading zeroes
time.append(LEADING_ZEROES.get(DESIRED_MILLIS_LENGTH - millisLength));
}
time.append(millisString);
}
return time.toString();
}
// Spotbugs requires these methods to be overridden
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), this.millisReprValue);
}
}