Unverified 提交 f9dda484 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1359 from katzyn/OffsetDateTime

Add system property to return OffsetDateTime from ResultSet.getObject()
...@@ -71,6 +71,16 @@ public class SysProperties { ...@@ -71,6 +71,16 @@ public class SysProperties {
public static final String USER_HOME = public static final String USER_HOME =
Utils.getProperty("user.home", ""); Utils.getProperty("user.home", "");
/**
* System property {@code h2.preview} (default: false).
* <p>
* Controls default values of other properties. If {@code true} default
* values of other properties are changed to planned defaults for the 1.5.x
* versions of H2. Some other functionality may be also enabled or disabled.
* </p>
*/
public static final boolean PREVIEW = Utils.getProperty("h2.preview", false);
/** /**
* System property <code>h2.allowedClasses</code> (default: *).<br /> * System property <code>h2.allowedClasses</code> (default: *).<br />
* Comma separated list of class names or prefixes. * Comma separated list of class names or prefixes.
...@@ -325,23 +335,53 @@ public class SysProperties { ...@@ -325,23 +335,53 @@ public class SysProperties {
Utils.getProperty("h2.oldStyleOuterJoin", false); Utils.getProperty("h2.oldStyleOuterJoin", false);
/** /**
* System property {@code h2.oldResultSetGetObject}, {@code true} by default. * System property {@code h2.oldResultSetGetObject}, {@code true} by default
* Return {@code Byte} and {@code Short} instead of {@code Integer} from * unless {@code h2.preview} is enabled.
* {@code ResultSet#getObject(...)} for {@code TINYINT} and {@code SMALLINT} * <p>
* values. * If {@code true} return {@code Byte} and {@code Short} from
* {@code ResultSet#getObject(int)} and {@code ResultSet#getObject(String)}
* for {@code TINYINT} and {@code SMALLINT} values.
* </p>
* <p>
* If {@code false} return {@code Integer} for them as specified in JDBC
* specification (see Mapping from JDBC Types to Java Object Types).
* </p>
*/ */
public static final boolean OLD_RESULT_SET_GET_OBJECT = public static final boolean OLD_RESULT_SET_GET_OBJECT = Utils.getProperty("h2.oldResultSetGetObject", !PREVIEW);
Utils.getProperty("h2.oldResultSetGetObject", true);
/** /**
* System property {@code h2.bigDecimalIsDecimal}, {@code true} by default. If * System property {@code h2.bigDecimalIsDecimal}, {@code true} by default
* {@code true} map {@code BigDecimal} to {@code DECIMAL} type, if {@code false} * unless {@code h2.preview} is enabled.
* map it to {@code NUMERIC} as specified in JDBC specification (see Mapping * <p>
* from Java Object Types to JDBC Types). * If {@code true} map {@code BigDecimal} to {@code DECIMAL} type.
* <p>
* <p>
* If {@code false} map {@code BigDecimal} to {@code NUMERIC} as specified
* in JDBC specification (see Mapping from Java Object Types to JDBC Types).
* </p>
*/ */
public static final boolean BIG_DECIMAL_IS_DECIMAL = public static final boolean BIG_DECIMAL_IS_DECIMAL = Utils.getProperty("h2.bigDecimalIsDecimal", !PREVIEW);
Utils.getProperty("h2.bigDecimalIsDecimal", true);
/**
* System property {@code h2.returnOffsetDateTime}, {@code false} by default
* unless {@code h2.preview} is enabled.
* <p>
* If {@code true} {@link java.sql.ResultSet#getObject(int)} and
* {@link java.sql.ResultSet#getObject(String)} return
* {@code TIMESTAMP WITH TIME ZONE} values as
* {@code java.time.OffsetDateTime}.
* </p>
* <p>
* If {@code false} return them as {@code org.h2.api.TimestampWithTimeZone}
* instead.
* </p>
* <p>
* This property has effect only on Java 8 / Android API 26 and later
* versions. Without JSR-310 {@code org.h2.api.TimestampWithTimeZone} is
* used unconditionally.
* </p>
*/
public static final boolean RETURN_OFFSET_DATE_TIME = Utils.getProperty("h2.returnOffsetDateTime", PREVIEW);
/** /**
* System property {@code h2.unlimitedTimeRange}, {@code false} by default. * System property {@code h2.unlimitedTimeRange}, {@code false} by default.
......
...@@ -178,7 +178,7 @@ public class JdbcParameterMetaData extends TraceObject implements ...@@ -178,7 +178,7 @@ public class JdbcParameterMetaData extends TraceObject implements
if (type == Value.UNKNOWN) { if (type == Value.UNKNOWN) {
type = Value.STRING; type = Value.STRING;
} }
return DataType.getTypeClassName(type); return DataType.getTypeClassName(type, false);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
......
...@@ -59,6 +59,7 @@ import org.h2.value.ValueShort; ...@@ -59,6 +59,7 @@ import org.h2.value.ValueShort;
import org.h2.value.ValueString; import org.h2.value.ValueString;
import org.h2.value.ValueTime; import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp; import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
/** /**
* <p> * <p>
...@@ -3915,21 +3916,19 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS ...@@ -3915,21 +3916,19 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
return type.cast(value.getBytes()); return type.cast(value.getBytes());
} else if (type == java.sql.Array.class) { } else if (type == java.sql.Array.class) {
int id = getNextId(TraceObject.ARRAY); int id = getNextId(TraceObject.ARRAY);
return type.cast(value == ValueNull.INSTANCE ? null : new JdbcArray(conn, value, id)); return type.cast(new JdbcArray(conn, value, id));
} else if (type == Blob.class) { } else if (type == Blob.class) {
int id = getNextId(TraceObject.BLOB); int id = getNextId(TraceObject.BLOB);
return type.cast(value == ValueNull.INSTANCE return type.cast(new JdbcBlob(conn, value, JdbcLob.State.WITH_VALUE, id));
? null : new JdbcBlob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == Clob.class) { } else if (type == Clob.class) {
int id = getNextId(TraceObject.CLOB); int id = getNextId(TraceObject.CLOB);
return type.cast(value == ValueNull.INSTANCE return type.cast(new JdbcClob(conn, value, JdbcLob.State.WITH_VALUE, id));
? null : new JdbcClob(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == SQLXML.class) { } else if (type == SQLXML.class) {
int id = getNextId(TraceObject.SQLXML); int id = getNextId(TraceObject.SQLXML);
return type.cast(value == ValueNull.INSTANCE return type.cast(new JdbcSQLXML(conn, value, JdbcLob.State.WITH_VALUE, id));
? null : new JdbcSQLXML(conn, value, JdbcLob.State.WITH_VALUE, id));
} else if (type == TimestampWithTimeZone.class) { } else if (type == TimestampWithTimeZone.class) {
return type.cast(value.convertTo(Value.TIMESTAMP_TZ).getObject()); ValueTimestampTimeZone v = (ValueTimestampTimeZone) value.convertTo(Value.TIMESTAMP_TZ);
return type.cast(new TimestampWithTimeZone(v.getDateValue(), v.getTimeNanos(), v.getTimeZoneOffsetMins()));
} else if (DataType.isGeometryClass(type)) { } else if (DataType.isGeometryClass(type)) {
return type.cast(value.convertTo(Value.GEOMETRY).getObject()); return type.cast(value.convertTo(Value.GEOMETRY).getObject());
} else if (type == LocalDateTimeUtils.LOCAL_DATE) { } else if (type == LocalDateTimeUtils.LOCAL_DATE) {
......
...@@ -371,7 +371,7 @@ public class JdbcResultSetMetaData extends TraceObject implements ...@@ -371,7 +371,7 @@ public class JdbcResultSetMetaData extends TraceObject implements
debugCodeCall("getColumnClassName", column); debugCodeCall("getColumnClassName", column);
checkColumnIndex(column); checkColumnIndex(column);
int type = result.getColumnType(--column); int type = result.getColumnType(--column);
return DataType.getTypeClassName(type); return DataType.getTypeClassName(type, true);
} catch (Exception e) { } catch (Exception e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
......
...@@ -2003,7 +2003,7 @@ public class SimpleResultSet implements ResultSet, ResultSetMetaData, ...@@ -2003,7 +2003,7 @@ public class SimpleResultSet implements ResultSet, ResultSetMetaData,
@Override @Override
public String getColumnClassName(int columnIndex) throws SQLException { public String getColumnClassName(int columnIndex) throws SQLException {
int type = DataType.getValueTypeFromResultSet(this, columnIndex); int type = DataType.getValueTypeFromResultSet(this, columnIndex);
return DataType.getTypeClassName(type); return DataType.getTypeClassName(type, true);
} }
/** /**
......
...@@ -431,7 +431,7 @@ public class LocalDateTimeUtils { ...@@ -431,7 +431,7 @@ public class LocalDateTimeUtils {
* @param offsetDateTime the OffsetDateTime to convert, not {@code null} * @param offsetDateTime the OffsetDateTime to convert, not {@code null}
* @return the value * @return the value
*/ */
public static Value offsetDateTimeToValue(Object offsetDateTime) { public static ValueTimestampTimeZone offsetDateTimeToValue(Object offsetDateTime) {
try { try {
Object localDateTime = OFFSET_DATE_TIME_TO_LOCAL_DATE_TIME.invoke(offsetDateTime); Object localDateTime = OFFSET_DATE_TIME_TO_LOCAL_DATE_TIME.invoke(offsetDateTime);
Object localDate = LOCAL_DATE_TIME_TO_LOCAL_DATE.invoke(localDateTime); Object localDate = LOCAL_DATE_TIME_TO_LOCAL_DATE.invoke(localDateTime);
......
...@@ -583,9 +583,16 @@ public class DataType { ...@@ -583,9 +583,16 @@ public class DataType {
break; break;
} }
case Value.TIMESTAMP_TZ: { case Value.TIMESTAMP_TZ: {
TimestampWithTimeZone value = (TimestampWithTimeZone) rs.getObject(columnIndex); Object obj = rs.getObject(columnIndex);
v = value == null ? (Value) ValueNull.INSTANCE : if (obj == null) {
ValueTimestampTimeZone.get(value); v = ValueNull.INSTANCE;
} else if (LocalDateTimeUtils.isJava8DateApiPresent()
&& LocalDateTimeUtils.OFFSET_DATE_TIME.isInstance(obj)) {
v = LocalDateTimeUtils.offsetDateTimeToValue(obj);
} else {
TimestampWithTimeZone value = (TimestampWithTimeZone) obj;
v = ValueTimestampTimeZone.get(value);
}
break; break;
} }
case Value.DECIMAL: { case Value.DECIMAL: {
...@@ -740,17 +747,26 @@ public class DataType { ...@@ -740,17 +747,26 @@ public class DataType {
* Get the name of the Java class for the given value type. * Get the name of the Java class for the given value type.
* *
* @param type the value type * @param type the value type
* @param forResultSet return mapping for result set
* @return the class name * @return the class name
*/ */
public static String getTypeClassName(int type) { public static String getTypeClassName(int type, boolean forResultSet) {
switch (type) { switch (type) {
case Value.BOOLEAN: case Value.BOOLEAN:
// "java.lang.Boolean"; // "java.lang.Boolean";
return Boolean.class.getName(); return Boolean.class.getName();
case Value.BYTE: case Value.BYTE:
if (forResultSet && !SysProperties.OLD_RESULT_SET_GET_OBJECT) {
// "java.lang.Integer";
return Integer.class.getName();
}
// "java.lang.Byte"; // "java.lang.Byte";
return Byte.class.getName(); return Byte.class.getName();
case Value.SHORT: case Value.SHORT:
if (forResultSet && !SysProperties.OLD_RESULT_SET_GET_OBJECT) {
// "java.lang.Integer";
return Integer.class.getName();
}
// "java.lang.Short"; // "java.lang.Short";
return Short.class.getName(); return Short.class.getName();
case Value.INT: case Value.INT:
...@@ -772,6 +788,10 @@ public class DataType { ...@@ -772,6 +788,10 @@ public class DataType {
// "java.sql.Timestamp"; // "java.sql.Timestamp";
return Timestamp.class.getName(); return Timestamp.class.getName();
case Value.TIMESTAMP_TZ: case Value.TIMESTAMP_TZ:
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
// "java.time.OffsetDateTime";
return LocalDateTimeUtils.OFFSET_DATE_TIME.getName();
}
// "org.h2.api.TimestampWithTimeZone"; // "org.h2.api.TimestampWithTimeZone";
return TimestampWithTimeZone.class.getName(); return TimestampWithTimeZone.class.getName();
case Value.BYTES: case Value.BYTES:
......
...@@ -10,8 +10,10 @@ import java.sql.SQLException; ...@@ -10,8 +10,10 @@ import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.api.TimestampWithTimeZone; import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.util.LocalDateTimeUtils;
/** /**
* Implementation of the TIMESTAMP WITH TIME ZONE data type. * Implementation of the TIMESTAMP WITH TIME ZONE data type.
...@@ -273,8 +275,10 @@ public class ValueTimestampTimeZone extends Value { ...@@ -273,8 +275,10 @@ public class ValueTimestampTimeZone extends Value {
@Override @Override
public Object getObject() { public Object getObject() {
return new TimestampWithTimeZone(dateValue, timeNanos, if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
timeZoneOffsetMins); return LocalDateTimeUtils.valueToOffsetDateTime(this);
}
return new TimestampWithTimeZone(dateValue, timeNanos, timeZoneOffsetMins);
} }
@Override @Override
......
...@@ -35,6 +35,7 @@ import java.util.Objects; ...@@ -35,6 +35,7 @@ import java.util.Objects;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.fs.FilePath; import org.h2.store.fs.FilePath;
...@@ -1028,7 +1029,8 @@ public abstract class TestBase { ...@@ -1028,7 +1029,8 @@ public abstract class TestBase {
break; break;
case Types.SMALLINT: case Types.SMALLINT:
assertEquals("SMALLINT", typeName); assertEquals("SMALLINT", typeName);
assertEquals("java.lang.Short", className); assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Short" : "java.lang.Integer",
className);
break; break;
case Types.TIMESTAMP: case Types.TIMESTAMP:
assertEquals("TIMESTAMP", typeName); assertEquals("TIMESTAMP", typeName);
......
...@@ -22,6 +22,7 @@ import java.sql.Timestamp; ...@@ -22,6 +22,7 @@ import java.sql.Timestamp;
import java.sql.Types; import java.sql.Types;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.TestDb; import org.h2.test.TestDb;
...@@ -305,7 +306,8 @@ public class TestUpdatableResultSet extends TestDb { ...@@ -305,7 +306,8 @@ public class TestUpdatableResultSet extends TestDb {
assertEquals("java.lang.String", meta.getColumnClassName(2)); assertEquals("java.lang.String", meta.getColumnClassName(2));
assertEquals("java.math.BigDecimal", meta.getColumnClassName(3)); assertEquals("java.math.BigDecimal", meta.getColumnClassName(3));
assertEquals("java.lang.Boolean", meta.getColumnClassName(4)); assertEquals("java.lang.Boolean", meta.getColumnClassName(4));
assertEquals("java.lang.Byte", meta.getColumnClassName(5)); assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Byte" : "java.lang.Integer",
meta.getColumnClassName(5));
assertEquals("[B", meta.getColumnClassName(6)); assertEquals("[B", meta.getColumnClassName(6));
assertEquals("java.sql.Date", meta.getColumnClassName(7)); assertEquals("java.sql.Date", meta.getColumnClassName(7));
assertEquals("java.sql.Time", meta.getColumnClassName(8)); assertEquals("java.sql.Time", meta.getColumnClassName(8));
...@@ -314,7 +316,8 @@ public class TestUpdatableResultSet extends TestDb { ...@@ -314,7 +316,8 @@ public class TestUpdatableResultSet extends TestDb {
assertEquals("java.lang.Float", meta.getColumnClassName(11)); assertEquals("java.lang.Float", meta.getColumnClassName(11));
assertEquals("java.lang.Long", meta.getColumnClassName(12)); assertEquals("java.lang.Long", meta.getColumnClassName(12));
assertEquals("java.lang.Integer", meta.getColumnClassName(13)); assertEquals("java.lang.Integer", meta.getColumnClassName(13));
assertEquals("java.lang.Short", meta.getColumnClassName(14)); assertEquals(SysProperties.OLD_RESULT_SET_GET_OBJECT ? "java.lang.Short" : "java.lang.Integer",
meta.getColumnClassName(14));
assertEquals("java.sql.Clob", meta.getColumnClassName(15)); assertEquals("java.sql.Clob", meta.getColumnClassName(15));
assertEquals("java.sql.Blob", meta.getColumnClassName(16)); assertEquals("java.sql.Blob", meta.getColumnClassName(16));
rs.moveToInsertRow(); rs.moveToInsertRow();
......
...@@ -14,6 +14,7 @@ import java.sql.Statement; ...@@ -14,6 +14,7 @@ import java.sql.Statement;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.api.TimestampWithTimeZone; import org.h2.api.TimestampWithTimeZone;
import org.h2.engine.SysProperties;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.TestDb; import org.h2.test.TestDb;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
...@@ -64,7 +65,7 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -64,7 +65,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
ResultSet rs = stat.executeQuery("select t1 from test"); ResultSet rs = stat.executeQuery("select t1 from test");
rs.next(); rs.next();
assertEquals("1970-01-01 12:00:00+00:15", rs.getString(1)); assertEquals("1970-01-01 12:00:00+00:15", rs.getString(1));
TimestampWithTimeZone ts = (TimestampWithTimeZone) rs.getObject(1); TimestampWithTimeZone ts = test1_getTimestamp(rs);
assertEquals(1970, ts.getYear()); assertEquals(1970, ts.getYear());
assertEquals(1, ts.getMonth()); assertEquals(1, ts.getMonth());
assertEquals(1, ts.getDay()); assertEquals(1, ts.getDay());
...@@ -76,7 +77,7 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -76,7 +77,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString()); LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
} }
rs.next(); rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1); ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear()); assertEquals(2016, ts.getYear());
assertEquals(9, ts.getMonth()); assertEquals(9, ts.getMonth());
assertEquals(24, ts.getDay()); assertEquals(24, ts.getDay());
...@@ -87,7 +88,7 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -87,7 +88,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString()); LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
} }
rs.next(); rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1); ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear()); assertEquals(2016, ts.getYear());
assertEquals(9, ts.getMonth()); assertEquals(9, ts.getMonth());
assertEquals(24, ts.getDay()); assertEquals(24, ts.getDay());
...@@ -98,7 +99,7 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -98,7 +99,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString()); LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
} }
rs.next(); rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1); ts = test1_getTimestamp(rs);
assertEquals(2016, ts.getYear()); assertEquals(2016, ts.getYear());
assertEquals(1, ts.getMonth()); assertEquals(1, ts.getMonth());
assertEquals(1, ts.getDay()); assertEquals(1, ts.getDay());
...@@ -107,7 +108,7 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -107,7 +108,7 @@ public class TestTimeStampWithTimeZone extends TestDb {
LocalDateTimeUtils.OFFSET_DATE_TIME).toString()); LocalDateTimeUtils.OFFSET_DATE_TIME).toString());
} }
rs.next(); rs.next();
ts = (TimestampWithTimeZone) rs.getObject(1); ts = test1_getTimestamp(rs);
assertEquals(2015, ts.getYear()); assertEquals(2015, ts.getYear());
assertEquals(12, ts.getMonth()); assertEquals(12, ts.getMonth());
assertEquals(31, ts.getDay()); assertEquals(31, ts.getDay());
...@@ -124,6 +125,11 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -124,6 +125,11 @@ public class TestTimeStampWithTimeZone extends TestDb {
// Types.TIMESTAMP_WITH_TIMEZONE // Types.TIMESTAMP_WITH_TIMEZONE
// once Java 1.8 is required. // once Java 1.8 is required.
assertEquals(2014, columnType); assertEquals(2014, columnType);
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
assertEquals("java.time.OffsetDateTime", metaData.getColumnClassName(1));
} else {
assertEquals("org.h2.api.TimestampWithTimeZone", metaData.getColumnClassName(1));
}
rs.close(); rs.close();
...@@ -135,6 +141,16 @@ public class TestTimeStampWithTimeZone extends TestDb { ...@@ -135,6 +141,16 @@ public class TestTimeStampWithTimeZone extends TestDb {
conn.close(); conn.close();
} }
private static TimestampWithTimeZone test1_getTimestamp(ResultSet rs) throws SQLException {
Object o = rs.getObject(1);
if (SysProperties.RETURN_OFFSET_DATE_TIME && LocalDateTimeUtils.isJava8DateApiPresent()) {
ValueTimestampTimeZone value = LocalDateTimeUtils.offsetDateTimeToValue(o);
return new TimestampWithTimeZone(value.getDateValue(), value.getTimeNanos(),
value.getTimeZoneOffsetMins());
}
return (TimestampWithTimeZone) o;
}
private void test2() { private void test2() {
ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-01 12:00:00.00+00:15"); ValueTimestampTimeZone a = ValueTimestampTimeZone.parse("1970-01-01 12:00:00.00+00:15");
ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 12:00:01.00+01:15"); ValueTimestampTimeZone b = ValueTimestampTimeZone.parse("1970-01-01 12:00:01.00+01:15");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论