提交 8c95b033 authored 作者: Thomas Mueller's avatar Thomas Mueller

Date, time, and timestamp data type processing has been re-implemented.

上级 2421bad7
......@@ -18,7 +18,10 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>-
<ul><li>Date, time, and timestamp data type processing has been re-implemented.
Time now supports nanoseconds resolution and now now supports a wider range
(negative and large values), similar to PostgreSQL.
</li><li>SQL statements with a non-breaking space were considered invalid.
</li></ul>
<h2>Version 1.3.157 (2011-06-25)</h2>
......
......@@ -2465,15 +2465,15 @@ public class Parser {
if (equalsToken("DATE", name)) {
String date = currentValue.getString();
read();
r = ValueExpression.get(ValueDate.get(ValueDate.parseDate(date)));
r = ValueExpression.get(ValueDate.parse(date));
} else if (equalsToken("TIME", name)) {
String time = currentValue.getString();
read();
r = ValueExpression.get(ValueTime.get(ValueTime.parseTime(time)));
r = ValueExpression.get(ValueTime.parse(time));
} else if (equalsToken("TIMESTAMP", name)) {
String timestamp = currentValue.getString();
read();
r = ValueExpression.get(ValueTimestamp.getNoCopy(ValueTimestamp.parseTimestamp(timestamp)));
r = ValueExpression.get(ValueTimestamp.parse(timestamp));
} else if (equalsToken("X", name)) {
read();
byte[] buffer = StringUtils.convertHexToBytes(currentValue.getString());
......@@ -3231,7 +3231,7 @@ public class Parser {
} else if (c >= '0' && c <= '9') {
type = CHAR_VALUE;
} else {
if (c <= ' ' || Character.isWhitespace(c)) {
if (c <= ' ' || Character.isSpaceChar(c)) {
// whitespace
} else if (Character.isJavaIdentifierPart(c)) {
type = CHAR_NAME;
......
......@@ -56,6 +56,11 @@ public class Constants {
*/
public static final int TCP_PROTOCOL_VERSION_8 = 8;
/**
* The TCP protocol version number 9.
*/
public static final int TCP_PROTOCOL_VERSION_9 = 9;
/**
* The major version of this database.
*/
......
......@@ -94,7 +94,7 @@ public class SessionRemote extends SessionWithState implements DataHandler {
trans.setSSL(ci.isSSL());
trans.init();
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_8);
trans.writeInt(Constants.TCP_PROTOCOL_VERSION_9);
trans.writeString(db);
trans.writeString(ci.getOriginalURL());
trans.writeString(ci.getUserName());
......
......@@ -629,52 +629,52 @@ public class Function extends Expression implements FunctionCall {
break;
case DAY_NAME: {
SimpleDateFormat dayName = new SimpleDateFormat("EEEE", Locale.ENGLISH);
result = ValueString.get(dayName.format(v0.getDateNoCopy()));
result = ValueString.get(dayName.format(v0.getDate()));
break;
}
case DAY_OF_MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.DAY_OF_MONTH));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_MONTH));
break;
case DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.DAY_OF_WEEK));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_WEEK));
break;
case DAY_OF_YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.DAY_OF_YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.DAY_OF_YEAR));
break;
case HOUR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.HOUR_OF_DAY));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.HOUR_OF_DAY));
break;
case MINUTE:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.MINUTE));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.MINUTE));
break;
case MONTH:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.MONTH));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.MONTH));
break;
case MONTH_NAME: {
SimpleDateFormat monthName = new SimpleDateFormat("MMMM", Locale.ENGLISH);
result = ValueString.get(monthName.format(v0.getDateNoCopy()));
result = ValueString.get(monthName.format(v0.getDate()));
break;
}
case QUARTER:
result = ValueInt.get((DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.MONTH) - 1) / 3 + 1);
result = ValueInt.get((DateTimeUtils.getDatePart(v0.getDate(), Calendar.MONTH) - 1) / 3 + 1);
break;
case SECOND:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestampNoCopy(), Calendar.SECOND));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getTimestamp(), Calendar.SECOND));
break;
case WEEK:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.WEEK_OF_YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.WEEK_OF_YEAR));
break;
case YEAR:
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDateNoCopy(), Calendar.YEAR));
result = ValueInt.get(DateTimeUtils.getDatePart(v0.getDate(), Calendar.YEAR));
break;
case ISO_YEAR:
result = ValueInt.get(DateTimeUtils.getIsoYear(v0.getDateNoCopy()));
result = ValueInt.get(DateTimeUtils.getIsoYear(v0.getDate()));
break;
case ISO_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoWeek(v0.getDateNoCopy()));
result = ValueInt.get(DateTimeUtils.getIsoWeek(v0.getDate()));
break;
case ISO_DAY_OF_WEEK:
result = ValueInt.get(DateTimeUtils.getIsoDayOfWeek(v0.getDateNoCopy()));
result = ValueInt.get(DateTimeUtils.getIsoDayOfWeek(v0.getDate()));
break;
case CURDATE:
case CURRENT_DATE: {
......@@ -693,7 +693,7 @@ public class Function extends Expression implements FunctionCall {
case NOW:
case CURRENT_TIMESTAMP: {
long now = session.getTransactionStart();
ValueTimestamp vt = ValueTimestamp.getNoCopy(new Timestamp(now));
ValueTimestamp vt = ValueTimestamp.get(new Timestamp(now));
if (v0 != null) {
Mode mode = database.getMode();
vt = (ValueTimestamp) vt.convertScale(mode.convertOnlyToSmallerScale, v0.getInt());
......@@ -1038,10 +1038,10 @@ public class Function extends Expression implements FunctionCall {
break;
// date
case DATE_ADD:
result = ValueTimestamp.getNoCopy(dateadd(v0.getString(), v1.getInt(), v2.getTimestampNoCopy()));
result = ValueTimestamp.get(dateadd(v0.getString(), v1.getInt(), v2.getTimestamp()));
break;
case DATE_DIFF:
result = ValueLong.get(datediff(v0.getString(), v1.getTimestampNoCopy(), v2.getTimestampNoCopy()));
result = ValueLong.get(datediff(v0.getString(), v1.getTimestamp(), v2.getTimestamp()));
break;
case EXTRACT: {
int field = getDatePart(v0.getString());
......@@ -1065,7 +1065,7 @@ public class Function extends Expression implements FunctionCall {
String locale = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString();
String tz = v3 == null ? null : v3 == ValueNull.INSTANCE ? null : v3.getString();
java.util.Date d = DateTimeUtils.parseDateTime(v0.getString(), v1.getString(), locale, tz);
result = ValueTimestamp.getNoCopy(new Timestamp(d.getTime()));
result = ValueTimestamp.get(new Timestamp(d.getTime()));
}
break;
}
......
......@@ -611,7 +611,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (x == null) {
setParameter(parameterIndex, ValueNull.INSTANCE);
} else {
setParameter(parameterIndex, DateTimeUtils.convertDateToUniversal(x, calendar));
setParameter(parameterIndex, DateTimeUtils.convertDateToUTC(x, calendar));
}
} catch (Exception e) {
throw logAndConvert(e);
......@@ -635,7 +635,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (x == null) {
setParameter(parameterIndex, ValueNull.INSTANCE);
} else {
setParameter(parameterIndex, DateTimeUtils.convertTimeToUniversal(x, calendar));
setParameter(parameterIndex, DateTimeUtils.convertTimeToUTC(x, calendar));
}
} catch (Exception e) {
throw logAndConvert(e);
......
......@@ -71,12 +71,12 @@ public class TcpServerThread implements Runnable {
int minClientVersion = transfer.readInt();
if (minClientVersion < Constants.TCP_PROTOCOL_VERSION_6) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2, "" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_6);
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_8) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2, "" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_8);
} else if (minClientVersion > Constants.TCP_PROTOCOL_VERSION_9) {
throw DbException.get(ErrorCode.DRIVER_VERSION_ERROR_2, "" + clientVersion, "" + Constants.TCP_PROTOCOL_VERSION_9);
}
int maxClientVersion = transfer.readInt();
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_8) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_8;
if (maxClientVersion >= Constants.TCP_PROTOCOL_VERSION_9) {
clientVersion = Constants.TCP_PROTOCOL_VERSION_9;
} else {
clientVersion = minClientVersion;
}
......
......@@ -471,34 +471,38 @@ public class Data {
case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_TIME);
writeVarLong(DateTimeUtils.getTimeLocal(v.getTimeNoCopy()));
writeVarLong(((ValueTime) v).getNanos());
} else {
writeByte((byte) type);
writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTimeNoCopy()));
writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
}
break;
case Value.DATE: {
if (SysProperties.STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_DATE);
long x = DateTimeUtils.getTimeLocal(v.getDateNoCopy());
writeVarLong(x / MILLIS_PER_MINUTE);
long x = ((ValueDate) v).getDateValue();
writeVarLong(x);
} else {
writeByte((byte) type);
long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDateNoCopy());
long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDate());
writeVarLong(x / MILLIS_PER_MINUTE);
}
break;
}
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestampNoCopy();
if (SysProperties.STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_TIMESTAMP);
writeVarLong(DateTimeUtils.getTimeLocal(ts));
ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue();
long nanos = ts.getNanos();
writeVarLong(dateValue);
writeVarLong(nanos);
} else {
Timestamp ts = v.getTimestamp();
writeByte((byte) type);
writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(ts));
writeVarInt(ts.getNanos());
}
writeVarInt(ts.getNanos());
break;
}
case Value.JAVA_OBJECT: {
......@@ -679,28 +683,26 @@ public class Data {
return ValueDecimal.get(new BigDecimal(b, scale));
}
case LOCAL_DATE: {
long x = readVarLong() * MILLIS_PER_MINUTE;
return ValueDate.getNoCopy(new Date(DateTimeUtils.getTimeGMT(x)));
return ValueDate.get(readVarLong());
}
case Value.DATE: {
long x = readVarLong() * MILLIS_PER_MINUTE;
return ValueDate.getNoCopy(new Date(DateTimeUtils.getTimeGMTWithoutDst(x)));
return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(x)));
}
case LOCAL_TIME:
// need to normalize the year, month and day
return ValueTime.get(new Time(DateTimeUtils.getTimeGMT(readVarLong())));
return ValueTime.get(readVarLong());
case Value.TIME:
// need to normalize the year, month and day
return ValueTime.get(new Time(DateTimeUtils.getTimeGMTWithoutDst(readVarLong())));
return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readVarLong())));
case LOCAL_TIMESTAMP: {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeGMT(readVarLong()));
ts.setNanos(readVarInt());
return ValueTimestamp.getNoCopy(ts);
long dateValue = readVarLong();
long nanos = readVarLong();
return ValueTimestamp.get(dateValue, nanos);
}
case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeGMTWithoutDst(readVarLong()));
Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readVarLong()));
ts.setNanos(readVarInt());
return ValueTimestamp.getNoCopy(ts);
return ValueTimestamp.get(ts);
}
case Value.BYTES: {
int len = readVarInt();
......@@ -893,23 +895,25 @@ public class Data {
}
case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) {
return 1 + getVarLongLen(DateTimeUtils.getTimeLocal(v.getTimeNoCopy()));
return 1 + getVarLongLen(((ValueTime) v).getNanos());
}
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(v.getTimeNoCopy()));
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
case Value.DATE: {
if (SysProperties.STORE_LOCAL_TIME) {
long x = DateTimeUtils.getTimeLocal(v.getDateNoCopy());
return 1 + getVarLongLen(x / MILLIS_PER_MINUTE);
long dateValue = ((ValueDate) v).getDateValue();
return 1 + getVarLongLen(dateValue);
}
long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDateNoCopy());
long x = DateTimeUtils.getTimeLocalWithoutDst(v.getDate());
return 1 + getVarLongLen(x / MILLIS_PER_MINUTE);
}
case Value.TIMESTAMP: {
if (SysProperties.STORE_LOCAL_TIME) {
Timestamp ts = v.getTimestampNoCopy();
return 1 + getVarLongLen(DateTimeUtils.getTimeLocal(ts)) + getVarIntLen(ts.getNanos());
ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue();
long nanos = ts.getNanos();
return 1 + getVarLongLen(dateValue) + getVarLongLen(nanos);
}
Timestamp ts = v.getTimestampNoCopy();
Timestamp ts = v.getTimestamp();
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(ts)) + getVarIntLen(ts.getNanos());
}
case Value.JAVA_OBJECT: {
......
......@@ -230,7 +230,7 @@ public class FileLock implements Runnable {
transfer.setSocket(socket);
transfer.init();
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_6);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_8);
transfer.writeInt(Constants.TCP_PROTOCOL_VERSION_9);
transfer.writeString(null);
transfer.writeString(null);
transfer.writeString(id);
......
......@@ -284,12 +284,15 @@ public class Column {
if (dt.decimal) {
value = ValueInt.get(0).convertTo(type);
} else if (dt.type == Value.TIMESTAMP) {
value = ValueTimestamp.getNoCopy(new Timestamp(System.currentTimeMillis()));
// TODO
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis()));
} else if (dt.type == Value.TIME) {
// TODO
// need to normalize
value = ValueTime.get(Time.valueOf("0:0:0"));
} else if (dt.type == Value.DATE) {
value = ValueTimestamp.getNoCopy(new Timestamp(System.currentTimeMillis())).convertTo(dt.type);
// TODO
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis())).convertTo(dt.type);
} else {
value = ValueString.get("").convertTo(type);
}
......
......@@ -320,27 +320,37 @@ public class Transfer {
writeByte(v.getByte());
break;
case Value.TIME:
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTimeNoCopy()));
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
writeLong(((ValueTime) v).getNanos());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
} else {
writeLong(v.getTimeNoCopy().getTime());
writeLong(v.getTime().getTime());
}
break;
case Value.DATE:
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getDateNoCopy()));
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
writeLong(((ValueDate) v).getDateValue());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
writeLong(DateTimeUtils.getTimeLocalWithoutDst(v.getDate()));
} else {
writeLong(v.getDateNoCopy().getTime());
writeLong(v.getDate().getTime());
}
break;
case Value.TIMESTAMP: {
Timestamp ts = v.getTimestampNoCopy();
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
ValueTimestamp ts = (ValueTimestamp) v;
writeLong(ts.getDateValue());
writeLong(ts.getNanos());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
Timestamp ts = v.getTimestamp();
writeLong(DateTimeUtils.getTimeLocalWithoutDst(ts));
writeInt(ts.getNanos());
} else {
Timestamp ts = v.getTimestamp();
writeLong(ts.getTime());
writeInt(ts.getNanos());
}
writeInt(ts.getNanos());
break;
}
case Value.DECIMAL:
......@@ -460,24 +470,30 @@ public class Transfer {
case Value.BYTE:
return ValueByte.get(readByte());
case Value.DATE:
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueDate.getNoCopy(new Date(DateTimeUtils.getTimeGMTWithoutDst(readLong())));
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueDate.get(readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
}
return ValueDate.getNoCopy(new Date(readLong()));
return ValueDate.get(new Date(readLong()));
case Value.TIME:
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueTime.getNoCopy(new Time(DateTimeUtils.getTimeGMTWithoutDst(readLong())));
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueTime.get(readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
}
return ValueTime.getNoCopy(new Time(readLong()));
return ValueTime.get(new Time(readLong()));
case Value.TIMESTAMP: {
if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeGMTWithoutDst(readLong()));
if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueTimestamp.get(readLong(), readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readLong()));
ts.setNanos(readInt());
return ValueTimestamp.getNoCopy(ts);
return ValueTimestamp.get(ts);
}
Timestamp ts = new Timestamp(readLong());
ts.setNanos(readInt());
return ValueTimestamp.getNoCopy(ts);
return ValueTimestamp.get(ts);
}
case Value.DECIMAL:
return ValueDecimal.get(new BigDecimal(readString()));
......
......@@ -24,6 +24,7 @@ import org.h2.message.DbException;
import org.h2.store.DataHandler;
import org.h2.store.LobStorage;
import org.h2.tools.SimpleResultSet;
import org.h2.util.DateTimeUtils;
import org.h2.util.IOUtils;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
......@@ -370,26 +371,14 @@ public abstract class Value {
return ((ValueDate) convertTo(Value.DATE)).getDate();
}
public Date getDateNoCopy() {
return ((ValueDate) convertTo(Value.DATE)).getDateNoCopy();
}
public Time getTime() {
return ((ValueTime) convertTo(Value.TIME)).getTime();
}
public Time getTimeNoCopy() {
return ((ValueTime) convertTo(Value.TIME)).getTimeNoCopy();
}
public Timestamp getTimestamp() {
return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestamp();
}
public Timestamp getTimestampNoCopy() {
return ((ValueTimestamp) convertTo(Value.TIMESTAMP)).getTimestampNoCopy();
}
public byte[] getBytes() {
return ((ValueBytes) convertTo(Value.BYTES)).getBytes();
}
......@@ -693,9 +682,11 @@ public abstract class Value {
case DATE: {
switch (getType()) {
case TIME:
return ValueDate.get(new Date(getTimeNoCopy().getTime()));
// because the time has set the date to 1970-01-01,
// this will be the result
return ValueDate.get(DateTimeUtils.dateValue(1970, 1, 1));
case TIMESTAMP:
return ValueDate.get(new Date(getTimestampNoCopy().getTime()));
return ValueDate.get(((ValueTimestamp) this).getDateValue());
}
break;
}
......@@ -703,19 +694,22 @@ public abstract class Value {
switch (getType()) {
case DATE:
// need to normalize the year, month and day
return ValueTime.get(new Time(getDateNoCopy().getTime()));
// because a date has the time set to 0, the result will be 0
return ValueTime.get(0);
case TIMESTAMP:
// need to normalize the year, month and day
return ValueTime.get(new Time(getTimestampNoCopy().getTime()));
return ValueTime.get(new Time(getTimestamp().getTime()));
}
break;
}
case TIMESTAMP: {
switch (getType()) {
case TIME:
return ValueTimestamp.getNoCopy(new Timestamp(getTimeNoCopy().getTime()));
// TODO
return ValueTimestamp.get(new Timestamp(getTime().getTime()));
case DATE:
return ValueTimestamp.getNoCopy(new Timestamp(getDateNoCopy().getTime()));
// TODO
return ValueTimestamp.get(new Timestamp(getDate().getTime()));
}
break;
}
......@@ -815,11 +809,11 @@ public abstract class Value {
case DECIMAL:
return ValueDecimal.get(new BigDecimal(s.trim()));
case TIME:
return ValueTime.getNoCopy(ValueTime.parseTime(s.trim()));
return ValueTime.parse(s.trim());
case DATE:
return ValueDate.getNoCopy(ValueDate.parseDate(s.trim()));
return ValueDate.parse(s.trim());
case TIMESTAMP:
return ValueTimestamp.getNoCopy(ValueTimestamp.parseTimestamp(s.trim()));
return ValueTimestamp.parse(s.trim());
case BYTES:
return ValueBytes.getNoCopy(StringUtils.convertHexToBytes(s.trim()));
case JAVA_OBJECT:
......
......@@ -9,8 +9,8 @@ package org.h2.value;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Calendar;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
/**
* Implementation of the DATE data type.
......@@ -28,29 +28,29 @@ public class ValueDate extends Value {
*/
static final int DISPLAY_SIZE = 10;
private final Date value;
private final long dateValue;
private ValueDate(Date value) {
this.value = value;
private ValueDate(long dateValue) {
this.dateValue = dateValue;
}
/**
* Parse a string to a java.sql.Date object.
* Parse a string to a ValueDate.
*
* @param s the string to parse
* @return the date
*/
public static Date parseDate(String s) {
return (Date) DateTimeUtils.parseDateTime(s, Value.DATE);
public static ValueDate parse(String s) {
Value x = DateTimeUtils.parse(s, Value.DATE);
return (ValueDate) Value.cache(x);
}
public Date getDate() {
// this class is mutable - must copy the object
return (Date) value.clone();
return DateTimeUtils.convertDateValueToDate(dateValue);
}
public Date getDateNoCopy() {
return value;
public long getDateValue() {
return dateValue;
}
public String getSQL() {
......@@ -62,22 +62,13 @@ public class ValueDate extends Value {
}
protected int compareSecure(Value o, CompareMode mode) {
ValueDate v = (ValueDate) o;
return Integer.signum(value.compareTo(v.value));
return MathUtils.compareLong(dateValue, ((ValueDate) o).dateValue);
}
public String getString() {
String s = value.toString();
long time = value.getTime();
// special case: java.sql.Date doesn't format
// years below year 1 (BC) and years above 9999 correctly
if (time < ValueTimestamp.YEAR_ONE || time > ValueTimestamp.YEAR_9999) {
int year = DateTimeUtils.getDatePart(value, Calendar.YEAR);
if (year < 1 || year > 9999) {
s = year + s.substring(s.indexOf('-'));
}
}
return s;
StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
DateTimeUtils.appendDate(buff, dateValue);
return buff.toString();
}
public long getPrecision() {
......@@ -85,39 +76,36 @@ public class ValueDate extends Value {
}
public int hashCode() {
return value.hashCode();
return (int) (dateValue ^ (dateValue >>> 32));
}
public Object getObject() {
// this class is mutable - must copy the object
return getDate();
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
prep.setDate(parameterIndex, value);
prep.setDate(parameterIndex, getDate());
}
/**
* Get or create a date value for the given date.
* Clone the date.
*
* @param date the date
* @return the value
*/
public static ValueDate get(Date date) {
date = DateTimeUtils.cloneAndNormalizeDate(date);
return getNoCopy(date);
long x = DateTimeUtils.dateValueFromDate(date.getTime());
return get(x);
}
/**
* Get or create a date value for the given date.
* Do not clone the date.
*
* @param date the date
* @param dateValue the date value
* @return the value
*/
public static ValueDate getNoCopy(Date date) {
return (ValueDate) Value.cache(new ValueDate(date));
public static ValueDate get(long dateValue) {
return (ValueDate) Value.cache(new ValueDate(dateValue));
}
public int getDisplaySize() {
......@@ -125,7 +113,10 @@ public class ValueDate extends Value {
}
public boolean equals(Object other) {
return other instanceof ValueDate && value.equals(((ValueDate) other).value);
if (this == other) {
return true;
}
return other instanceof ValueDate && dateValue == (((ValueDate) other).dateValue);
}
}
......@@ -10,6 +10,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
/**
* Implementation of the TIME data type.
......@@ -27,29 +28,28 @@ public class ValueTime extends Value {
*/
static final int DISPLAY_SIZE = 8;
private final Time value;
private final long nanos;
private ValueTime(Time value) {
this.value = value;
private ValueTime(long nanos) {
this.nanos = nanos;
}
/**
* Parse a string to a java.sql.Time object.
* Parse a string to a ValueTime.
*
* @param s the string to parse
* @return the time
*/
public static Time parseTime(String s) {
return (Time) DateTimeUtils.parseDateTime(s, Value.TIME);
public static ValueTime parse(String s) {
return new ValueTime(DateTimeUtils.parseTime(s));
}
public Time getTime() {
// this class is mutable - must copy the object
return (Time) value.clone();
return DateTimeUtils.convertNanoToTime(nanos);
}
public Time getTimeNoCopy() {
return value;
public long getNanos() {
return nanos;
}
public String getSQL() {
......@@ -61,12 +61,13 @@ public class ValueTime extends Value {
}
protected int compareSecure(Value o, CompareMode mode) {
ValueTime v = (ValueTime) o;
return Integer.signum(value.compareTo(v.value));
return MathUtils.compareLong(nanos, ((ValueTime) o).nanos);
}
public String getString() {
return value.toString();
StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
DateTimeUtils.appendTime(buff, nanos, false);
return buff.toString();
}
public long getPrecision() {
......@@ -74,7 +75,7 @@ public class ValueTime extends Value {
}
public int hashCode() {
return value.hashCode();
return (int) (nanos ^ (nanos >>> 32));
}
public Object getObject() {
......@@ -82,30 +83,28 @@ public class ValueTime extends Value {
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
prep.setTime(parameterIndex, value);
prep.setTime(parameterIndex, getTime());
}
/**
* Get or create a time value for the given time.
* Clone the time.
*
* @param time the time
* @return the value
*/
public static ValueTime get(Time time) {
time = DateTimeUtils.cloneAndNormalizeTime(time);
return getNoCopy(time);
long x = DateTimeUtils.nanosFromDate(time.getTime());
return get(x);
}
/**
* Get or create a time value for the given time.
* Do not clone the time.
* Get or create a time value.
*
* @param time the time
* @param nanos the nanoseconds
* @return the value
*/
public static ValueTime getNoCopy(Time time) {
return (ValueTime) Value.cache(new ValueTime(time));
public static ValueTime get(long nanos) {
return (ValueTime) Value.cache(new ValueTime(nanos));
}
public int getDisplaySize() {
......@@ -113,31 +112,28 @@ public class ValueTime extends Value {
}
public boolean equals(Object other) {
return other instanceof ValueTime && value.equals(((ValueTime) other).value);
if (this == other) {
return true;
}
return other instanceof ValueTime && nanos == (((ValueTime) other).nanos);
}
public Value add(Value v) {
Time t = new Time(value.getTime() + v.getTime().getTime());
return ValueTime.get(t);
ValueTime t = (ValueTime) v.convertTo(Value.TIME);
return ValueTime.get(nanos + t.getNanos());
}
public Value subtract(Value v) {
Time t = new Time(value.getTime() - v.getTime().getTime());
return ValueTime.get(t);
ValueTime t = (ValueTime) v.convertTo(Value.TIME);
return ValueTime.get(nanos - t.getNanos());
}
public Value multiply(Value v) {
long zeroTime = ValueTime.get(new Time(0)).getDate().getTime();
long t = value.getTime() - zeroTime;
t = (long) (t * v.getDouble()) + zeroTime;
return ValueTime.get(new Time(t));
return ValueTime.get((long) (nanos * v.getDouble()));
}
public Value divide(Value v) {
long zeroTime = ValueTime.get(new Time(0)).getDate().getTime();
long t = value.getTime() - zeroTime;
t = (long) (t / v.getDouble()) + zeroTime;
return ValueTime.get(new Time(t));
return ValueTime.get((long) (nanos / v.getDouble()));
}
}
......@@ -9,9 +9,7 @@ package org.h2.value;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import org.h2.message.DbException;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
......@@ -37,33 +35,24 @@ public class ValueTimestamp extends Value {
*/
static final int DEFAULT_SCALE = 10;
/**
* This is used to find out if a date is possibly BC. Because of time zone
* issues (the date is time zone specific), the second day is used. That
* means the value is not exact, but it does not need to be.
*/
static final long YEAR_ONE = java.sql.Date.valueOf("0001-01-02").getTime();
private final long dateValue;
private final long nanos;
/**
* This is used to find out if the year is possibly larger than 9999.
* Because of time zone issues (the date is time zone specific), it's a few
* days before the last day. That means the value is not exact, but it does
* not need to be.
*/
static final long YEAR_9999 = java.sql.Date.valueOf("9999-12-20").getTime();
private final Timestamp value;
private ValueTimestamp(Timestamp value) {
this.value = value;
private ValueTimestamp(long dateValue, long nanos) {
this.dateValue = dateValue;
this.nanos = nanos;
}
public Timestamp getTimestamp() {
return (Timestamp) value.clone();
return DateTimeUtils.convertDateValueToTimestamp(dateValue, nanos);
}
public long getDateValue() {
return dateValue;
}
public Timestamp getTimestampNoCopy() {
return value;
public long getNanos() {
return nanos;
}
public String getSQL() {
......@@ -71,13 +60,25 @@ public class ValueTimestamp extends Value {
}
/**
* Parse a string to a java.sql.Timestamp object.
* Get or create a date value for the given date.
*
* @param dateValue the date value
* @param nanos the nanoseconds
* @return the value
*/
public static ValueTimestamp get(long dateValue, long nanos) {
return (ValueTimestamp) Value.cache(new ValueTimestamp(dateValue, nanos));
}
/**
* Parse a string to a ValueTimestamp.
*
* @param s the string to parse
* @return the timestamp
* @return the date
*/
public static Timestamp parseTimestamp(String s) {
return (Timestamp) DateTimeUtils.parseDateTime(s, Value.TIMESTAMP);
public static ValueTimestamp parse(String s) {
Value x = DateTimeUtils.parse(s, Value.TIMESTAMP);
return (ValueTimestamp) Value.cache(x);
}
public int getType() {
......@@ -85,22 +86,21 @@ public class ValueTimestamp extends Value {
}
protected int compareSecure(Value o, CompareMode mode) {
ValueTimestamp v = (ValueTimestamp) o;
return Integer.signum(value.compareTo(v.value));
ValueTimestamp t = (ValueTimestamp) o;
int c = MathUtils.compareLong(dateValue, t.dateValue);
if (c != 0) {
return c;
}
return MathUtils.compareLong(nanos, t.nanos);
}
public String getString() {
String s = value.toString();
long time = value.getTime();
// special case: java.sql.Timestamp doesn't format
// years below year 1 (BC) correctly
if (time < YEAR_ONE) {
int year = DateTimeUtils.getDatePart(value, Calendar.YEAR);
if (year < 1) {
s = year + s.substring(s.indexOf('-'));
}
}
return s;
// TODO verify display size
StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
DateTimeUtils.appendDate(buff, dateValue);
buff.append(' ');
DateTimeUtils.appendTime(buff, nanos, true);
return buff.toString();
}
public long getPrecision() {
......@@ -112,63 +112,48 @@ public class ValueTimestamp extends Value {
}
public int hashCode() {
return value.hashCode();
return (int) (dateValue ^ (dateValue >>> 32) ^ nanos ^ (nanos >>> 32));
}
public Object getObject() {
// this class is mutable - must copy the object
return getTimestamp();
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
prep.setTimestamp(parameterIndex, value);
prep.setTimestamp(parameterIndex, getTimestamp());
}
/**
* Get or create a timestamp value for the given timestamp.
* Clone the timestamp.
*
* @param timestamp the timestamp
* @return the value
*/
public static ValueTimestamp get(Timestamp timestamp) {
timestamp = (Timestamp) timestamp.clone();
return getNoCopy(timestamp);
}
/**
* Get or create a timestamp value for the given timestamp.
* Do not clone the timestamp.
*
* @param timestamp the timestamp
* @return the value
*/
public static ValueTimestamp getNoCopy(Timestamp timestamp) {
return (ValueTimestamp) Value.cache(new ValueTimestamp(timestamp));
long ms = timestamp.getTime();
long dateValue = DateTimeUtils.dateValueFromDate(ms);
long nanos = DateTimeUtils.nanosFromDate(ms);
nanos += timestamp.getNanos() % 1000000;
return get(dateValue, nanos);
}
public Value convertScale(boolean onlyToSmallerScale, int targetScale) {
if (targetScale == DEFAULT_SCALE) {
return this;
}
if (targetScale < 0 || targetScale > DEFAULT_SCALE) {
// TODO convertScale for Timestamps: may throw an exception?
throw DbException.getInvalidValueException("scale", targetScale);
}
int nanos = value.getNanos();
BigDecimal bd = BigDecimal.valueOf(nanos);
long n = nanos;
BigDecimal bd = BigDecimal.valueOf(n);
bd = bd.movePointLeft(9);
bd = MathUtils.setScale(bd, targetScale);
bd = bd.movePointRight(9);
int n2 = bd.intValue();
if (n2 == nanos) {
long n2 = bd.longValue();
if (n2 == n) {
return this;
}
long t = value.getTime();
while (n2 >= 1000000000) {
t += 1000;
n2 -= 1000000000;
}
Timestamp t2 = new Timestamp(t);
t2.setNanos(n2);
return ValueTimestamp.getNoCopy(t2);
return get(dateValue, n2);
}
public int getDisplaySize() {
......@@ -176,21 +161,29 @@ public class ValueTimestamp extends Value {
}
public boolean equals(Object other) {
return other instanceof ValueTimestamp && value.equals(((ValueTimestamp) other).value);
if (this == other) {
return true;
} else if (!(other instanceof ValueTimestamp)) {
return false;
}
ValueTimestamp x = (ValueTimestamp) other;
return dateValue == x.dateValue && nanos == x.nanos;
}
public Value add(Value v) {
long zeroTime = ValueTime.get(new Time(0)).getDate().getTime();
long t = value.getTime() - zeroTime + v.getTimestamp().getTime();
Timestamp ts = new Timestamp(t);
return ValueTimestamp.get(ts);
// TODO test sum of timestamps, dates, times
ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP);
long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue);
long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue);
return DateTimeUtils.normalize(d1 + d2, nanos + t.nanos);
}
public Value subtract(Value v) {
long zeroTime = ValueTime.get(new Time(0)).getDate().getTime();
long t = value.getTime() + zeroTime - v.getTimestamp().getTime();
Timestamp ts = new Timestamp(t);
return ValueTimestamp.get(ts);
// TODO test sum of timestamps, dates, times
ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP);
long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue);
long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue);
return DateTimeUtils.normalize(d1 - d2, nanos - t.nanos);
}
}
......@@ -339,7 +339,8 @@ java org.h2.test.TestAll timer
System.setProperty("h2.delayWrongPasswordMin", "0");
System.setProperty("h2.delayWrongPasswordMax", "0");
// System.setProperty("h2.storeLocalTime", "true");
int todoTestBoth;
// System.setProperty("h2.storeLocalTime", "true");
// speedup
// System.setProperty("h2.syncMethod", "");
......
......@@ -156,6 +156,7 @@ public class TestCompatibility extends TestBase {
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello'), (2, 'World')");
org.h2.mode.FunctionsMySQL.register(conn);
assertResult("0", stat, "SELECT UNIX_TIMESTAMP('1970-01-01 00:00:00Z')");
assertResult("1196418619", stat, "SELECT UNIX_TIMESTAMP('2007-11-30 10:30:19Z')");
assertResult("1196418619", stat, "SELECT UNIX_TIMESTAMP(FROM_UNIXTIME(1196418619))");
assertResult("2007 November", stat, "SELECT FROM_UNIXTIME(1196300000, '%Y %M')");
......
......@@ -123,7 +123,7 @@ public class TestDateStorage extends TestBase {
}
private static void test(int year, int month, int day, int hour) {
DateTimeUtils.parseDateTime(year + "-" + month + "-" + day + " " + hour + ":00:00",
DateTimeUtils.parse(year + "-" + month + "-" + day + " " + hour + ":00:00",
Value.TIMESTAMP);
}
......
......@@ -30,6 +30,7 @@ public class TestLinkedTable extends TestBase {
* @param a ignored
*/
public static void main(String... a) throws Exception {
// System.setProperty("h2.storeLocalTime", "true");
TestBase.createCaller().init().test();
}
......
......@@ -59,7 +59,7 @@ public class TestScriptSimple extends TestBase {
while (rs.next()) {
String expected = reader.readStatement().trim();
String got = "> " + rs.getString(1);
assertEquals(expected, got);
assertEquals(sql, expected, got);
}
} else {
conn.createStatement().execute(sql);
......
......@@ -7233,7 +7233,7 @@ INSERT INTO TEST VALUES(0, '0:0:0','1-2-3','2-3-4 0:0:0');
INSERT INTO TEST VALUES(1, '01:02:03','2001-02-03','2001-02-29 0:0:0');
> exception
INSERT INTO TEST VALUES(1, '24:02:03','2001-02-03','2001-02-01 0:0:0');
INSERT INTO TEST VALUES(1, '24:62:03','2001-02-03','2001-02-01 0:0:0');
> exception
INSERT INTO TEST VALUES(1, '23:02:03','2001-04-31','2001-02-01 0:0:0');
......@@ -7269,12 +7269,12 @@ SELECT XD+1, XD-1, XD-XD FROM TEST;
SELECT ID, CAST(XT AS DATE) T2D, CAST(XTS AS DATE) TS2D,
CAST(XD AS TIME) D2T, CAST(XTS AS TIME) TS2T,
CAST(XT AS TIMESTAMP) D2TS, CAST(XD AS TIMESTAMP) D2TS FROM TEST;
> ID T2D TS2D D2T TS2T D2TS D2TS
> ---- ---------- ---------- -------- -------- --------------------- ---------------------
> 0 1970-01-01 0002-03-04 00:00:00 00:00:00 1970-01-01 00:00:00.0 0001-02-03 00:00:00.0
> 1 1970-01-01 0007-08-09 00:00:00 00:01:02 1970-01-01 01:02:03.0 0004-05-06 00:00:00.0
> 2 1970-01-01 1999-12-31 00:00:00 23:59:59 1970-01-01 23:59:59.0 1999-12-31 00:00:00.0
> null null null null null null null
> ID T2D TS2D D2T TS2T D2TS D2TS
> ---- ---------- ---------- -------- ------------ --------------------- ---------------------
> 0 1970-01-01 0002-03-04 00:00:00 00:00:00 1970-01-01 00:00:00.0 0001-02-03 00:00:00.0
> 1 1970-01-01 0007-08-09 00:00:00 00:01:02 1970-01-01 01:02:03.0 0004-05-06 00:00:00.0
> 2 1970-01-01 1999-12-31 00:00:00 23:59:59.123 1970-01-01 23:59:59.0 1999-12-31 00:00:00.0
> null null null null null null null
> rows: 4
SCRIPT SIMPLE NOPASSWORDS NOSETTINGS;
......@@ -9331,10 +9331,10 @@ select length(curdate()) c1, length(current_date()) c2, substring(curdate(), 5,
> 10 10 -
> rows: 1
select length(curtime()) c1, length(current_time()) c2, substring(curtime(), 3, 1) c3 from test;
> C1 C2 C3
> -- -- --
> 8 8 :
select length(curtime())>=8 c1, length(current_time())>=8 c2, substring(curtime(), 3, 1) c3 from test;
> C1 C2 C3
> ---- ---- --
> TRUE TRUE :
> rows: 1
select length(now())>20 c1, length(current_timestamp())>20 c2, length(now(0))>20 c3, length(now(2))>20 c4, substring(now(5), 20, 1) c5 from test;
......
......@@ -38,15 +38,105 @@ public class TestDate extends TestBase {
* @param a ignored
*/
public static void main(String... a) throws Exception {
System.setProperty("h2.storeLocalTime", "true");
// System.setProperty("h2.storeLocalTime", "true");
TestBase.createCaller().init().test();
}
public void test() throws SQLException {
testValidDate();
testValidTime();
testCalculateLocalMillis();
testTimeOperationsAcrossTimeZones();
testDateTimeUtils();
}
private void testValidTime() {
for (int h = -1; h < 28; h++) {
for (int m = -1; m < 65; m++) {
for (int s = -1; s < 65; s++) {
boolean valid = DateTimeUtils.isValidTime(h, m, s);
boolean expected = h >= 0 && h < 24 && m >= 0 && m < 60 &&
s >= 0 && s < 60;
assertEquals(expected, valid);
}
}
}
}
private void testValidDate() {
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
c.setLenient(false);
for (int y = -2000; y < 3000; y++) {
for (int m = -10; m <= 20; m++) {
for (int d = -10; d <= 40; d++) {
boolean valid = DateTimeUtils.isValidDate(y, m, d);
if (m < 1 || m > 12) {
assertFalse(valid);
} else if (d < 1 || d > 31) {
assertFalse(valid);
} else {
if (y <= 0) {
c.set(Calendar.ERA, GregorianCalendar.BC);
c.set(Calendar.YEAR, 1 - y);
} else {
c.set(Calendar.ERA, GregorianCalendar.AD);
c.set(Calendar.YEAR, y);
}
c.set(Calendar.MONTH, m - 1);
c.set(Calendar.DAY_OF_MONTH, d);
boolean expected = true;
try {
c.getTimeInMillis();
} catch (Exception e) {
expected = false;
}
if (expected != valid) {
fail(y + "-" + m + "-" + d + " expected: " + expected + " got: " + valid);
}
}
}
}
}
}
private void testCalculateLocalMillis() {
TimeZone defaultTimeZone = TimeZone.getDefault();
try {
for (TimeZone tz : TestDate.getDistinctTimeZones()) {
TimeZone.setDefault(tz);
for (int y = 1900; y < 2039; y++) {
if (y == 1993) {
// timezone change in Kwajalein
} else if (y == 1995) {
// timezone change in Enderbury and Kiritimati
}
for (int m = 1; m <= 12; m++) {
for (int day = 1; day < 29; day++) {
if (y == 1582 && m == 10 && day >= 5 && day <= 14) {
continue;
}
testDate(y, m, day);
}
}
}
}
} finally {
TimeZone.setDefault(defaultTimeZone);
}
}
static void testDate(int y, int m, int day) {
long millis = DateTimeUtils.getMillis(TimeZone.getDefault(), y, m, day, 0, 0, 0, 0);
String st = new java.sql.Date(millis).toString();
int y2 = Integer.parseInt(st.substring(0, 4));
int m2 = Integer.parseInt(st.substring(5, 7));
int d2 = Integer.parseInt(st.substring(8, 10));
if (y != y2 || m != m2 || day != d2) {
String s = y + "-" + (m < 10 ? "0" + m : m) + "-" + (day < 10 ? "0" + day : day);
System.out.println(s + "<>" + st + " " + TimeZone.getDefault().getID());
}
}
private void testTimeOperationsAcrossTimeZones() {
if (!SysProperties.STORE_LOCAL_TIME) {
return;
......@@ -124,25 +214,20 @@ public class TestDate extends TestBase {
}
private void testDateTimeUtils() {
java.sql.Timestamp ts1 = (Timestamp) DateTimeUtils.parseDateTime("-999-08-07 13:14:15.16", Value.TIMESTAMP);
java.sql.Timestamp ts2 = (Timestamp) DateTimeUtils.parseDateTime("19999-08-07 13:14:15.16", Value.TIMESTAMP);
java.sql.Time t1 = DateTimeUtils.cloneAndNormalizeTime(new java.sql.Time(ts1.getTime()));
java.sql.Time t2 = DateTimeUtils.cloneAndNormalizeTime(new java.sql.Time(ts2.getTime()));
java.sql.Date d1 = DateTimeUtils.cloneAndNormalizeDate(new java.sql.Date(ts1.getTime()));
java.sql.Date d2 = DateTimeUtils.cloneAndNormalizeDate(new java.sql.Date(ts2.getTime()));
assertEquals("-999-08-07 13:14:15.16", ValueTimestamp.get(ts1).getString());
assertEquals("-999-08-07", ValueDate.get(d1).getString());
assertEquals("13:14:15", ValueTime.get(t1).getString());
assertEquals("19999-08-07 13:14:15.16", ValueTimestamp.get(ts2).getString());
assertEquals("19999-08-07", ValueDate.get(d2).getString());
assertEquals("13:14:15", ValueTime.get(t2).getString());
Calendar cal = Calendar.getInstance();
cal.setTime(t1);
assertEquals(GregorianCalendar.AD, cal.get(Calendar.ERA));
cal.setTime(t2);
assertEquals(GregorianCalendar.AD, cal.get(Calendar.ERA));
java.sql.Timestamp ts1a = DateTimeUtils.convertTimestampToCalendar(ts1, Calendar.getInstance());
java.sql.Timestamp ts2a = DateTimeUtils.convertTimestampToCalendar(ts2, Calendar.getInstance());
ValueTimestamp ts1 = (ValueTimestamp) DateTimeUtils.parse("-999-08-07 13:14:15.16", Value.TIMESTAMP);
ValueTimestamp ts2 = (ValueTimestamp) DateTimeUtils.parse("19999-08-07 13:14:15.16", Value.TIMESTAMP);
ValueTime t1 = (ValueTime) ts1.convertTo(Value.TIME);
ValueTime t2 = (ValueTime) ts2.convertTo(Value.TIME);
ValueDate d1 = (ValueDate) ts1.convertTo(Value.DATE);
ValueDate d2 = (ValueDate) ts2.convertTo(Value.DATE);
assertEquals("-999-08-07 13:14:15.16", ts1.getString());
assertEquals("-999-08-07", d1.getString());
assertEquals("13:14:15.16", t1.getString());
assertEquals("19999-08-07 13:14:15.16", ts2.getString());
assertEquals("19999-08-07", d2.getString());
assertEquals("13:14:15.16", t2.getString());
java.sql.Timestamp ts1a = DateTimeUtils.convertTimestampToCalendar(ts1.getTimestamp(), Calendar.getInstance());
java.sql.Timestamp ts2a = DateTimeUtils.convertTimestampToCalendar(ts2.getTimestamp(), Calendar.getInstance());
assertEquals("-999-08-07 13:14:15.16", ValueTimestamp.get(ts1a).getString());
assertEquals("19999-08-07 13:14:15.16", ValueTimestamp.get(ts2a).getString());
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论