/* Copyright (c) 2001-2018, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb.types;
import java.math.
BigDecimal;
import java.text.
SimpleDateFormat;
import java.util.
Calendar;
import java.util.
Date;
import org.hsqldb.
HsqlDateTime;
import org.hsqldb.
HsqlException;
import org.hsqldb.
OpTypes;
import org.hsqldb.
Session;
import org.hsqldb.
SessionInterface;
import org.hsqldb.
Tokens;
import org.hsqldb.error.
Error;
import org.hsqldb.error.
ErrorCode;
import org.hsqldb.lib.
StringConverter;
/**
* Type subclass for DATE, TIME and TIMESTAMP.<p>
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 2.4.1
* @since 1.9.0
*/
public final class
DateTimeType extends
DTIType {
public final boolean
withTimeZone;
private
String nameString;
public static final long
epochSeconds =
HsqlDateTime.
getDateSeconds("1-01-01");
public static final
TimestampData epochTimestamp =
new
TimestampData(
epochSeconds);
public static final long
limitSeconds =
HsqlDateTime.
getDateSeconds("10000-01-01");
public
DateTimeType(int
typeGroup, int
type, int
scale) {
super(
typeGroup,
type, 0,
scale);
withTimeZone =
type ==
Types.
SQL_TIME_WITH_TIME_ZONE
||
type ==
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE;
nameString =
getNameStringPrivate();
}
public int
displaySize() {
switch (
typeCode) {
case
Types.
SQL_DATE :
return 10;
case
Types.
SQL_TIME :
return 8 + (
scale == 0 ? 0
:
scale + 1);
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return 8 + (
scale == 0 ? 0
:
scale + 1) + 6;
case
Types.
SQL_TIMESTAMP :
return 19 + (
scale == 0 ? 0
:
scale + 1);
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return 19 + (
scale == 0 ? 0
:
scale + 1) + 6;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public int
getJDBCTypeCode() {
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return
Types.
TIME_WITH_TIMEZONE;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return
Types.
TIMESTAMP_WITH_TIMEZONE;
default :
// JDBC numbers happen to be the same as SQL
return
typeCode;
}
}
public
Class getJDBCClass() {
switch (
typeCode) {
case
Types.
SQL_DATE :
return java.sql.
Date.class;
case
Types.
SQL_TIME :
return java.sql.
Time.class;
case
Types.
SQL_TIMESTAMP :
return java.sql.
Timestamp.class;
//#ifdef JAVA8
/*
case Types.SQL_TIME_WITH_TIME_ZONE :
return java.time.OffsetTime.class;
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
return java.time.OffsetDateTime.class;
*/
//#else
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return java.sql.
Time.class;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return java.sql.
Timestamp.class;
//#endif JAVA8
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
String getJDBCClassName() {
switch (
typeCode) {
case
Types.
SQL_DATE :
return "java.sql.Date";
case
Types.
SQL_TIME :
return "java.sql.Time";
case
Types.
SQL_TIMESTAMP :
return "java.sql.Timestamp";
//#ifdef JAVA8
/*
case Types.SQL_TIME_WITH_TIME_ZONE :
return "java.time.OffsetTime";
case Types.SQL_TIMESTAMP_WITH_TIME_ZONE :
return "java.time.OffsetDateTime";
*/
//#else
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return "java.sql.Time";
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return "java.sql.Timestamp";
//#endif JAVA8
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public int
getJDBCPrecision() {
return this.
displaySize();
}
public int
getSQLGenericTypeCode() {
return
Types.
SQL_DATETIME;
}
public
String getNameString() {
return
nameString;
}
public boolean
canCompareDirect(
Type otherType) {
return
typeCode ==
otherType.
typeCode;
}
private
String getNameStringPrivate() {
switch (
typeCode) {
case
Types.
SQL_DATE :
return
Tokens.
T_DATE;
case
Types.
SQL_TIME :
return
Tokens.
T_TIME;
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return
Tokens.
T_TIME + ' ' +
Tokens.
T_WITH + ' '
+
Tokens.
T_TIME + ' ' +
Tokens.
T_ZONE;
case
Types.
SQL_TIMESTAMP :
return
Tokens.
T_TIMESTAMP;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return
Tokens.
T_TIMESTAMP + ' ' +
Tokens.
T_WITH + ' '
+
Tokens.
T_TIME + ' ' +
Tokens.
T_ZONE;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
String getDefinition() {
String token;
switch (
typeCode) {
case
Types.
SQL_DATE :
return
Tokens.
T_DATE;
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME :
if (
scale ==
DTIType.
defaultTimeFractionPrecision) {
return
getNameString();
}
token =
Tokens.
T_TIME;
break;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP :
if (
scale ==
DTIType.
defaultTimestampFractionPrecision) {
return
getNameString();
}
token =
Tokens.
T_TIMESTAMP;
break;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
StringBuffer sb = new
StringBuffer(16);
sb.
append(
token);
sb.
append('(');
sb.
append(
scale);
sb.
append(')');
if (
withTimeZone) {
sb.
append(' ' +
Tokens.
T_WITH + ' ' +
Tokens.
T_TIME + ' '
+
Tokens.
T_ZONE);
}
return
sb.
toString();
}
public boolean
isDateTimeType() {
return true;
}
public boolean
isDateOrTimestampType() {
switch (
typeCode) {
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return true;
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return false;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public boolean
isTimestampType() {
switch (
typeCode) {
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return true;
case
Types.
SQL_DATE :
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return false;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public boolean
isTimeType() {
switch (
typeCode) {
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_DATE :
return false;
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return true;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public boolean
isDateTimeTypeWithZone() {
return
withTimeZone;
}
public boolean
acceptsFractionalPrecision() {
return
typeCode !=
Types.
SQL_DATE;
}
public
Type getAggregateType(
Type other) {
if (
other == null) {
return this;
}
if (
other ==
SQL_ALL_TYPES) {
return this;
}
// DATE with DATE returned here
if (
typeCode ==
other.
typeCode) {
return
scale >=
other.
scale ? this
:
other;
}
if (
other.
typeCode ==
Types.
SQL_ALL_TYPES) {
return this;
}
if (
other.
isCharacterType()) {
return
other.
getAggregateType(this);
}
if (!
other.
isDateTimeType()) {
throw
Error.
error(
ErrorCode.
X_42562);
}
DateTimeType otherType = (
DateTimeType)
other;
// DATE with TIME caught here
if (
otherType.
startIntervalType >
endIntervalType
||
startIntervalType >
otherType.
endIntervalType) {
throw
Error.
error(
ErrorCode.
X_42562);
}
int
newType =
typeCode;
int
scale = this.
scale >
otherType.
scale ? this.
scale
:
otherType.
scale;
boolean
zone =
withTimeZone ||
otherType.
withTimeZone;
int
startType =
otherType.
startIntervalType >
startIntervalType
?
startIntervalType
:
otherType.
startIntervalType;
if (
startType ==
Types.
SQL_INTERVAL_HOUR) {
newType =
zone ?
Types.
SQL_TIME_WITH_TIME_ZONE
:
Types.
SQL_TIME;
} else {
newType =
zone ?
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE
:
Types.
SQL_TIMESTAMP;
}
return
getDateTimeType(
newType,
scale);
}
public
Type getCombinedType(
Session session,
Type other, int
operation) {
switch (
operation) {
case
OpTypes.
EQUAL :
case
OpTypes.
GREATER :
case
OpTypes.
GREATER_EQUAL :
case
OpTypes.
SMALLER_EQUAL :
case
OpTypes.
SMALLER :
case
OpTypes.
NOT_EQUAL : {
if (
typeCode ==
other.
typeCode) {
return this;
}
if (
other.
typeCode ==
Types.
SQL_ALL_TYPES) {
return this;
}
if (!
other.
isDateTimeType()) {
throw
Error.
error(
ErrorCode.
X_42562);
}
DateTimeType otherType = (
DateTimeType)
other;
// DATE with TIME caught here
if (
otherType.
startIntervalType >
endIntervalType
||
startIntervalType >
otherType.
endIntervalType) {
throw
Error.
error(
ErrorCode.
X_42562);
}
int
newType =
typeCode;
int
scale = this.
scale >
otherType.
scale ? this.
scale
:
otherType
.
scale;
boolean
zone =
withTimeZone ||
otherType.
withTimeZone;
int
startType =
otherType.
startIntervalType
>
startIntervalType ?
startIntervalType
:
otherType
.
startIntervalType;
if (
startType ==
Types.
SQL_INTERVAL_HOUR) {
newType =
zone ?
Types.
SQL_TIME_WITH_TIME_ZONE
:
Types.
SQL_TIME;
} else {
newType =
zone ?
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE
:
Types.
SQL_TIMESTAMP;
}
return
getDateTimeType(
newType,
scale);
}
case
OpTypes.
ADD :
case
OpTypes.
SUBTRACT :
if (
other.
isIntervalType()) {
if (
typeCode !=
Types.
SQL_DATE &&
other.
scale >
scale) {
return
getDateTimeType(
typeCode,
other.
scale);
}
return this;
} else if (
other.
isDateTimeType()) {
if (
operation ==
OpTypes.
SUBTRACT) {
if (
other.
typeComparisonGroup ==
typeComparisonGroup) {
if (
typeCode ==
Types.
SQL_DATE) {
return
Type.
SQL_INTERVAL_DAY_MAX_PRECISION;
} else {
return
Type
.
SQL_INTERVAL_DAY_TO_SECOND_MAX_PRECISION;
}
}
}
} else if (
other.
isNumberType()) {
return this;
}
break;
default :
}
throw
Error.
error(
ErrorCode.
X_42562);
}
public int
compare(
Session session,
Object a,
Object b) {
long
diff;
if (
a ==
b) {
return 0;
}
if (
a == null) {
return -1;
}
if (
b == null) {
return 1;
}
switch (
typeCode) {
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
diff = ((
TimeData)
a).
getSeconds()
- ((
TimeData)
b).
getSeconds();
if (
diff == 0) {
diff = ((
TimeData)
a).
getNanos()
- ((
TimeData)
b).
getNanos();
}
return
diff == 0 ? 0
:
diff > 0 ? 1
: -1;
}
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
diff = ((
TimestampData)
a).
getSeconds()
- ((
TimestampData)
b).
getSeconds();
if (
diff == 0) {
diff = ((
TimestampData)
a).
getNanos()
- ((
TimestampData)
b).
getNanos();
}
return
diff == 0 ? 0
:
diff > 0 ? 1
: -1;
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
Object convertToTypeLimits(
SessionInterface session,
Object a) {
if (
a == null) {
return null;
}
if (
scale ==
maxFractionPrecision) {
return
a;
}
switch (
typeCode) {
case
Types.
SQL_DATE :
return
a;
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME : {
TimeData ti = (
TimeData)
a;
int
nanos =
ti.
getNanos();
int
newNanos =
scaleNanos(
nanos);
if (
newNanos ==
nanos) {
return
ti;
}
return new
TimeData(
ti.
getSeconds(),
newNanos,
ti.
getZone());
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP : {
TimestampData ts = (
TimestampData)
a;
int
nanos =
ts.
getNanos();
int
newNanos =
scaleNanos(
nanos);
if (
newNanos ==
nanos) {
return
ts;
}
return new
TimestampData(
ts.
getSeconds(),
newNanos,
ts.
getZone());
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
int
scaleNanos(int
nanos) {
int
divisor =
nanoScaleFactors[
scale];
return (
nanos /
divisor) *
divisor;
}
public
Object convertToType(
SessionInterface session,
Object a,
Type otherType) {
if (
a == null) {
return
a;
}
switch (
otherType.
typeCode) {
case
Types.
SQL_CLOB :
a =
a.
toString();
//fall through
case
Types.
SQL_CHAR :
case
Types.
SQL_VARCHAR :
switch (this.
typeCode) {
case
Types.
SQL_DATE :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP : {
try {
return
session.
getScanner()
.
convertToDatetimeInterval(
session,
(
String)
a, this);
} catch (
HsqlException e) {
return
convertToDatetimeSpecial(
session,
(
String)
a, this);
}
}
}
break;
case
Types.
SQL_DATE :
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
break;
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
switch (this.
typeCode) {
case
Types.
SQL_DATE :
switch (
otherType.
typeCode) {
case
Types.
SQL_DATE :
return
a;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
long
seconds = ((
TimestampData)
a).
getSeconds()
+ ((
TimestampData)
a).
getZone();
long
millis =
HsqlDateTime.
getNormalisedDate(
session.
getCalendarGMT(),
seconds * 1000);
return new
TimestampData(
millis / 1000);
}
case
Types.
SQL_TIMESTAMP : {
long
l =
HsqlDateTime.
getNormalisedDate(
session.
getCalendarGMT(),
((
TimestampData)
a).
getSeconds() * 1000);
return new
TimestampData(
l / 1000);
}
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
case
Types.
SQL_TIME_WITH_TIME_ZONE :
switch (
otherType.
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
return
convertToTypeLimits(
session,
a);
case
Types.
SQL_TIME : {
TimeData ti = (
TimeData)
a;
return new
TimeData(
ti.
getSeconds() -
session.
getZoneSeconds(),
scaleNanos(
ti.
getNanos()),
session.
getZoneSeconds());
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
TimestampData ts = (
TimestampData)
a;
long
seconds =
HsqlDateTime.
convertToNormalisedTime(
ts.
getSeconds() * 1000) / 1000;
return new
TimeData((int) (
seconds),
scaleNanos(
ts.
getNanos()),
ts.
getZone());
}
case
Types.
SQL_TIMESTAMP : {
TimestampData ts = (
TimestampData)
a;
long
seconds =
ts.
getSeconds()
-
session.
getZoneSeconds();
seconds =
HsqlDateTime.
convertToNormalisedTime(
seconds * 1000,
session.
getCalendarGMT()) / 1000;
return new
TimeData((int) (
seconds),
scaleNanos(
ts.
getNanos()),
session.
getZoneSeconds());
}
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
case
Types.
SQL_TIME :
switch (
otherType.
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
TimeData ti = (
TimeData)
a;
return new
TimeData(
ti.
getSeconds() +
ti.
getZone(),
scaleNanos(
ti.
getNanos()), 0);
}
case
Types.
SQL_TIME :
return
convertToTypeLimits(
session,
a);
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
TimestampData ts = (
TimestampData)
a;
long
seconds =
ts.
getSeconds() +
ts.
getZone();
seconds =
HsqlDateTime.
convertToNormalisedTime(
seconds * 1000,
session.
getCalendarGMT()) / 1000;
return new
TimeData((int) (
seconds),
scaleNanos(
ts.
getNanos()), 0);
}
case
Types.
SQL_TIMESTAMP :
TimestampData ts = (
TimestampData)
a;
long
seconds =
HsqlDateTime.
convertToNormalisedTime(
ts.
getSeconds() * 1000,
session.
getCalendarGMT()) / 1000;
return new
TimeData((int) (
seconds),
scaleNanos(
ts.
getNanos()));
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
switch (
otherType.
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
TimeData ti = (
TimeData)
a;
long
seconds =
session.
getCurrentDate().
getSeconds()
+
ti.
getSeconds();
return new
TimestampData(
seconds,
scaleNanos(
ti.
getNanos()),
ti.
getZone());
}
case
Types.
SQL_TIME : {
TimeData ti = (
TimeData)
a;
long
seconds =
session.
getCurrentDate().
getSeconds()
+
ti.
getSeconds()
-
session.
getZoneSeconds();
return new
TimestampData(
seconds,
scaleNanos(
ti.
getNanos()),
session.
getZoneSeconds());
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return
convertToTypeLimits(
session,
a);
case
Types.
SQL_TIMESTAMP : {
TimestampData ts = (
TimestampData)
a;
long
seconds =
ts.
getSeconds()
-
session.
getZoneSeconds();
return new
TimestampData(
seconds,
scaleNanos(
ts.
getNanos()),
session.
getZoneSeconds());
}
case
Types.
SQL_DATE : {
TimestampData ts = (
TimestampData)
a;
return new
TimestampData(
ts.
getSeconds(), 0,
session.
getZoneSeconds());
}
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
case
Types.
SQL_TIMESTAMP :
switch (
otherType.
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
TimeData ti = (
TimeData)
a;
long
seconds =
session.
getCurrentDate().
getSeconds()
+
ti.
getSeconds()
-
session.
getZoneSeconds();
return new
TimestampData(
seconds,
scaleNanos(
ti.
getNanos()),
session.
getZoneSeconds());
}
case
Types.
SQL_TIME : {
TimeData ti = (
TimeData)
a;
long
seconds =
session.
getCurrentDate().
getSeconds()
+
ti.
getSeconds();
return new
TimestampData(
seconds,
scaleNanos(
ti.
getNanos()));
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
TimestampData ts = (
TimestampData)
a;
long
seconds =
ts.
getSeconds() +
ts.
getZone();
return new
TimestampData(
seconds,
scaleNanos(
ts.
getNanos()));
}
case
Types.
SQL_TIMESTAMP :
return
convertToTypeLimits(
session,
a);
case
Types.
SQL_DATE :
return
a;
default :
throw
Error.
error(
ErrorCode.
X_42561);
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
Object convertToDefaultType(
SessionInterface session,
Object a) {
Type otherType =
a instanceof
TimeData ?
Type.
SQL_TIME
:
Type.
SQL_TIMESTAMP;
return
convertToType(
session,
a,
otherType);
}
/** @todo - check the time zone conversion */
public
Object convertJavaToSQL(
SessionInterface session,
Object a) {
if (
a == null) {
return null;
}
switch (
typeCode) {
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
if (
a instanceof java.sql.
Date) {
break;
}
if (
a instanceof java.util.
Date) {
long
millis;
int
nanos = 0;
int
zoneSeconds = 0;
if (
typeCode ==
Types.
SQL_TIME) {
millis =
HsqlDateTime.
convertMillisFromCalendar(
session.
getCalendarGMT(),
session.
getCalendar(),
((java.util.
Date)
a).
getTime());
} else {
millis = ((java.util.
Date)
a).
getTime();
zoneSeconds =
session.
getZoneSeconds();
}
millis =
HsqlDateTime.
getNormalisedTime(
session.
getCalendarGMT(),
millis);
if (
a instanceof java.sql.
Timestamp) {
nanos = ((java.sql.
Timestamp)
a).
getNanos();
nanos =
normaliseFraction(
nanos,
scale);
}
return new
TimeData((int)
millis / 1000,
nanos,
zoneSeconds);
}
TimeData time =
convertJavaTimeObject(
session,
a);
if (
time != null) {
return
time;
}
break;
case
Types.
SQL_DATE : {
if (
a instanceof java.sql.
Time) {
break;
}
if (
a instanceof java.util.
Date) {
long
millis;
long
seconds;
millis =
HsqlDateTime.
convertMillisFromCalendar(
session.
getCalendarGMT(),
session.
getCalendar(),
((java.util.
Date)
a).
getTime());
millis =
HsqlDateTime.
getNormalisedDate(
session.
getCalendarGMT(),
millis);
seconds =
millis / 1000;
if (
seconds <
epochSeconds ||
seconds >
limitSeconds) {
throw
Error.
error(
ErrorCode.
X_22008);
}
return new
TimestampData(
seconds);
}
TimestampData timestamp =
convertJavaTimeObject(
session,
a,
false);
if (
timestamp != null) {
return
timestamp;
}
break;
}
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
if (
a instanceof java.sql.
Time) {
break;
}
if (
a instanceof java.util.
Date) {
long
millis;
long
seconds;
int
nanos = 0;
int
zoneSeconds = 0;
if (
typeCode ==
Types.
SQL_TIMESTAMP) {
millis =
HsqlDateTime.
convertMillisFromCalendar(
session.
getCalendarGMT(),
session.
getCalendar(),
((java.util.
Date)
a).
getTime());
} else {
millis = ((java.util.
Date)
a).
getTime();
zoneSeconds =
HsqlDateTime.
getZoneMillis(
session.
getCalendar(),
millis) / 1000;
}
if (
a instanceof java.sql.
Timestamp) {
nanos = ((java.sql.
Timestamp)
a).
getNanos();
nanos =
DateTimeType.
normaliseFraction(
nanos,
scale);
}
seconds =
millis / 1000;
if (
seconds <
epochSeconds ||
seconds >
limitSeconds) {
throw
Error.
error(
ErrorCode.
X_22008);
}
return new
TimestampData(
seconds,
nanos,
zoneSeconds);
}
TimestampData timestamp =
convertJavaTimeObject(
session,
a,
true);
if (
timestamp != null) {
return
timestamp;
}
break;
}
}
throw
Error.
error(
ErrorCode.
X_42561);
}
//#ifdef JAVA8
/*
TimestampData convertJavaTimeObject(SessionInterface session, Object a, boolean timestamp) {
if (a instanceof java.time.OffsetDateTime) {
java.time.OffsetDateTime odt = (java.time.OffsetDateTime) a;
long seconds = odt.toEpochSecond();
int nanos = 0;
int zoneSeconds = 0;
if(timestamp) {
nanos = odt.getNano();
nanos = DateTimeType.normaliseFraction(nanos, scale);
if(withTimeZone) {
zoneSeconds = odt.get(java.time.temporal.ChronoField.OFFSET_SECONDS);
}
} else {
seconds = HsqlDateTime.getNormalisedDate(session.getCalendarGMT(),seconds * 1000) / 1000;
}
return new TimestampData(seconds, nanos, zoneSeconds);
} else if (a instanceof java.time.LocalDateTime) {
java.time.LocalDateTime odt = (java.time.LocalDateTime) a;
int year = odt.getYear();
int month = odt.getMonthValue() - 1;
int day = odt.getDayOfMonth();
int hour = 0;
int minute = 0;
int second = 0;
int nanos = 0;
int zoneSeconds = 0;
if(timestamp) {
hour = odt.getHour();
minute = odt.getMinute();
second = odt.getSecond();
nanos = odt.getNano();
nanos = DateTimeType.normaliseFraction(nanos, scale);
if(withTimeZone) {
zoneSeconds = session.getZoneSeconds();
}
}
Calendar cal = session.getCalendarGMT();
cal.clear();
cal.set(year, month, day, hour, minute, second);
long seconds = cal.getTimeInMillis() / 1000;
return new TimestampData(seconds, nanos, zoneSeconds);
} else if (a instanceof java.time.LocalDate) {
java.time.LocalDate odt = (java.time.LocalDate) a;
int year = odt.getYear();
int month = odt.getMonthValue() - 1;
int day = odt.getDayOfMonth();
int zoneSeconds = 0;
if(timestamp) {
if(withTimeZone) {
zoneSeconds = session.getZoneSeconds();
}
}
Calendar cal = session.getCalendarGMT();
cal.clear();
cal.set(year, month, day);
long seconds = cal.getTimeInMillis() / 1000;
return new TimestampData(seconds, 0, zoneSeconds);
}
return null;
}
TimeData convertJavaTimeObject(SessionInterface session, Object a) {
int secondsInDay = 24 * 3600;
if (a instanceof java.time.OffsetTime) {
java.time.OffsetTime odt = (java.time.OffsetTime) a;
int zoneSeconds = 0;
int hour = odt.getHour();
int minute = odt.getMinute();
int second = odt.getSecond();
int fraction = odt.getNano();
fraction = DateTimeType.normaliseFraction(fraction, scale);
if (withTimeZone) {
zoneSeconds = odt.get(java.time.temporal.ChronoField.OFFSET_SECONDS);
}
int seconds = hour * 3600 + minute * 60 + second - zoneSeconds;
if (seconds < 0) {
seconds += secondsInDay;
} else if (seconds >=secondsInDay) {
seconds -= secondsInDay;
}
return new TimeData(seconds, fraction, zoneSeconds);
} else if (a instanceof java.time.LocalTime) {
java.time.LocalTime odt = (java.time.LocalTime) a;
long nanos = odt.toNanoOfDay();
int seconds = (int)(nanos / 1_000_000_000);
int fraction = (int)(nanos % 1_000_000_000);
fraction = DateTimeType.normaliseFraction(fraction, scale);
int zoneSeconds = 0;
if (withTimeZone) {
zoneSeconds = session.getZoneSeconds();
}
return new TimeData(seconds, fraction, zoneSeconds);
}
return null;
}
*/
//#else
TimestampData convertJavaTimeObject(
SessionInterface session,
Object a,
boolean
timestamp) {
return null;
}
TimeData convertJavaTimeObject(
SessionInterface session,
Object a) {
return null;
}
//#endif JAVA8
public
Object convertSQLToJavaGMT(
SessionInterface session,
Object a) {
long
millis;
switch (
typeCode) {
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
millis = ((
TimeData)
a).
getSeconds() * 1000L;
millis += ((
TimeData)
a).
getNanos() / 1000000;
return new java.sql.
Time(
millis);
case
Types.
SQL_DATE :
millis = ((
TimestampData)
a).
getSeconds() * 1000;
return new java.sql.
Date(
millis);
case
Types.
SQL_TIMESTAMP :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
millis = ((
TimestampData)
a).
getSeconds() * 1000;
java.sql.
Timestamp value = new java.sql.
Timestamp(
millis);
value.
setNanos(((
TimestampData)
a).
getNanos());
return
value;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
Object convertSQLToJava(
SessionInterface session,
Object a) {
if (
a == null) {
return null;
}
switch (
typeCode) {
case
Types.
SQL_TIME : {
Calendar cal =
session.
getCalendar();
long
millis =
HsqlDateTime.
convertMillisToCalendar(
cal,
((
TimeData)
a).
getMillis());
millis =
HsqlDateTime.
getNormalisedTime(
cal,
millis);
java.sql.
Time value = new java.sql.
Time(
millis);
return
value;
}
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
long
millis = ((
TimeData)
a).
getMillis();
return new java.sql.
Time(
millis);
}
case
Types.
SQL_DATE : {
Calendar cal =
session.
getCalendar();
long
millis =
HsqlDateTime.
convertMillisToCalendar(
cal,
((
TimestampData)
a).
getMillis());
// millis = HsqlDateTime.getNormalisedDate(cal, millis);
java.sql.
Date value = new java.sql.
Date(
millis);
return
value;
}
case
Types.
SQL_TIMESTAMP : {
Calendar cal =
session.
getCalendar();
long
millis =
HsqlDateTime.
convertMillisToCalendar(
cal,
((
TimestampData)
a).
getMillis());
java.sql.
Timestamp value = new java.sql.
Timestamp(
millis);
value.
setNanos(((
TimestampData)
a).
getNanos());
return
value;
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
long
millis = ((
TimestampData)
a).
getMillis();
java.sql.
Timestamp value = new java.sql.
Timestamp(
millis);
value.
setNanos(((
TimestampData)
a).
getNanos());
return
value;
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public static int
normaliseTime(int
seconds) {
while (
seconds < 0) {
seconds += 24 * 60 * 60;
}
if (
seconds > 24 * 60 * 60) {
seconds %= 24 * 60 * 60;
}
return
seconds;
}
public
String convertToString(
Object a) {
boolean
zone = false;
String s;
StringBuffer sb;
if (
a == null) {
return null;
}
switch (
typeCode) {
case
Types.
SQL_DATE :
return
HsqlDateTime.
getDateString(
((
TimestampData)
a).
getSeconds());
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME : {
TimeData t = (
TimeData)
a;
int
seconds =
normaliseTime(
t.
getSeconds() +
t.
getZone());
s =
intervalSecondToString(
seconds,
t.
getNanos(), false);
if (!
withTimeZone) {
return
s;
}
sb = new
StringBuffer(
s);
s =
Type.
SQL_INTERVAL_HOUR_TO_MINUTE.
intervalSecondToString(
((
TimeData)
a).
getZone(), 0, true);
sb.
append(
s);
return
sb.
toString();
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP : {
TimestampData ts = (
TimestampData)
a;
sb = new
StringBuffer();
HsqlDateTime.
getTimestampString(
sb,
ts.
getSeconds()
+
ts.
getZone(),
ts.
getNanos(),
scale);
if (!
withTimeZone) {
return
sb.
toString();
}
s =
Type.
SQL_INTERVAL_HOUR_TO_MINUTE.
intervalSecondToString(
((
TimestampData)
a).
getZone(), 0, true);
sb.
append(
s);
return
sb.
toString();
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
String convertToSQLString(
Object a) {
if (
a == null) {
return
Tokens.
T_NULL;
}
StringBuffer sb = new
StringBuffer(32);
switch (
typeCode) {
case
Types.
SQL_DATE :
sb.
append(
Tokens.
T_DATE);
break;
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME :
sb.
append(
Tokens.
T_TIME);
break;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP :
sb.
append(
Tokens.
T_TIMESTAMP);
break;
}
sb.
append(
StringConverter.
toQuotedString(
convertToString(
a), '\'',
false));
return
sb.
toString();
}
public boolean
canConvertFrom(
Type otherType) {
if (
otherType.
typeCode ==
Types.
SQL_ALL_TYPES) {
return true;
}
if (
otherType.
isCharacterType()) {
return true;
}
if (!
otherType.
isDateTimeType()) {
return false;
}
if (
otherType.
typeCode ==
Types.
SQL_DATE) {
return
typeCode !=
Types.
SQL_TIME;
} else if (
otherType.
typeCode ==
Types.
SQL_TIME) {
return
typeCode !=
Types.
SQL_DATE;
}
return true;
}
public int
canMoveFrom(
Type otherType) {
if (
otherType == this) {
return 0;
}
if (
typeCode ==
otherType.
typeCode) {
return
scale >=
otherType.
scale ? 0
: -1;
}
return -1;
}
public
Object add(
Session session,
Object a,
Object b,
Type otherType) {
if (
a == null ||
b == null) {
return null;
}
if (
otherType.
isNumberType()) {
if (
typeCode ==
Types.
SQL_DATE) {
b = ((
NumberType)
otherType).
floor(
b);
}
b =
Type.
SQL_INTERVAL_SECOND_MAX_PRECISION.
multiply(
IntervalSecondData.
oneDay,
b);
}
switch (
typeCode) {
/** @todo - range checks for units added */
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME :
if (
b instanceof
IntervalMonthData) {
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"DateTimeType");
} else if (
b instanceof
IntervalSecondData) {
return
addSeconds((
TimeData)
a,
((
IntervalSecondData)
b).
units,
((
IntervalSecondData)
b).
nanos);
}
break;
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP :
if (
b instanceof
IntervalMonthData) {
return
addMonths(
session, (
TimestampData)
a,
((
IntervalMonthData)
b).
units);
} else if (
b instanceof
IntervalSecondData) {
return
addSeconds((
TimestampData)
a,
((
IntervalSecondData)
b).
units,
((
IntervalSecondData)
b).
nanos);
}
break;
default :
}
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
public
Object subtract(
Session session,
Object a,
Object b,
Type otherType) {
if (
a == null ||
b == null) {
return null;
}
if (
otherType.
isNumberType()) {
if (
typeCode ==
Types.
SQL_DATE) {
b = ((
NumberType)
otherType).
floor(
b);
}
b =
Type.
SQL_INTERVAL_SECOND_MAX_PRECISION.
multiply(
IntervalSecondData.
oneDay,
b);
}
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME :
if (
b instanceof
IntervalMonthData) {
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"DateTimeType");
} else if (
b instanceof
IntervalSecondData) {
return
addSeconds((
TimeData)
a,
-((
IntervalSecondData)
b).
units,
-((
IntervalSecondData)
b).
nanos);
}
break;
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP :
if (
b instanceof
IntervalMonthData) {
return
addMonths(
session, (
TimestampData)
a,
-((
IntervalMonthData)
b).
units);
} else if (
b instanceof
IntervalSecondData) {
return
addSeconds((
TimestampData)
a,
-((
IntervalSecondData)
b).
units,
-((
IntervalSecondData)
b).
nanos);
}
break;
default :
}
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
public
Object truncate(
Object a, int
part) {
if (
a == null) {
return null;
}
long
millis =
getMillis(
a);
millis =
HsqlDateTime.
getTruncatedPart(
millis,
part);
millis -=
getZoneMillis(
a);
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
millis =
HsqlDateTime.
getNormalisedTime(
millis);
//fall through
case
Types.
SQL_TIME : {
return new
TimeData((int) (
millis / 1000), 0,
((
TimeData)
a).
getZone());
}
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP : {
return new
TimestampData(
millis / 1000, 0,
((
TimestampData)
a).
getZone());
}
default :
}
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
public
Object round(
Object a, int
part) {
if (
a == null) {
return null;
}
long
millis =
getMillis(
a);
millis =
HsqlDateTime.
getRoundedPart(
millis,
part);
millis -=
getZoneMillis(
a);
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
case
Types.
SQL_TIME : {
millis =
HsqlDateTime.
getNormalisedTime(
millis);
return new
TimeData((int) (
millis / 1000), 0,
((
TimeData)
a).
getZone());
}
case
Types.
SQL_DATE :
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
case
Types.
SQL_TIMESTAMP : {
return new
TimestampData(
millis / 1000, 0,
((
TimestampData)
a).
getZone());
}
default :
}
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
public boolean
equals(
Object other) {
if (
other == this) {
return true;
}
if (
other instanceof
DateTimeType) {
return super.equals(
other)
&& ((
DateTimeType)
other).
withTimeZone ==
withTimeZone;
}
return false;
}
public int
getPart(
Session session,
Object dateTime, int
part) {
int
calendarPart;
int
increment = 0;
int
divisor = 1;
switch (
part) {
case
Types.
SQL_INTERVAL_YEAR :
calendarPart =
Calendar.
YEAR;
break;
case
Types.
SQL_INTERVAL_MONTH :
increment = 1;
calendarPart =
Calendar.
MONTH;
break;
case
Types.
SQL_INTERVAL_DAY :
case
DAY_OF_MONTH :
calendarPart =
Calendar.
DAY_OF_MONTH;
break;
case
Types.
SQL_INTERVAL_HOUR :
calendarPart =
Calendar.
HOUR_OF_DAY;
break;
case
Types.
SQL_INTERVAL_MINUTE :
calendarPart =
Calendar.
MINUTE;
break;
case
Types.
SQL_INTERVAL_SECOND :
calendarPart =
Calendar.
SECOND;
break;
case
DAY_OF_WEEK :
calendarPart =
Calendar.
DAY_OF_WEEK;
break;
case
WEEK_OF_YEAR :
calendarPart =
Calendar.
WEEK_OF_YEAR;
break;
case
SECONDS_MIDNIGHT : {
if (
typeCode ==
Types.
SQL_TIME
||
typeCode ==
Types.
SQL_TIME_WITH_TIME_ZONE) {}
else {
try {
Type target =
withTimeZone
?
Type.
SQL_TIME_WITH_TIME_ZONE
:
Type.
SQL_TIME;
dateTime =
target.
castToType(
session,
dateTime, this);
} catch (
HsqlException e) {}
}
return ((
TimeData)
dateTime).
getSeconds();
}
case
TIMEZONE_HOUR :
if (
typeCode ==
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE) {
return ((
TimestampData)
dateTime).
getZone() / 3600;
} else {
return ((
TimeData)
dateTime).
getZone() / 3600;
}
case
TIMEZONE_MINUTE :
if (
typeCode ==
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE) {
return ((
TimestampData)
dateTime).
getZone() / 60 % 60;
} else {
return ((
TimeData)
dateTime).
getZone() / 60 % 60;
}
case
TIMEZONE :
if (
typeCode ==
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE) {
return ((
TimestampData)
dateTime).
getZone() / 60;
} else {
return ((
TimeData)
dateTime).
getZone() / 60;
}
case
QUARTER :
increment = 1;
divisor = 3;
calendarPart =
Calendar.
MONTH;
break;
case
DAY_OF_YEAR :
calendarPart =
Calendar.
DAY_OF_YEAR;
break;
case
MILLISECOND :
if (this.
isDateOrTimestampType()) {
return ((
TimestampData)
dateTime).
getNanos() / 1000000;
} else {
return ((
TimeData)
dateTime).
getNanos() / 1000000;
}
case
NANOSECOND :
if (this.
isDateOrTimestampType()) {
return ((
TimestampData)
dateTime).
getNanos();
} else {
return ((
TimeData)
dateTime).
getNanos();
}
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"DateTimeType - " +
part);
}
long
millis =
getMillis(
dateTime);
return
HsqlDateTime.
getDateTimePart(
millis,
calendarPart) /
divisor
+
increment;
}
public
Object addMonthsSpecial(
Session session,
Object dateTime,
int
months) {
TimestampData ts = (
TimestampData)
dateTime;
Calendar cal =
session.
getCalendarGMT();
long
millis = (
ts.
getSeconds() +
ts.
getZone()) * 1000;
boolean
lastDay;
HsqlDateTime.
setTimeInMillis(
cal,
millis);
cal.
set(
Calendar.
DAY_OF_MONTH, 1);
cal.
add(
Calendar.
MONTH, 1);
cal.
add(
Calendar.
DAY_OF_MONTH, -1);
lastDay =
millis ==
cal.
getTimeInMillis();
HsqlDateTime.
setTimeInMillis(
cal,
millis);
cal.
add(
Calendar.
MONTH,
months);
if (
lastDay) {
cal.
set(
Calendar.
DAY_OF_MONTH, 1);
cal.
add(
Calendar.
MONTH, 1);
cal.
add(
Calendar.
DAY_OF_MONTH, -1);
}
millis =
cal.
getTimeInMillis();
return new
TimestampData(
millis / 1000, 0, 0);
}
public
Object getLastDayOfMonth(
Session session,
Object dateTime) {
TimestampData ts = (
TimestampData)
dateTime;
Calendar cal =
session.
getCalendarGMT();
long
millis = (
ts.
getSeconds() +
ts.
getZone()) * 1000;
HsqlDateTime.
setTimeInMillis(
cal,
millis);
cal.
set(
Calendar.
DAY_OF_MONTH, 1);
cal.
add(
Calendar.
MONTH, 1);
cal.
add(
Calendar.
DAY_OF_MONTH, -1);
millis =
cal.
getTimeInMillis();
return new
TimestampData(
millis / 1000, 0, 0);
}
long
getMillis(
Object dateTime) {
long
millis;
if (
typeCode ==
Types.
SQL_TIME
||
typeCode ==
Types.
SQL_TIME_WITH_TIME_ZONE) {
millis =
(((
TimeData)
dateTime).
getSeconds() + ((
TimeData)
dateTime)
.
getZone()) * 1000L;
} else {
millis =
(((
TimestampData)
dateTime)
.
getSeconds() + ((
TimestampData)
dateTime).
getZone()) * 1000;
}
return
millis;
}
long
getZoneMillis(
Object dateTime) {
long
millis;
if (
typeCode ==
Types.
SQL_TIME
||
typeCode ==
Types.
SQL_TIME_WITH_TIME_ZONE) {
millis = ((
TimeData)
dateTime).
getZone() * 1000L;
} else {
millis = ((
TimestampData)
dateTime).
getZone() * 1000L;
}
return
millis;
}
public
BigDecimal getSecondPart(
Object dateTime) {
long
seconds =
getPart(null,
dateTime,
Types.
SQL_INTERVAL_SECOND);
int
nanos = 0;
if (
typeCode ==
Types.
SQL_TIMESTAMP
||
typeCode ==
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE) {
nanos = ((
TimestampData)
dateTime).
getNanos();
} else if (
typeCode ==
Types.
SQL_TIME
||
typeCode ==
Types.
SQL_TIME_WITH_TIME_ZONE) {
nanos = ((
TimeData)
dateTime).
getNanos();
}
return
getSecondPart(
seconds,
nanos);
}
public
String getPartString(
Session session,
Object dateTime, int
part) {
String javaPattern = "";
switch (
part) {
case
DAY_NAME :
javaPattern = "EEEE";
break;
case
MONTH_NAME :
javaPattern = "MMMM";
break;
}
SimpleDateFormat format =
session.
getSimpleDateFormatGMT();
try {
format.
applyPattern(
javaPattern);
} catch (
Exception e) {}
Date date = (
Date)
convertSQLToJavaGMT(
session,
dateTime);
return
format.
format(
date);
}
public
Object getValue(long
seconds, int
nanos, int
zoneSeconds) {
switch (
typeCode) {
case
Types.
SQL_DATE :
seconds =
HsqlDateTime.
getNormalisedDate(
(
seconds +
zoneSeconds) * 1000) / 1000;
return new
TimestampData(
seconds);
case
Types.
SQL_TIME_WITH_TIME_ZONE :
seconds =
HsqlDateTime.
getNormalisedDate(
seconds * 1000)
/ 1000;
return new
TimeData((int)
seconds,
nanos,
zoneSeconds);
case
Types.
SQL_TIME :
seconds =
HsqlDateTime.
getNormalisedTime(
(
seconds +
zoneSeconds) * 1000) / 1000;
return new
TimeData((int)
seconds,
nanos);
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
return new
TimestampData(
seconds,
nanos,
zoneSeconds);
case
Types.
SQL_TIMESTAMP :
return new
TimestampData(
seconds +
zoneSeconds,
nanos);
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
DateTimeType getDateTimeTypeWithoutZone() {
if (this.
withTimeZone) {
DateTimeType type;
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE :
type = new
DateTimeType(
Types.
SQL_TIME,
Types.
SQL_TIME,
scale);
break;
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
type = new
DateTimeType(
Types.
SQL_TIMESTAMP,
Types.
SQL_TIMESTAMP,
scale);
break;
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500,
"DateTimeType");
}
type.
nameString =
nameString;
return
type;
}
return this;
}
public static
DateTimeType getDateTimeType(int
type, int
scale) {
if (
scale >
DTIType.
maxFractionPrecision) {
throw
Error.
error(
ErrorCode.
X_42592);
}
switch (
type) {
case
Types.
SQL_DATE :
return
SQL_DATE;
case
Types.
SQL_TIME :
if (
scale ==
DTIType.
defaultTimeFractionPrecision) {
return
SQL_TIME;
}
return new
DateTimeType(
Types.
SQL_TIME,
type,
scale);
case
Types.
SQL_TIME_WITH_TIME_ZONE :
if (
scale ==
DTIType.
defaultTimeFractionPrecision) {
return
SQL_TIME_WITH_TIME_ZONE;
}
return new
DateTimeType(
Types.
SQL_TIME,
type,
scale);
case
Types.
SQL_TIMESTAMP :
if (
scale ==
DTIType.
defaultTimestampFractionPrecision) {
return
SQL_TIMESTAMP;
}
if (
scale == 0) {
return
SQL_TIMESTAMP_NO_FRACTION;
}
return new
DateTimeType(
Types.
SQL_TIMESTAMP,
type,
scale);
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
if (
scale ==
DTIType.
defaultTimestampFractionPrecision) {
return
SQL_TIMESTAMP_WITH_TIME_ZONE;
}
return new
DateTimeType(
Types.
SQL_TIMESTAMP,
type,
scale);
default :
throw
Error.
runtimeError(
ErrorCode.
U_S0500, "DateTimeType");
}
}
public
Object changeZone(
Object a,
Type otherType, int
targetZone,
int
localZone) {
if (
a == null) {
return null;
}
if (
targetZone >
DTIType.
timezoneSecondsLimit
|| -
targetZone >
DTIType.
timezoneSecondsLimit) {
throw
Error.
error(
ErrorCode.
X_22009);
}
switch (
typeCode) {
case
Types.
SQL_TIME_WITH_TIME_ZONE : {
TimeData value = (
TimeData)
a;
if (
otherType.
isDateTimeTypeWithZone()) {
if (
value.
zone !=
targetZone) {
return new
TimeData(
value.
getSeconds(),
value.
getNanos(),
targetZone);
}
} else {
int
seconds =
value.
getSeconds() -
localZone;
seconds =
(int) (
HsqlDateTime.
getNormalisedTime(
seconds * 1000L)
/ 1000);
return new
TimeData(
seconds,
value.
getNanos(),
targetZone);
}
break;
}
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE : {
TimestampData value = (
TimestampData)
a;
long
seconds =
value.
getSeconds();
if (!
otherType.
isDateTimeTypeWithZone()) {
seconds -=
localZone;
}
if (
value.
getSeconds() !=
seconds
||
value.
zone !=
targetZone) {
return new
TimestampData(
seconds,
value.
getNanos(),
targetZone);
}
break;
}
}
return
a;
}
public boolean
canAdd(
IntervalType other) {
return
other.
startPartIndex >=
startPartIndex
&&
other.
endPartIndex <=
endPartIndex;
}
public int
getSqlDateTimeSub() {
switch (
typeCode) {
case
Types.
SQL_DATE :
return 1;
case
Types.
SQL_TIME :
return 2;
case
Types.
SQL_TIMESTAMP :
return 3;
default :
return 0;
}
}
/**
* For temporal predicate operations on periods, we need to make sure we
* compare data of the same types.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return The common data type of the boundaries of the two limits.
* null if any of the two periods is null or if the first limit of
* any period is null.
*
* @since 2.3.4
*/
public static
Type normalizeInput(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb,
boolean
pointOfTime) {
if (
a == null ||
b == null) {
return null;
}
if (
a[0] == null ||
b[0] == null) {
return null;
}
if (
a[1] == null) {
return null;
}
if (!
pointOfTime &&
b[1] == null) {
return null;
}
Type commonType =
SQL_TIMESTAMP_WITH_TIME_ZONE;
a[0] =
commonType.
castToType(
session,
a[0],
ta[0]);
b[0] =
commonType.
castToType(
session,
b[0],
tb[0]);
if (
ta[1].
isIntervalType()) {
a[1] =
commonType.
add(
session,
a[0],
a[1],
ta[1]);
} else {
a[1] =
commonType.
castToType(
session,
a[1],
ta[1]);
}
if (
tb[1].
isIntervalType()) {
b[1] =
commonType.
add(
session,
b[0],
b[1],
tb[1]);
} else {
if (
pointOfTime) {
b[1] =
b[0];
} else {
b[1] =
commonType.
castToType(
session,
b[1],
tb[1]);
}
}
if (
commonType.
compare(
session,
a[0],
a[1]) >= 0) {
throw
Error.
error(
ErrorCode.
X_22020);
}
if (!
pointOfTime &&
commonType.
compare(
session,
b[0],
b[1]) >= 0) {
throw
Error.
error(
ErrorCode.
X_22020);
}
return
commonType;
}
/**
* For temporal predicate operations on periods, we need to make sure we
* compare data of the same types.
* We also switch the period boundaries if the first entry is after the
* second one.
* <p>
* Important: when this method returns, the boundaries of the periods may
* have been changed.
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return The common data type of the boundaries of the two limits.
* null if any of the two periods is null or if the first limit of
* any period is null.
*
* @since 2.3.4
*/
public static
Type normalizeInputRelaxed(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
if (
a == null ||
b == null) {
return null;
}
if (
a[0] == null ||
b[0] == null) {
return null;
}
if (
a[1] == null) {
a[1] =
a[0];
}
if (
b[1] == null) {
b[1] =
b[0];
}
Type commonType =
ta[0].
getCombinedType(
session,
tb[0],
OpTypes.
EQUAL);
a[0] =
commonType.
castToType(
session,
a[0],
ta[0]);
b[0] =
commonType.
castToType(
session,
b[0],
tb[0]);
if (
ta[1].
isIntervalType()) {
a[1] =
commonType.
add(
session,
a[0],
a[1],
ta[1]);
} else {
a[1] =
commonType.
castToType(
session,
a[1],
ta[1]);
}
if (
tb[1].
isIntervalType()) {
b[1] =
commonType.
add(
session,
b[0],
b[1],
tb[1]);
} else {
b[1] =
commonType.
castToType(
session,
b[1],
tb[1]);
}
if (
commonType.
compare(
session,
a[0],
a[1]) > 0) {
Object temp =
a[0];
a[0] =
a[1];
a[1] =
temp;
}
if (
commonType.
compare(
session,
b[0],
b[1]) > 0) {
Object temp =
b[0];
b[0] =
b[1];
b[1] =
temp;
}
return
commonType;
}
/**
* The predicate "a OVERLAPS b" applies when both a and b are either period
* names or period constructors.
* This predicate returns True if the two periods have at least one time
* point in common, i.e, if a[0] < b[1] and
* a[1] > b[0]. This predicates is commutative: "a OVERLAPS B" must return
* the same result of "b OVERLAPS a"
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if the two periods overlaps,
* else {@link Boolean#FALSE}
*/
public static
Boolean overlaps(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[0],
b[0]) > 0) {
Object[]
temp =
a;
a =
b;
b =
temp;
}
if (
commonType.
compare(
session,
a[1],
b[0]) > 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "a OVERLAPS b" applies when both a and b are rows.
* This predicate returns True if the two periods have at least one time
* point in common, i.e, if a[0] < b[1] and
* a[1] > b[0]. This predicates is commutative: "a OVERLAPS B" must return
* the same result of "b OVERLAPS a"
* <p>
* Important: when this method returns, the boundaries of the periods may
* have been changed.
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if the two periods overlaps,
* else {@link Boolean#FALSE}
*/
public static
Boolean overlapsRelaxed(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInputRelaxed(
session,
a,
ta,
b,
tb);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[0],
b[0]) > 0) {
Object[]
temp =
a;
a =
b;
b =
temp;
}
if (
commonType.
compare(
session,
a[1],
b[0]) > 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "a PRECEDES b" applies when both a and b are either period
* names or period constructors.
* In this case, the predicate returns True if the end value of a is less
* than or equal to the start value of b, i.e., if ae <= as.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a precedes period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean precedes(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[1],
b[0]) <= 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "x IMMEDIATELY PRECEDES y" applies when both x and y are either period names or
* period constructors. In this case, the predicate returns True if the end value of x is equal to the start value
* of y, i.e., if xe = ys.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a immediately precedes period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean immediatelyPrecedes(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[1],
b[0]) == 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "x IMMEDIATELY SUCCEEDS y" applies when both x and y are either period names or
* period constructors. In this case, the predicate returns True if the start value of x is equal to the end value
* of y, i.e., if xs = ye.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a immediately succeeds period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean immediatelySucceeds(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[0],
b[1]) == 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "x SUCCEEDS y" applies when both x and y are either period names or period constructors.
* In this case, the predicate returns True if the start value of x is greater than or equal to the end value of y,
* i.e., if xs >= ye.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a succeeds period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean succeeds(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[0],
b[1]) >= 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "x EQUALS y" applies when both x and y are either period names or period constructors.
* This predicate returns True if the two periods have every time point in common, i.e., if xs = ys and xe = ye.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a equals period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean equals(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb, false);
if (
commonType == null) {
return null;
}
if (
commonType.
compare(
session,
a[0],
b[0]) == 0
&&
commonType.
compare(
session,
a[1],
b[1]) == 0) {
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
/**
* The predicate "x CONTAINS y" applies when<br>
* a) both x and y are either period names or period constructors. In this case, the predicate returns True if
* x contains every time point in y, i.e., if xs <= ys and xe >= ye.<br>
* b) x is either a period name or a period constructor and y is a datetime value expression. In this case, the
* predicate returns True if x contains y, i.e., if xs <= y and xe > y.
* <p>
* The <i>b</i> part of this definition is not supported yet. In order to get the same result, one have to specify
* a period with the same date time value for the period start and end.
* <p>
*
* @param session
* @param a First period to compare
* @param ta Types of the first period
* @param b Second period to compare
* @param tb Type of the second period
*
* @return {@link Boolean#TRUE} if period a contains period b,
* else {@link Boolean#FALSE}
*/
public static
Boolean contains(
Session session,
Object[]
a,
Type[]
ta,
Object[]
b,
Type[]
tb,
boolean
pointOfTime) {
Type commonType =
normalizeInput(
session,
a,
ta,
b,
tb,
pointOfTime);
if (
commonType == null) {
return null;
}
int
compareStart =
commonType.
compare(
session,
a[0],
b[0]);
int
compareEnd =
commonType.
compare(
session,
a[1],
b[1]);
if (
compareStart <= 0 &&
compareEnd >= 0) {
// if the end of the two period are equals, period a does not
// contains period b if it is defined by a single point in time
if (
pointOfTime) {
if (
compareEnd == 0) {
return
Boolean.
FALSE;
}
}
return
Boolean.
TRUE;
}
return
Boolean.
FALSE;
}
public static
BigDecimal subtractMonthsSpecial(
Session session,
TimestampData a,
TimestampData b) {
long
s1 = (
a.
getSeconds() +
a.
getZone()) * 1000;
long
s2 = (
b.
getSeconds() +
b.
getZone()) * 1000;
boolean
minus = false;
if (
s1 <
s2) {
minus = true;
long
temp =
s1;
s1 =
s2;
s2 =
temp;
}
s1 =
HsqlDateTime.
getNormalisedDate(
session.
getCalendarGMT(),
s1);
s2 =
HsqlDateTime.
getNormalisedDate(
session.
getCalendarGMT(),
s2);
Calendar cal =
session.
getCalendarGMT();
cal.
setTimeInMillis(
s1);
int
lastDay1;
int
months1 =
cal.
get(
Calendar.
MONTH) +
cal.
get(
Calendar.
YEAR) * 12;
int
day1 =
cal.
get(
Calendar.
DAY_OF_MONTH);
cal.
set(
Calendar.
DAY_OF_MONTH, 1);
long
millis =
cal.
getTimeInMillis();
cal.
add(
Calendar.
MONTH, 1);
millis =
cal.
getTimeInMillis();
cal.
add(
Calendar.
DAY_OF_MONTH, -1);
millis =
cal.
getTimeInMillis();
lastDay1 =
cal.
get(
Calendar.
DAY_OF_MONTH);
cal.
setTimeInMillis(
s2);
int
lastDay2;
int
months2 =
cal.
get(
Calendar.
MONTH) +
cal.
get(
Calendar.
YEAR) * 12;
int
day2 =
cal.
get(
Calendar.
DAY_OF_MONTH);
cal.
set(
Calendar.
DAY_OF_MONTH, 1);
millis =
cal.
getTimeInMillis();
cal.
add(
Calendar.
MONTH, 1);
millis =
cal.
getTimeInMillis();
cal.
add(
Calendar.
DAY_OF_MONTH, -1);
millis =
cal.
getTimeInMillis();
lastDay2 =
cal.
get(
Calendar.
DAY_OF_MONTH);
double
months;
double
days;
if (
day1 ==
day2 || (
day1 ==
lastDay1 &&
day2 ==
lastDay2)) {
months =
months1 -
months2;
if (
minus) {
months = -
months;
}
return
BigDecimal.
valueOf(
months);
} else if (
day2 >
day1) {
months =
months1 -
months2 - 1;
days =
lastDay2 -
day2 +
day1;
months +=
days / 31;
if (
minus) {
months = -
months;
}
return
BigDecimal.
valueOf(
months);
} else {
months =
months1 -
months2;
days =
day1 -
day2;
months +=
days / 31;
if (
minus) {
months = -
months;
}
return
BigDecimal.
valueOf(
months);
}
}
//
public static int
subtractMonths(
Session session,
TimestampData a,
TimestampData b, boolean
isYear) {
Calendar calendar =
session.
getCalendarGMT();
synchronized (
calendar) {
boolean
negate = false;
if (
b.
getSeconds() >
a.
getSeconds()) {
negate = true;
TimestampData temp =
a;
a =
b;
b =
temp;
}
calendar.
setTimeInMillis(
a.
getSeconds() * 1000);
int
months =
calendar.
get(
Calendar.
MONTH);
int
years =
calendar.
get(
Calendar.
YEAR);
calendar.
setTimeInMillis(
b.
getSeconds() * 1000);
months -=
calendar.
get(
Calendar.
MONTH);
years -=
calendar.
get(
Calendar.
YEAR);
if (
isYear) {
months =
years * 12;
} else {
if (
months < 0) {
months += 12;
years--;
}
months +=
years * 12;
}
if (
negate) {
months = -
months;
}
return
months;
}
}
public static
TimeData addSeconds(
TimeData source, long
seconds,
int
nanos) {
nanos +=
source.
getNanos();
seconds +=
nanos /
limitNanoseconds;
nanos %=
limitNanoseconds;
if (
nanos < 0) {
nanos +=
DTIType.
limitNanoseconds;
seconds--;
}
seconds +=
source.
getSeconds();
seconds %= (24 * 60 * 60);
TimeData ti = new
TimeData((int)
seconds,
nanos,
source.
getZone());
return
ti;
}
/** @todo - overflow */
public static
TimestampData addMonths(
Session session,
TimestampData source, int
months) {
int
n =
source.
getNanos();
Calendar cal =
session.
getCalendarGMT();
HsqlDateTime.
setTimeInMillis(
cal,
source.
getSeconds() * 1000);
cal.
add(
Calendar.
MONTH,
months);
TimestampData ts = new
TimestampData(
cal.
getTimeInMillis() / 1000,
n,
source.
getZone());
return
ts;
}
public static
TimestampData addSeconds(
TimestampData source, long
seconds,
int
nanos) {
nanos +=
source.
getNanos();
seconds +=
nanos /
limitNanoseconds;
nanos %=
limitNanoseconds;
if (
nanos < 0) {
nanos +=
limitNanoseconds;
seconds--;
}
long
newSeconds =
source.
getSeconds() +
seconds;
TimestampData ts = new
TimestampData(
newSeconds,
nanos,
source.
getZone());
return
ts;
}
public static
TimestampData convertToDatetimeSpecial(
SessionInterface session,
String s,
DateTimeType type) {
switch (
type.
typeCode) {
case
Types.
SQL_TIMESTAMP :
if (
session instanceof
Session
&& ((
Session)
session).
database.
sqlSyntaxOra) {
String pattern;
switch (
s.
length()) {
case 8 :
case 9 : {
pattern = "DD-MON-YY";
break;
}
case 10 :
case 11 : {
pattern = "DD-MON-YYYY";
break;
}
case 19 :
case 20 : {
pattern = "DD-MON-YYYY HH24:MI:SS";
break;
}
default :
// if (s.length() > 20)
{
pattern = "DD-MON-YYYY HH24:MI:SS.FF";
break;
}
}
SimpleDateFormat format =
session.
getSimpleDateFormatGMT();
return
HsqlDateTime.
toDate(
s,
pattern,
format, true);
}
// fall through
case
Types.
SQL_TIMESTAMP_WITH_TIME_ZONE :
//
case
Types.
SQL_DATE :
case
Types.
SQL_TIME :
case
Types.
SQL_TIME_WITH_TIME_ZONE :
default :
}
throw
Error.
error(
ErrorCode.
X_22007);
}
public static
TimestampData nextDayOfWeek(
Session session,
TimestampData d, int
day) {
Calendar cal =
session.
getCalendarGMT();
cal.
setTimeInMillis(
d.
getMillis());
int
start =
cal.
get(
Calendar.
DAY_OF_WEEK);
if (
start >=
day) {
day += 7;
}
int
diff =
day -
start;
cal.
add(
Calendar.
DAY_OF_MONTH,
diff);
long
millis =
cal.
getTimeInMillis();
millis =
HsqlDateTime.
getNormalisedDate(
cal,
millis);
return new
TimestampData(
millis / 1000);
}
public static int
getDayOfWeek(
String name) {
int
c =
Character.
toUpperCase(
name.
charAt(0));
switch (
c) {
case 'M' :
return 2;
case 'T' :
if (
Character.
toUpperCase(
name.
charAt(1)) == 'U') {
return 3;
} else if (
Character.
toUpperCase(
name.
charAt(1)) == 'H') {
return 5;
}
break;
case 'W' :
return 4;
case 'F' :
return 6;
case 'S' :
if (
Character.
toUpperCase(
name.
charAt(1)) == 'A') {
return 7;
} else if (
Character.
toUpperCase(
name.
charAt(1)) == 'U') {
return 1;
}
break;
}
throw
Error.
error(
ErrorCode.
X_22007);
}
}