Unverified 提交 07a0b62b authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #723 from katzyn/LocalDateTimeUtils

Clean up LocalDateTimeUtils
...@@ -27,22 +27,10 @@ import org.h2.value.ValueTimestampTimeZone; ...@@ -27,22 +27,10 @@ import org.h2.value.ValueTimestampTimeZone;
* <p>This class is implemented using reflection so that it compiles on * <p>This class is implemented using reflection so that it compiles on
* Java 7 as well.</p> * Java 7 as well.</p>
* *
* <p>For LocalDate and LocalTime the conversion methods provided by * <p>Custom conversion methods between H2 internal values and JSR-310 classes
* the JDK are used. For OffsetDateTime a custom conversion method is * are used without intermediate conversions to java.sql classes. Direct
* used because it has no equivalent in JDBC. For LocalDateTime a * conversion is simpler, faster, and it does not inherit limitations and
* custom conversion method is used instead of the one provided by the * issues from java.sql classes and conversion methods provided by JDK.</p>
* JDK as well.</p>
*
* <p>Using the JDK provided conversion method for LocalDateTime would
* introduces some errors in edge cases. Consider the following case:
* at 2016-03-27 02:00 in Europe/Berlin the clocks were set to
* 2016-03-27 03:00. This means that 2016-03-27 02:15 does not exist in
* Europe/Berlin. Unfortunately java.sql.Timestamp is in the the time
* zone of the JVM. That means if you run a JVM with the time zone
* Europe/Berlin then the SQL value 'TIMESTAMP 2016-03-27 02:15:00' can
* not be represented. java.time.LocalDateTime does not have these
* limitations but if we convert through java.sql.Timestamp we inherit
* its limitations. Therefore that conversion must be avoided.</p>
* *
* <p>Once the driver requires Java 8 all the reflection can be removed.</p> * <p>Once the driver requires Java 8 all the reflection can be removed.</p>
*/ */
...@@ -85,8 +73,8 @@ public class LocalDateTimeUtils { ...@@ -85,8 +73,8 @@ public class LocalDateTimeUtils {
private static final Method LOCAL_DATE_TIME_PLUS_NANOS; private static final Method LOCAL_DATE_TIME_PLUS_NANOS;
// java.time.LocalDateTime#toLocalDate() // java.time.LocalDateTime#toLocalDate()
private static final Method LOCAL_DATE_TIME_TO_LOCAL_DATE; private static final Method LOCAL_DATE_TIME_TO_LOCAL_DATE;
// java.time.LocalDateTime#truncatedTo(TemporalUnit) // java.time.LocalDateTime#toLocalTime()
private static final Method LOCAL_DATE_TIME_TRUNCATED_TO; private static final Method LOCAL_DATE_TIME_TO_LOCAL_TIME;
// java.time.LocalDateTime#parse(CharSequence) // java.time.LocalDateTime#parse(CharSequence)
private static final Method LOCAL_DATE_TIME_PARSE; private static final Method LOCAL_DATE_TIME_PARSE;
...@@ -105,17 +93,8 @@ public class LocalDateTimeUtils { ...@@ -105,17 +93,8 @@ public class LocalDateTimeUtils {
// java.time.ZoneOffset#getTotalSeconds() // java.time.ZoneOffset#getTotalSeconds()
private static final Method ZONE_OFFSET_GET_TOTAL_SECONDS; private static final Method ZONE_OFFSET_GET_TOTAL_SECONDS;
// java.time.Duration#between(Temporal, Temporal)
private static final Method DURATION_BETWEEN;
// java.time.Duration#toNanos()
private static final Method DURATION_TO_NANOS;
// java.time.temporal.ChronoUnit#DAYS
private static final Object CHRONO_UNIT_DAYS;
private static final boolean IS_JAVA8_DATE_API_PRESENT; private static final boolean IS_JAVA8_DATE_API_PRESENT;
static { static {
LOCAL_DATE = tryGetClass("java.time.LocalDate"); LOCAL_DATE = tryGetClass("java.time.LocalDate");
LOCAL_TIME = tryGetClass("java.time.LocalTime"); LOCAL_TIME = tryGetClass("java.time.LocalTime");
...@@ -127,12 +106,6 @@ public class LocalDateTimeUtils { ...@@ -127,12 +106,6 @@ public class LocalDateTimeUtils {
ZONE_OFFSET != null; ZONE_OFFSET != null;
if (IS_JAVA8_DATE_API_PRESENT) { if (IS_JAVA8_DATE_API_PRESENT) {
Class<?> temporalUnit = getClass("java.time.temporal.TemporalUnit");
Class<?> chronoUnit = getClass("java.time.temporal.ChronoUnit");
Class<?> duration = getClass("java.time.Duration");
Class<?> temporal = getClass("java.time.temporal.Temporal");
LOCAL_TIME_OF_NANO = getMethod(LOCAL_TIME, "ofNanoOfDay", long.class); LOCAL_TIME_OF_NANO = getMethod(LOCAL_TIME, "ofNanoOfDay", long.class);
LOCAL_TIME_TO_NANO = getMethod(LOCAL_TIME, "toNanoOfDay"); LOCAL_TIME_TO_NANO = getMethod(LOCAL_TIME, "toNanoOfDay");
...@@ -150,7 +123,7 @@ public class LocalDateTimeUtils { ...@@ -150,7 +123,7 @@ public class LocalDateTimeUtils {
LOCAL_DATE_TIME_PLUS_NANOS = getMethod(LOCAL_DATE_TIME, "plusNanos", long.class); LOCAL_DATE_TIME_PLUS_NANOS = getMethod(LOCAL_DATE_TIME, "plusNanos", long.class);
LOCAL_DATE_TIME_TO_LOCAL_DATE = getMethod(LOCAL_DATE_TIME, "toLocalDate"); LOCAL_DATE_TIME_TO_LOCAL_DATE = getMethod(LOCAL_DATE_TIME, "toLocalDate");
LOCAL_DATE_TIME_TRUNCATED_TO = getMethod(LOCAL_DATE_TIME, "truncatedTo", temporalUnit); LOCAL_DATE_TIME_TO_LOCAL_TIME = getMethod(LOCAL_DATE_TIME, "toLocalTime");
LOCAL_DATE_TIME_PARSE = getMethod(LOCAL_DATE_TIME, "parse", CharSequence.class); LOCAL_DATE_TIME_PARSE = getMethod(LOCAL_DATE_TIME, "parse", CharSequence.class);
ZONE_OFFSET_OF_TOTAL_SECONDS = getMethod(ZONE_OFFSET, "ofTotalSeconds", int.class); ZONE_OFFSET_OF_TOTAL_SECONDS = getMethod(ZONE_OFFSET, "ofTotalSeconds", int.class);
...@@ -162,11 +135,6 @@ public class LocalDateTimeUtils { ...@@ -162,11 +135,6 @@ public class LocalDateTimeUtils {
OFFSET_DATE_TIME_PARSE = getMethod(OFFSET_DATE_TIME, "parse", CharSequence.class); OFFSET_DATE_TIME_PARSE = getMethod(OFFSET_DATE_TIME, "parse", CharSequence.class);
ZONE_OFFSET_GET_TOTAL_SECONDS = getMethod(ZONE_OFFSET, "getTotalSeconds"); ZONE_OFFSET_GET_TOTAL_SECONDS = getMethod(ZONE_OFFSET, "getTotalSeconds");
DURATION_BETWEEN = getMethod(duration, "between", temporal, temporal);
DURATION_TO_NANOS = getMethod(duration, "toNanos");
CHRONO_UNIT_DAYS = getFieldValue(chronoUnit, "DAYS");
} else { } else {
LOCAL_TIME_OF_NANO = null; LOCAL_TIME_OF_NANO = null;
LOCAL_TIME_TO_NANO = null; LOCAL_TIME_TO_NANO = null;
...@@ -179,7 +147,7 @@ public class LocalDateTimeUtils { ...@@ -179,7 +147,7 @@ public class LocalDateTimeUtils {
LOCAL_TIME_PARSE = null; LOCAL_TIME_PARSE = null;
LOCAL_DATE_TIME_PLUS_NANOS = null; LOCAL_DATE_TIME_PLUS_NANOS = null;
LOCAL_DATE_TIME_TO_LOCAL_DATE = null; LOCAL_DATE_TIME_TO_LOCAL_DATE = null;
LOCAL_DATE_TIME_TRUNCATED_TO = null; LOCAL_DATE_TIME_TO_LOCAL_TIME = null;
LOCAL_DATE_TIME_PARSE = null; LOCAL_DATE_TIME_PARSE = null;
ZONE_OFFSET_OF_TOTAL_SECONDS = null; ZONE_OFFSET_OF_TOTAL_SECONDS = null;
OFFSET_DATE_TIME_TO_LOCAL_DATE_TIME = null; OFFSET_DATE_TIME_TO_LOCAL_DATE_TIME = null;
...@@ -187,9 +155,6 @@ public class LocalDateTimeUtils { ...@@ -187,9 +155,6 @@ public class LocalDateTimeUtils {
OFFSET_DATE_TIME_OF_LOCAL_DATE_TIME_ZONE_OFFSET = null; OFFSET_DATE_TIME_OF_LOCAL_DATE_TIME_ZONE_OFFSET = null;
OFFSET_DATE_TIME_PARSE = null; OFFSET_DATE_TIME_PARSE = null;
ZONE_OFFSET_GET_TOTAL_SECONDS = null; ZONE_OFFSET_GET_TOTAL_SECONDS = null;
DURATION_BETWEEN = null;
DURATION_TO_NANOS = null;
CHRONO_UNIT_DAYS = null;
} }
} }
...@@ -310,15 +275,6 @@ public class LocalDateTimeUtils { ...@@ -310,15 +275,6 @@ public class LocalDateTimeUtils {
} }
} }
private static Class<?> getClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Java 8 or later but class " +
className + " is missing", e);
}
}
private static Method getMethod(Class<?> clazz, String methodName, private static Method getMethod(Class<?> clazz, String methodName,
Class<?>... parameterTypes) { Class<?>... parameterTypes) {
try { try {
...@@ -330,15 +286,6 @@ public class LocalDateTimeUtils { ...@@ -330,15 +286,6 @@ public class LocalDateTimeUtils {
} }
} }
private static Object getFieldValue(Class<?> clazz, String fieldName) {
try {
return clazz.getField(fieldName).get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new IllegalStateException("Java 8 or later but field " +
clazz.getName() + "#" + fieldName + " is missing", e);
}
}
/** /**
* Checks if the given class is LocalDate. * Checks if the given class is LocalDate.
* *
...@@ -523,7 +470,7 @@ public class LocalDateTimeUtils { ...@@ -523,7 +470,7 @@ public class LocalDateTimeUtils {
try { try {
Object localDate = LOCAL_DATE_TIME_TO_LOCAL_DATE.invoke(localDateTime); Object localDate = LOCAL_DATE_TIME_TO_LOCAL_DATE.invoke(localDateTime);
long dateValue = dateValueFromLocalDate(localDate); long dateValue = dateValueFromLocalDate(localDate);
long timeNanos = timeNanosFromLocalDate(localDateTime); long timeNanos = timeNanosFromLocalDateTime(localDateTime);
return ValueTimestamp.fromDateValueAndNanos(dateValue, timeNanos); return ValueTimestamp.fromDateValueAndNanos(dateValue, timeNanos);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw DbException.convert(e); throw DbException.convert(e);
...@@ -545,7 +492,7 @@ public class LocalDateTimeUtils { ...@@ -545,7 +492,7 @@ public class LocalDateTimeUtils {
Object zoneOffset = OFFSET_DATE_TIME_GET_OFFSET.invoke(offsetDateTime); Object zoneOffset = OFFSET_DATE_TIME_GET_OFFSET.invoke(offsetDateTime);
long dateValue = dateValueFromLocalDate(localDate); long dateValue = dateValueFromLocalDate(localDate);
long timeNanos = timeNanosFromLocalDate(localDateTime); long timeNanos = timeNanosFromLocalDateTime(localDateTime);
short timeZoneOffsetMins = zoneOffsetToOffsetMinute(zoneOffset); short timeZoneOffsetMins = zoneOffsetToOffsetMinute(zoneOffset);
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue,
timeNanos, timeZoneOffsetMins); timeNanos, timeZoneOffsetMins);
...@@ -564,11 +511,10 @@ public class LocalDateTimeUtils { ...@@ -564,11 +511,10 @@ public class LocalDateTimeUtils {
return DateTimeUtils.dateValue(year, month, day); return DateTimeUtils.dateValue(year, month, day);
} }
private static long timeNanosFromLocalDate(Object localDateTime) private static long timeNanosFromLocalDateTime(Object localDateTime)
throws IllegalAccessException, InvocationTargetException { throws IllegalAccessException, InvocationTargetException {
Object midnight = LOCAL_DATE_TIME_TRUNCATED_TO.invoke(localDateTime, CHRONO_UNIT_DAYS); Object localTime = LOCAL_DATE_TIME_TO_LOCAL_TIME.invoke(localDateTime);
Object duration = DURATION_BETWEEN.invoke(null, midnight, localDateTime); return (Long) LOCAL_TIME_TO_NANO.invoke(localTime);
return (Long) DURATION_TO_NANOS.invoke(duration);
} }
private static short zoneOffsetToOffsetMinute(Object zoneOffset) private static short zoneOffsetToOffsetMinute(Object zoneOffset)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论