提交 b26bed64 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Fix subtraction of timestamps

上级 5b87daab
......@@ -5,6 +5,11 @@
*/
package org.h2.expression;
import static org.h2.util.DateTimeUtils.NANOS_PER_DAY;
import static org.h2.util.DateTimeUtils.absoluteDayFromDateValue;
import static org.h2.util.DateTimeUtils.dateAndTimeFromValue;
import static org.h2.util.DateTimeUtils.dateTimeToValue;
import static org.h2.util.DateTimeUtils.dateValueFromAbsoluteDay;
import static org.h2.util.IntervalUtils.NANOS_PER_DAY_BI;
import java.math.BigDecimal;
......@@ -17,7 +22,6 @@ import org.h2.message.DbException;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.util.DateTimeFunctions;
import org.h2.util.DateTimeUtils;
import org.h2.util.IntervalUtils;
import org.h2.value.DataType;
import org.h2.value.Value;
......@@ -73,6 +77,12 @@ public class IntervalOperation extends Expression {
private Expression left, right;
private int dataType;
private static BigInteger nanosFromValue(Value v) {
long[] a = dateAndTimeFromValue(v);
return BigInteger.valueOf(absoluteDayFromDateValue(a[0])).multiply(NANOS_PER_DAY_BI)
.add(BigInteger.valueOf(a[1]));
}
public IntervalOperation(IntervalOpType opType, Expression left, Expression right) {
this.opType = opType;
this.left = left;
......@@ -161,21 +171,15 @@ public class IntervalOperation extends Expression {
return ValueInterval.from(IntervalQualifier.HOUR_TO_SECOND, negative, diff / 3_600_000_000_000L,
diff % 3_600_000_000_000L);
} else if (lType == Value.DATE && rType == Value.DATE) {
long diff = DateTimeUtils.absoluteDayFromDateValue(((ValueDate) l).getDateValue())
- DateTimeUtils.absoluteDayFromDateValue(((ValueDate) r).getDateValue());
long diff = absoluteDayFromDateValue(((ValueDate) l).getDateValue())
- absoluteDayFromDateValue(((ValueDate) r).getDateValue());
boolean negative = diff < 0;
if (negative) {
diff = -diff;
}
return ValueInterval.from(IntervalQualifier.DAY, negative, diff, 0L);
} else {
long[] a = DateTimeUtils.dateAndTimeFromValue(l);
long[] b = DateTimeUtils.dateAndTimeFromValue(r);
BigInteger bi1 = BigInteger.valueOf(a[0]).multiply(NANOS_PER_DAY_BI)
.add(BigInteger.valueOf(a[1]));
BigInteger bi2 = BigInteger.valueOf(b[0]).multiply(NANOS_PER_DAY_BI)
.add(BigInteger.valueOf(b[1]));
BigInteger diff = bi1.subtract(bi2);
BigInteger diff = nanosFromValue(l).subtract(nanosFromValue(r));
if (lType == Value.TIMESTAMP_TZ || rType == Value.TIMESTAMP_TZ) {
l = l.convertTo(Value.TIMESTAMP_TZ);
r = r.convertTo(Value.TIMESTAMP_TZ);
......@@ -214,14 +218,13 @@ public class IntervalOperation extends Expression {
} else {
BigInteger a2 = IntervalUtils.intervalToAbsolute((ValueInterval) r);
if (lType == Value.DATE) {
BigInteger a1 = BigInteger
.valueOf(DateTimeUtils.absoluteDayFromDateValue(((ValueDate) l).getDateValue()));
BigInteger a1 = BigInteger.valueOf(absoluteDayFromDateValue(((ValueDate) l).getDateValue()));
a2 = a2.divide(NANOS_PER_DAY_BI);
BigInteger n = opType == IntervalOpType.DATETIME_PLUS_INTERVAL ? a1.add(a2) : a1.subtract(a2);
return ValueDate.fromDateValue(DateTimeUtils.dateValueFromAbsoluteDay(n.longValue()));
return ValueDate.fromDateValue(dateValueFromAbsoluteDay(n.longValue()));
} else {
long[] a = DateTimeUtils.dateAndTimeFromValue(l);
long absoluteDay = DateTimeUtils.absoluteDayFromDateValue(a[0]);
long[] a = dateAndTimeFromValue(l);
long absoluteDay = absoluteDayFromDateValue(a[0]);
long timeNanos = a[1];
BigInteger[] dr = a2.divideAndRemainder(NANOS_PER_DAY_BI);
if (opType == IntervalOpType.DATETIME_PLUS_INTERVAL) {
......@@ -231,15 +234,14 @@ public class IntervalOperation extends Expression {
absoluteDay -= dr[0].longValue();
timeNanos -= dr[1].longValue();
}
if (timeNanos >= DateTimeUtils.NANOS_PER_DAY) {
timeNanos -= DateTimeUtils.NANOS_PER_DAY;
if (timeNanos >= NANOS_PER_DAY) {
timeNanos -= NANOS_PER_DAY;
absoluteDay++;
} else if (timeNanos < 0) {
timeNanos += DateTimeUtils.NANOS_PER_DAY;
timeNanos += NANOS_PER_DAY;
absoluteDay--;
}
return DateTimeUtils.dateTimeToValue(l, DateTimeUtils.dateValueFromAbsoluteDay(absoluteDay),
timeNanos, false);
return dateTimeToValue(l, dateValueFromAbsoluteDay(absoluteDay), timeNanos, false);
}
}
}
......
......@@ -775,3 +775,12 @@ DROP TABLE TEST;
CREATE TABLE TEST(I INTERVAL HOUR TO SECOND(10));
> exception INVALID_VALUE_SCALE_PRECISION
SELECT TIMESTAMP '2018-09-10 23:30:00' - TIMESTAMP '2014-09-11 23:30:00';
>> INTERVAL '1460 00:00:00' DAY TO SECOND
SELECT TIMESTAMP WITH TIME ZONE '2014-09-11 23:30:00Z' - TIMESTAMP WITH TIME ZONE '2018-09-10 23:30:00Z';
>> INTERVAL '-1460 00:00:00' DAY TO SECOND
SELECT DATE '2018-09-10' - DATE '2014-09-11';
>> INTERVAL '1460' DAY
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论