Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
f0169c88
提交
f0169c88
authored
8月 23, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Extract IntervalUtils from DateTimeUtils
上级
f6a0794f
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
882 行增加
和
838 行删除
+882
-838
Interval.java
h2/src/main/org/h2/api/Interval.java
+9
-9
Parser.java
h2/src/main/org/h2/command/Parser.java
+2
-1
AggregateDataMedian.java
h2/src/main/org/h2/expression/AggregateDataMedian.java
+4
-3
IntervalOperation.java
h2/src/main/org/h2/expression/IntervalOperation.java
+10
-9
DateTimeFunctions.java
h2/src/main/org/h2/util/DateTimeFunctions.java
+10
-10
DateTimeUtils.java
h2/src/main/org/h2/util/DateTimeUtils.java
+2
-791
IntervalUtils.java
h2/src/main/org/h2/util/IntervalUtils.java
+827
-0
LocalDateTimeUtils.java
h2/src/main/org/h2/util/LocalDateTimeUtils.java
+1
-1
Value.java
h2/src/main/org/h2/value/Value.java
+7
-6
ValueInterval.java
h2/src/main/org/h2/value/ValueInterval.java
+7
-6
TestDateTimeUtils.java
h2/src/test/org/h2/test/unit/TestDateTimeUtils.java
+3
-2
没有找到文件。
h2/src/main/org/h2/api/Interval.java
浏览文件 @
f0169c88
...
...
@@ -9,7 +9,7 @@ import static org.h2.util.DateTimeUtils.NANOS_PER_MINUTE;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
NANOS_PER_SECOND
;
import
org.h2.message.DbException
;
import
org.h2.util.
DateTime
Utils
;
import
org.h2.util.
Interval
Utils
;
/**
* INTERVAL representation for result sets.
...
...
@@ -471,7 +471,7 @@ public final class Interval {
public
Interval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
this
.
qualifier
=
qualifier
;
try
{
this
.
negative
=
DateTime
Utils
.
validateInterval
(
qualifier
,
negative
,
leading
,
remaining
);
this
.
negative
=
Interval
Utils
.
validateInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
catch
(
DbException
e
)
{
throw
new
IllegalArgumentException
();
}
...
...
@@ -523,7 +523,7 @@ public final class Interval {
* @return years, or 0
*/
public
long
getYears
()
{
return
DateTime
Utils
.
yearsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
yearsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
/**
...
...
@@ -532,7 +532,7 @@ public final class Interval {
* @return months, or 0
*/
public
long
getMonths
()
{
return
DateTime
Utils
.
monthsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
monthsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
/**
...
...
@@ -541,7 +541,7 @@ public final class Interval {
* @return days, or 0
*/
public
long
getDays
()
{
return
DateTime
Utils
.
daysFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
daysFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
/**
...
...
@@ -550,7 +550,7 @@ public final class Interval {
* @return hours, or 0
*/
public
long
getHours
()
{
return
DateTime
Utils
.
hoursFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
hoursFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
/**
...
...
@@ -559,7 +559,7 @@ public final class Interval {
* @return minutes, or 0
*/
public
long
getMinutes
()
{
return
DateTime
Utils
.
minutesFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
minutesFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
/**
...
...
@@ -599,7 +599,7 @@ public final class Interval {
* @return nanoseconds (including seconds), or 0
*/
public
long
getSecondsAndNanos
()
{
return
DateTime
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
}
@Override
...
...
@@ -628,7 +628,7 @@ public final class Interval {
@Override
public
String
toString
()
{
return
DateTime
Utils
.
intervalToString
(
qualifier
,
negative
,
leading
,
remaining
);
return
Interval
Utils
.
intervalToString
(
qualifier
,
negative
,
leading
,
remaining
);
}
}
h2/src/main/org/h2/command/Parser.java
浏览文件 @
f0169c88
...
...
@@ -190,6 +190,7 @@ import org.h2.table.TableFilter.TableFilterVisitor;
import
org.h2.table.TableView
;
import
org.h2.util.DateTimeFunctions
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.ParserUtil
;
import
org.h2.util.StatementBuilder
;
...
...
@@ -3691,7 +3692,7 @@ public class Parser {
qualifier
=
IntervalQualifier
.
SECOND
;
}
try
{
return
ValueExpression
.
get
(
DateTime
Utils
.
parseInterval
(
qualifier
,
negative
,
s
));
return
ValueExpression
.
get
(
Interval
Utils
.
parseInterval
(
qualifier
,
negative
,
s
));
}
catch
(
Exception
e
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
e
,
"INTERVAL"
,
s
);
}
...
...
h2/src/main/org/h2/expression/AggregateDataMedian.java
浏览文件 @
f0169c88
...
...
@@ -23,6 +23,7 @@ import org.h2.table.IndexColumn;
import
org.h2.table.Table
;
import
org.h2.table.TableFilter
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
import
org.h2.value.CompareMode
;
import
org.h2.value.Value
;
import
org.h2.value.ValueDate
;
...
...
@@ -261,9 +262,9 @@ class AggregateDataMedian extends AggregateDataCollecting {
case
Value
.
INTERVAL_HOUR_TO_MINUTE
:
case
Value
.
INTERVAL_HOUR_TO_SECOND
:
case
Value
.
INTERVAL_MINUTE_TO_SECOND
:
return
DateTime
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
dataType
-
Value
.
INTERVAL_YEAR
),
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
v0
)
.
add
(
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
v1
)).
shiftRight
(
1
));
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
dataType
-
Value
.
INTERVAL_YEAR
),
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
v0
)
.
add
(
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
v1
)).
shiftRight
(
1
));
default
:
// Just return first
return
v0
.
convertTo
(
dataType
);
...
...
h2/src/main/org/h2/expression/IntervalOperation.java
浏览文件 @
f0169c88
...
...
@@ -16,6 +16,7 @@ import org.h2.table.ColumnResolver;
import
org.h2.table.TableFilter
;
import
org.h2.util.DateTimeFunctions
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
import
org.h2.value.DataType
;
import
org.h2.value.Value
;
import
org.h2.value.ValueDate
;
...
...
@@ -131,9 +132,9 @@ public class IntervalOperation extends Expression {
switch
(
opType
)
{
case
INTERVAL_PLUS_INTERVAL:
case
INTERVAL_MINUS_INTERVAL:
{
BigInteger
a1
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
l
);
BigInteger
a2
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
return
DateTime
Utils
.
intervalFromAbsolute
(
BigInteger
a1
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
l
);
BigInteger
a2
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
Value
.
getHigherOrder
(
lType
,
rType
)
-
Value
.
INTERVAL_YEAR
),
opType
==
IntervalOpType
.
INTERVAL_PLUS_INTERVAL
?
a1
.
add
(
a2
)
:
a1
.
subtract
(
a2
));
}
...
...
@@ -142,9 +143,9 @@ public class IntervalOperation extends Expression {
return
getDateTimeWithInterval
(
l
,
r
,
lType
,
rType
);
case
INTERVAL_MULTIPLY_NUMERIC:
case
INTERVAL_DIVIDE_NUMERIC:
{
BigDecimal
a1
=
new
BigDecimal
(
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
l
));
BigDecimal
a1
=
new
BigDecimal
(
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
l
));
BigDecimal
a2
=
r
.
getBigDecimal
();
return
DateTime
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
lType
-
Value
.
INTERVAL_YEAR
),
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
lType
-
Value
.
INTERVAL_YEAR
),
(
opType
==
IntervalOpType
.
INTERVAL_MULTIPLY_NUMERIC
?
a1
.
multiply
(
a2
)
:
a1
.
divide
(
a2
))
.
toBigInteger
());
}
...
...
@@ -179,7 +180,7 @@ public class IntervalOperation extends Expression {
diff
=
diff
.
add
(
BigInteger
.
valueOf
((((
ValueTimestampTimeZone
)
r
).
getTimeZoneOffsetMins
()
-
((
ValueTimestampTimeZone
)
l
).
getTimeZoneOffsetMins
())
*
60_000_000_000L
));
}
return
DateTime
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
DAY_TO_SECOND
,
diff
);
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
DAY_TO_SECOND
,
diff
);
}
}
throw
DbException
.
throwInternalError
(
"type="
+
opType
);
...
...
@@ -192,7 +193,7 @@ public class IntervalOperation extends Expression {
throw
DbException
.
throwInternalError
(
"type="
+
rType
);
}
BigInteger
a1
=
BigInteger
.
valueOf
(((
ValueTime
)
l
).
getNanos
());
BigInteger
a2
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
a2
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
n
=
opType
==
IntervalOpType
.
DATETIME_PLUS_INTERVAL
?
a1
.
add
(
a2
)
:
a1
.
subtract
(
a2
);
if
(
n
.
signum
()
<
0
||
n
.
compareTo
(
BigInteger
.
valueOf
(
DateTimeUtils
.
NANOS_PER_DAY
))
>=
0
)
{
throw
DbException
.
get
(
ErrorCode
.
NUMERIC_VALUE_OUT_OF_RANGE_1
,
n
.
toString
());
...
...
@@ -203,13 +204,13 @@ public class IntervalOperation extends Expression {
case
Value
.
TIMESTAMP
:
case
Value
.
TIMESTAMP_TZ
:
if
(
DataType
.
isYearMonthIntervalType
(
rType
))
{
long
m
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
).
longValue
();
long
m
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
).
longValue
();
if
(
opType
==
IntervalOpType
.
DATETIME_MINUS_INTERVAL
)
{
m
=
-
m
;
}
return
DateTimeFunctions
.
dateadd
(
"MONTH"
,
m
,
l
);
}
else
{
BigInteger
a2
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
BigInteger
a2
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
r
);
if
(
lType
==
Value
.
DATE
)
{
BigInteger
a1
=
BigInteger
.
valueOf
(
DateTimeUtils
.
absoluteDayFromDateValue
(((
ValueDate
)
l
).
getDateValue
()));
...
...
h2/src/main/org/h2/util/DateTimeFunctions.java
浏览文件 @
f0169c88
...
...
@@ -355,7 +355,7 @@ public final class DateTimeFunctions {
bd
=
bd
.
negate
();
}
}
else
{
bd
=
new
BigDecimal
(
DateTime
Utils
.
intervalToAbsolute
(
interval
))
bd
=
new
BigDecimal
(
Interval
Utils
.
intervalToAbsolute
(
interval
))
.
divide
(
BigDecimal
.
valueOf
(
NANOS_PER_SECOND
));
}
return
ValueDecimal
.
get
(
bd
);
...
...
@@ -634,33 +634,33 @@ public final class DateTimeFunctions {
long
v
;
switch
(
field
)
{
case
YEAR:
v
=
DateTime
Utils
.
yearsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
v
=
Interval
Utils
.
yearsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
break
;
case
MONTH:
v
=
DateTime
Utils
.
monthsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
v
=
Interval
Utils
.
monthsFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
break
;
case
DAY_OF_MONTH:
case
DAY_OF_WEEK:
case
DAY_OF_YEAR:
v
=
DateTime
Utils
.
daysFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
v
=
Interval
Utils
.
daysFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
break
;
case
HOUR:
v
=
DateTime
Utils
.
hoursFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
v
=
Interval
Utils
.
hoursFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
break
;
case
MINUTE:
v
=
DateTime
Utils
.
minutesFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
v
=
Interval
Utils
.
minutesFromInterval
(
qualifier
,
negative
,
leading
,
remaining
);
break
;
case
SECOND:
v
=
DateTime
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
NANOS_PER_SECOND
;
v
=
Interval
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
NANOS_PER_SECOND
;
break
;
case
MILLISECOND:
v
=
DateTime
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
1_000_000
%
1_000
;
v
=
Interval
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
1_000_000
%
1_000
;
break
;
case
MICROSECOND:
v
=
DateTime
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
1_000
%
1_000_000
;
v
=
Interval
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
/
1_000
%
1_000_000
;
break
;
case
NANOSECOND:
v
=
DateTime
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
%
NANOS_PER_SECOND
;
v
=
Interval
Utils
.
nanosFromInterval
(
qualifier
,
negative
,
leading
,
remaining
)
%
NANOS_PER_SECOND
;
break
;
default
:
throw
DbException
.
getUnsupportedException
(
"getDatePart("
+
date
+
", "
+
field
+
')'
);
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
f0169c88
...
...
@@ -6,20 +6,15 @@
*/
package
org
.
h2
.
util
;
import
java.math.BigInteger
;
import
java.sql.Date
;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.IntervalQualifier
;
import
org.h2.engine.Mode
;
import
org.h2.message.DbException
;
import
org.h2.value.Value
;
import
org.h2.value.ValueDate
;
import
org.h2.value.ValueInterval
;
import
org.h2.value.ValueNull
;
import
org.h2.value.ValueTime
;
import
org.h2.value.ValueTimestamp
;
...
...
@@ -461,7 +456,7 @@ public class DateTimeUtils {
return
((((
hour
*
60L
)
+
minute
)
*
60
)
+
second
)
*
NANOS_PER_SECOND
+
nanos
;
}
private
static
int
parseNanos
(
String
s
,
int
start
,
int
end
)
{
static
int
parseNanos
(
String
s
,
int
start
,
int
end
)
{
if
(
start
>=
end
)
{
throw
new
IllegalArgumentException
(
s
);
}
...
...
@@ -1480,7 +1475,7 @@ public class DateTimeUtils {
}
}
private
static
void
stripTrailingZeroes
(
StringBuilder
buff
)
{
static
void
stripTrailingZeroes
(
StringBuilder
buff
)
{
int
i
=
buff
.
length
()
-
1
;
if
(
buff
.
charAt
(
i
)
==
'0'
)
{
while
(
buff
.
charAt
(--
i
)
==
'0'
)
{
...
...
@@ -1555,414 +1550,6 @@ public class DateTimeUtils {
return
b
.
toString
();
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
* @param qualifier the default qualifier to use if string does not have one
* @param s the string with type information to parse
* @return the interval value.
* Type of value can be different from the specified qualifier.
*/
public
static
ValueInterval
parseFormattedInterval
(
IntervalQualifier
qualifier
,
String
s
)
{
int
i
=
0
;
i
=
skipWS
(
s
,
i
);
if
(!
s
.
regionMatches
(
true
,
i
,
"INTERVAL"
,
0
,
8
))
{
return
parseInterval
(
qualifier
,
false
,
s
);
}
i
=
skipWS
(
s
,
i
+
8
);
boolean
negative
=
false
;
char
ch
=
s
.
charAt
(
i
);
if
(
ch
==
'-'
)
{
negative
=
true
;
i
=
skipWS
(
s
,
i
+
1
);
ch
=
s
.
charAt
(
i
);
}
else
if
(
ch
==
'+'
)
{
i
=
skipWS
(
s
,
i
+
1
);
ch
=
s
.
charAt
(
i
);
}
if
(
ch
!=
'\''
)
{
throw
new
IllegalArgumentException
(
s
);
}
int
start
=
++
i
;
int
l
=
s
.
length
();
for
(;;)
{
if
(
i
==
l
)
{
throw
new
IllegalArgumentException
(
s
);
}
if
(
s
.
charAt
(
i
)
==
'\''
)
{
break
;
}
i
++;
}
String
v
=
s
.
substring
(
start
,
i
);
i
=
skipWS
(
s
,
i
+
1
);
if
(
s
.
regionMatches
(
true
,
i
,
"YEAR"
,
0
,
4
))
{
i
+=
4
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
YEAR
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
&&
s
.
regionMatches
(
true
,
i
,
"MONTH"
,
0
,
5
))
{
if
(
skipWSEnd
(
s
,
i
+
5
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
YEAR_TO_MONTH
,
negative
,
v
);
}
}
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"MONTH"
,
0
,
5
))
{
if
(
skipWSEnd
(
s
,
i
+
5
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MONTH
,
negative
,
v
);
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"DAY"
,
0
,
3
))
{
i
+=
3
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
)
{
if
(
s
.
regionMatches
(
true
,
i
,
"HOUR"
,
0
,
4
))
{
if
(
skipWSEnd
(
s
,
i
+
4
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_HOUR
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_MINUTE
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_SECOND
,
negative
,
v
);
}
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"HOUR"
,
0
,
4
))
{
i
+=
4
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
)
{
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR_TO_MINUTE
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR_TO_SECOND
,
negative
,
v
);
}
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
i
+=
6
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MINUTE
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
&&
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MINUTE_TO_SECOND
,
negative
,
v
);
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
SECOND
,
negative
,
v
);
}
}
throw
new
IllegalArgumentException
(
s
);
}
private
static
int
skipWS
(
String
s
,
int
i
)
{
for
(
int
l
=
s
.
length
();
;
i
++)
{
if
(
i
==
l
)
{
throw
new
IllegalArgumentException
(
s
);
}
if
(!
Character
.
isWhitespace
(
s
.
charAt
(
i
)))
{
return
i
;
}
}
}
private
static
int
skipWSEnd
(
String
s
,
int
i
)
{
for
(
int
l
=
s
.
length
();
;
i
++)
{
if
(
i
==
l
)
{
return
i
;
}
if
(!
Character
.
isWhitespace
(
s
.
charAt
(
i
)))
{
return
i
;
}
}
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
* @param qualifier the qualifier of interval
* @param negative whether the interval is negative
* @param s the string to parse
* @return the interval value
*/
public
static
ValueInterval
parseInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
String
s
)
{
long
leading
,
remaining
;
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
break
;
case
SECOND:
{
int
dot
=
s
.
indexOf
(
'.'
);
if
(
dot
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dot
,
negative
);
remaining
=
parseNanos
(
s
,
dot
+
1
,
s
.
length
());
}
break
;
}
case
YEAR_TO_MONTH:
return
parseInterval2
(
qualifier
,
s
,
'-'
,
11
,
negative
);
case
DAY_TO_HOUR:
return
parseInterval2
(
qualifier
,
s
,
' '
,
23
,
negative
);
case
DAY_TO_MINUTE:
{
int
space
=
s
.
indexOf
(
' '
);
if
(
space
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
space
,
negative
);
int
colon
=
s
.
indexOf
(
':'
,
space
+
1
);
if
(
colon
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
s
.
length
(),
23
)
*
60
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
60
+
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
);
}
}
break
;
}
case
DAY_TO_SECOND:
{
int
space
=
s
.
indexOf
(
' '
);
if
(
space
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
space
,
negative
);
int
colon
=
s
.
indexOf
(
':'
,
space
+
1
);
if
(
colon
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
s
.
length
(),
23
)
*
NANOS_PER_HOUR
;
}
else
{
int
colon2
=
s
.
indexOf
(
':'
,
colon
+
1
);
if
(
colon2
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
NANOS_PER_HOUR
+
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
)
*
NANOS_PER_MINUTE
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
NANOS_PER_HOUR
+
parseIntervalRemaining
(
s
,
colon
+
1
,
colon2
,
59
)
*
NANOS_PER_MINUTE
+
parseIntervalRemainingSeconds
(
s
,
colon2
+
1
);
}
}
}
break
;
}
case
HOUR_TO_MINUTE:
return
parseInterval2
(
qualifier
,
s
,
':'
,
59
,
negative
);
case
HOUR_TO_SECOND:
{
int
colon
=
s
.
indexOf
(
':'
);
if
(
colon
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
colon
,
negative
);
int
colon2
=
s
.
indexOf
(
':'
,
colon
+
1
);
if
(
colon2
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
)
*
NANOS_PER_MINUTE
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
colon
+
1
,
colon2
,
59
)
*
NANOS_PER_MINUTE
+
parseIntervalRemainingSeconds
(
s
,
colon2
+
1
);
}
}
break
;
}
case
MINUTE_TO_SECOND:
{
int
dash
=
s
.
indexOf
(
':'
);
if
(
dash
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dash
,
negative
);
remaining
=
parseIntervalRemainingSeconds
(
s
,
dash
+
1
);
}
break
;
}
default
:
throw
new
IllegalArgumentException
();
}
negative
=
leading
<
0
;
if
(
negative
)
{
if
(
leading
!=
Long
.
MIN_VALUE
)
{
leading
=
-
leading
;
}
else
{
leading
=
0
;
}
}
return
ValueInterval
.
from
(
qualifier
,
negative
,
leading
,
remaining
);
}
static
ValueInterval
parseInterval2
(
IntervalQualifier
qualifier
,
String
s
,
char
ch
,
int
max
,
boolean
negative
)
{
long
leading
;
long
remaining
;
int
dash
=
s
.
indexOf
(
ch
,
1
);
if
(
dash
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dash
,
negative
);
remaining
=
parseIntervalRemaining
(
s
,
dash
+
1
,
s
.
length
(),
max
);
}
negative
=
leading
<
0
;
if
(
negative
)
{
if
(
leading
!=
Long
.
MIN_VALUE
)
{
leading
=
-
leading
;
}
else
{
leading
=
0
;
}
}
return
ValueInterval
.
from
(
qualifier
,
negative
,
leading
,
remaining
);
}
private
static
long
parseIntervalLeading
(
String
s
,
int
start
,
int
end
,
boolean
negative
)
{
long
leading
=
Long
.
parseLong
(
s
.
substring
(
start
,
end
));
if
(
leading
==
0
)
{
return
negative
^
s
.
charAt
(
start
)
==
'-'
?
Long
.
MIN_VALUE
:
0
;
}
return
negative
?
-
leading
:
leading
;
}
private
static
long
parseIntervalRemaining
(
String
s
,
int
start
,
int
end
,
int
max
)
{
int
v
=
StringUtils
.
parseUInt31
(
s
,
start
,
end
);
if
(
v
>
max
)
{
throw
new
IllegalArgumentException
(
s
);
}
return
v
;
}
private
static
long
parseIntervalRemainingSeconds
(
String
s
,
int
start
)
{
int
seconds
,
nanos
;
int
dot
=
s
.
indexOf
(
'.'
,
start
+
1
);
if
(
dot
<
0
)
{
seconds
=
StringUtils
.
parseUInt31
(
s
,
start
,
s
.
length
());
nanos
=
0
;
}
else
{
seconds
=
StringUtils
.
parseUInt31
(
s
,
start
,
dot
);
nanos
=
parseNanos
(
s
,
dot
+
1
,
s
.
length
());
}
if
(
seconds
>
59
)
{
throw
new
IllegalArgumentException
(
s
);
}
return
seconds
*
NANOS_PER_SECOND
+
nanos
;
}
/**
* Formats interval as a string.
*
* @param qualifier qualifier of the interval
* @param negative whether interval is negative
* @param leading the value of leading field
* @param remaining the value of all remaining fields
* @return string representation of the specified interval
*/
public
static
String
intervalToString
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
StringBuilder
buff
=
new
StringBuilder
().
append
(
"INTERVAL "
);
buff
.
append
(
'\''
);
if
(
negative
)
{
buff
.
append
(
'-'
);
}
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
buff
.
append
(
leading
);
break
;
case
SECOND:
buff
.
append
(
leading
);
appendNanos
(
buff
,
remaining
);
break
;
case
YEAR_TO_MONTH:
buff
.
append
(
leading
).
append
(
'-'
).
append
(
remaining
);
break
;
case
DAY_TO_HOUR:
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
);
break
;
case
DAY_TO_MINUTE:
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
60
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
%
60
);
break
;
case
DAY_TO_SECOND:
{
long
nanos
=
remaining
%
NANOS_PER_MINUTE
;
remaining
/=
NANOS_PER_MINUTE
;
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
60
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
%
60
);
buff
.
append
(
':'
);
appendSecondsWithNanos
(
buff
,
nanos
);
break
;
}
case
HOUR_TO_MINUTE:
buff
.
append
(
leading
).
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
);
break
;
case
HOUR_TO_SECOND:
buff
.
append
(
leading
).
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
NANOS_PER_MINUTE
);
buff
.
append
(
':'
);
appendSecondsWithNanos
(
buff
,
remaining
%
NANOS_PER_MINUTE
);
break
;
case
MINUTE_TO_SECOND:
buff
.
append
(
leading
).
append
(
':'
);
appendSecondsWithNanos
(
buff
,
remaining
);
break
;
}
buff
.
append
(
"' "
).
append
(
qualifier
);
return
buff
.
toString
();
}
private
static
void
appendSecondsWithNanos
(
StringBuilder
buff
,
long
nanos
)
{
StringUtils
.
appendZeroPadded
(
buff
,
2
,
nanos
/
NANOS_PER_SECOND
);
appendNanos
(
buff
,
nanos
%
NANOS_PER_SECOND
);
}
private
static
void
appendNanos
(
StringBuilder
buff
,
long
nanos
)
{
if
(
nanos
>
0
)
{
buff
.
append
(
'.'
);
StringUtils
.
appendZeroPadded
(
buff
,
9
,
nanos
);
stripTrailingZeroes
(
buff
);
}
}
/**
* Converts scale of nanoseconds.
*
...
...
@@ -1982,380 +1569,4 @@ public class DateTimeUtils {
return
nanosOfDay
-
mod
;
}
/**
* Converts interval value to an absolute value.
*
* @param interval the interval value
* @return absolute value in months for year-month intervals,
* in nanoseconds for day-time intervals
*/
public
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
)
{
BigInteger
r
;
switch
(
interval
.
getQualifier
())
{
case
YEAR:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
12
));
break
;
case
MONTH:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
());
break
;
case
DAY:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_DAY
));
break
;
case
HOUR:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
));
break
;
case
MINUTE:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
));
break
;
case
SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_SECOND
);
break
;
case
YEAR_TO_MONTH:
r
=
intervalToAbsolute
(
interval
,
12
);
break
;
case
DAY_TO_HOUR:
r
=
intervalToAbsolute
(
interval
,
24
,
NANOS_PER_HOUR
);
break
;
case
DAY_TO_MINUTE:
r
=
intervalToAbsolute
(
interval
,
24
*
60
,
NANOS_PER_MINUTE
);
break
;
case
DAY_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_DAY
);
break
;
case
HOUR_TO_MINUTE:
r
=
intervalToAbsolute
(
interval
,
60
,
NANOS_PER_MINUTE
);
break
;
case
HOUR_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_HOUR
);
break
;
case
MINUTE_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_MINUTE
);
break
;
default
:
throw
new
IllegalArgumentException
();
}
return
interval
.
isNegative
()
?
r
.
negate
()
:
r
;
}
private
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
,
long
multiplier
,
long
totalMultiplier
)
{
return
intervalToAbsolute
(
interval
,
multiplier
).
multiply
(
BigInteger
.
valueOf
(
totalMultiplier
));
}
private
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
,
long
multiplier
)
{
return
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
multiplier
))
.
add
(
BigInteger
.
valueOf
(
interval
.
getRemaining
()));
}
/**
* Converts absolute value to an interval value.
*
* @param qualifier the qualifier of interval
* @param absolute absolute value in months for year-month intervals,
* in nanoseconds for day-time intervals
* @return the interval value
*/
public
static
ValueInterval
intervalFromAbsolute
(
IntervalQualifier
qualifier
,
BigInteger
absolute
)
{
switch
(
qualifier
)
{
case
YEAR:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
12
))),
0
);
case
MONTH:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
),
0
);
case
DAY:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_DAY
))),
0
);
case
HOUR:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
))),
0
);
case
MINUTE:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
))),
0
);
case
SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_SECOND
);
case
YEAR_TO_MONTH:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
12
);
case
DAY_TO_HOUR:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
)),
24
);
case
DAY_TO_MINUTE:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
)),
24
*
60
);
case
DAY_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_DAY
);
case
HOUR_TO_MINUTE:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
)),
60
);
case
HOUR_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_HOUR
);
case
MINUTE_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_MINUTE
);
default
:
throw
new
IllegalArgumentException
();
}
}
private
static
ValueInterval
intervalFromAbsolute
(
IntervalQualifier
qualifier
,
BigInteger
absolute
,
long
divisor
)
{
BigInteger
[]
dr
=
absolute
.
divideAndRemainder
(
BigInteger
.
valueOf
(
divisor
));
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
dr
[
0
]),
Math
.
abs
(
dr
[
1
].
longValue
()));
}
private
static
long
leadingExact
(
BigInteger
absolute
)
{
if
(
absolute
.
compareTo
(
BigInteger
.
valueOf
(
999_999_999_999_999_999L
))
>
0
||
absolute
.
compareTo
(
BigInteger
.
valueOf
(-
999_999_999_999_999_999L
))
<
0
)
{
throw
DbException
.
get
(
ErrorCode
.
NUMERIC_VALUE_OUT_OF_RANGE_1
,
absolute
.
toString
());
}
return
Math
.
abs
(
absolute
.
longValue
());
}
/**
* Ensures that all fields in interval are valid.
*
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return fixed value of negative field
*/
public
static
boolean
validateInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
if
(
qualifier
==
null
)
{
throw
new
NullPointerException
();
}
if
(
leading
==
0L
&&
remaining
==
0L
)
{
return
false
;
}
// Upper bound for remaining value (exclusive)
long
bound
;
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
bound
=
1
;
break
;
case
SECOND:
bound
=
NANOS_PER_SECOND
;
break
;
case
YEAR_TO_MONTH:
bound
=
12
;
break
;
case
DAY_TO_HOUR:
bound
=
24
;
break
;
case
DAY_TO_MINUTE:
bound
=
24
*
60
;
break
;
case
DAY_TO_SECOND:
bound
=
NANOS_PER_DAY
;
break
;
case
HOUR_TO_MINUTE:
bound
=
60
;
break
;
case
HOUR_TO_SECOND:
bound
=
NANOS_PER_HOUR
;
break
;
case
MINUTE_TO_SECOND:
bound
=
NANOS_PER_MINUTE
;
break
;
default
:
throw
DbException
.
getInvalidValueException
(
"interval"
,
qualifier
);
}
if
(
leading
<
0L
||
leading
>=
1_000_000_000_000_000_000L
)
{
throw
DbException
.
getInvalidValueException
(
"interval"
,
Long
.
toString
(
leading
));
}
if
(
remaining
<
0L
||
remaining
>=
bound
)
{
throw
DbException
.
getInvalidValueException
(
"interval"
,
Long
.
toString
(
remaining
));
}
return
negative
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return years, or 0
*/
public
static
long
yearsFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
if
(
qualifier
==
IntervalQualifier
.
YEAR
||
qualifier
==
IntervalQualifier
.
YEAR_TO_MONTH
)
{
long
v
=
leading
;
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
else
{
return
0
;
}
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return months, or 0
*/
public
static
long
monthsFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
if
(
qualifier
==
IntervalQualifier
.
MONTH
)
{
v
=
leading
;
}
else
if
(
qualifier
==
IntervalQualifier
.
YEAR_TO_MONTH
){
v
=
remaining
;
}
else
{
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return months, or 0
*/
public
static
long
daysFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
switch
(
qualifier
)
{
case
DAY:
case
DAY_TO_HOUR:
case
DAY_TO_MINUTE:
case
DAY_TO_SECOND:
long
v
=
leading
;
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
default
:
return
0
;
}
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return hours, or 0
*/
public
static
long
hoursFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
HOUR:
case
HOUR_TO_MINUTE:
case
HOUR_TO_SECOND:
v
=
leading
;
break
;
case
DAY_TO_HOUR:
v
=
remaining
;
break
;
case
DAY_TO_MINUTE:
v
=
remaining
/
60
;
break
;
case
DAY_TO_SECOND:
v
=
remaining
/
NANOS_PER_HOUR
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return minutes, or 0
*/
public
static
long
minutesFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
MINUTE:
case
MINUTE_TO_SECOND:
v
=
leading
;
break
;
case
DAY_TO_MINUTE:
v
=
remaining
%
60
;
break
;
case
DAY_TO_SECOND:
v
=
remaining
/
NANOS_PER_MINUTE
%
60
;
break
;
case
HOUR_TO_MINUTE:
v
=
remaining
;
break
;
case
HOUR_TO_SECOND:
v
=
remaining
/
NANOS_PER_MINUTE
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return nanoseconds, or 0
*/
public
static
long
nanosFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
SECOND:
v
=
leading
*
NANOS_PER_SECOND
+
remaining
;
break
;
case
DAY_TO_SECOND:
case
HOUR_TO_SECOND:
v
=
remaining
%
NANOS_PER_MINUTE
;
break
;
case
MINUTE_TO_SECOND:
v
=
remaining
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
}
h2/src/main/org/h2/util/IntervalUtils.java
0 → 100644
浏览文件 @
f0169c88
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
util
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
NANOS_PER_DAY
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
NANOS_PER_HOUR
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
NANOS_PER_MINUTE
;
import
static
org
.
h2
.
util
.
DateTimeUtils
.
NANOS_PER_SECOND
;
import
java.math.BigInteger
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.IntervalQualifier
;
import
org.h2.message.DbException
;
import
org.h2.value.ValueInterval
;
/**
* This utility class contains interval conversion functions.
*/
public
class
IntervalUtils
{
private
IntervalUtils
()
{
// utility class
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
* @param qualifier
* the default qualifier to use if string does not have one
* @param s
* the string with type information to parse
* @return the interval value. Type of value can be different from the
* specified qualifier.
*/
public
static
ValueInterval
parseFormattedInterval
(
IntervalQualifier
qualifier
,
String
s
)
{
int
i
=
0
;
i
=
skipWS
(
s
,
i
);
if
(!
s
.
regionMatches
(
true
,
i
,
"INTERVAL"
,
0
,
8
))
{
return
parseInterval
(
qualifier
,
false
,
s
);
}
i
=
skipWS
(
s
,
i
+
8
);
boolean
negative
=
false
;
char
ch
=
s
.
charAt
(
i
);
if
(
ch
==
'-'
)
{
negative
=
true
;
i
=
skipWS
(
s
,
i
+
1
);
ch
=
s
.
charAt
(
i
);
}
else
if
(
ch
==
'+'
)
{
i
=
skipWS
(
s
,
i
+
1
);
ch
=
s
.
charAt
(
i
);
}
if
(
ch
!=
'\''
)
{
throw
new
IllegalArgumentException
(
s
);
}
int
start
=
++
i
;
int
l
=
s
.
length
();
for
(;;)
{
if
(
i
==
l
)
{
throw
new
IllegalArgumentException
(
s
);
}
if
(
s
.
charAt
(
i
)
==
'\''
)
{
break
;
}
i
++;
}
String
v
=
s
.
substring
(
start
,
i
);
i
=
skipWS
(
s
,
i
+
1
);
if
(
s
.
regionMatches
(
true
,
i
,
"YEAR"
,
0
,
4
))
{
i
+=
4
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
YEAR
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
&&
s
.
regionMatches
(
true
,
i
,
"MONTH"
,
0
,
5
))
{
if
(
skipWSEnd
(
s
,
i
+
5
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
YEAR_TO_MONTH
,
negative
,
v
);
}
}
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"MONTH"
,
0
,
5
))
{
if
(
skipWSEnd
(
s
,
i
+
5
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MONTH
,
negative
,
v
);
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"DAY"
,
0
,
3
))
{
i
+=
3
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
)
{
if
(
s
.
regionMatches
(
true
,
i
,
"HOUR"
,
0
,
4
))
{
if
(
skipWSEnd
(
s
,
i
+
4
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_HOUR
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_MINUTE
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
DAY_TO_SECOND
,
negative
,
v
);
}
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"HOUR"
,
0
,
4
))
{
i
+=
4
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
)
{
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR_TO_MINUTE
,
negative
,
v
);
}
}
else
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
HOUR_TO_SECOND
,
negative
,
v
);
}
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"MINUTE"
,
0
,
6
))
{
i
+=
6
;
int
j
=
skipWSEnd
(
s
,
i
);
if
(
j
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MINUTE
,
negative
,
v
);
}
if
(
j
>
i
&&
s
.
regionMatches
(
true
,
j
,
"TO"
,
0
,
2
))
{
j
+=
2
;
i
=
skipWS
(
s
,
j
);
if
(
i
>
j
&&
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
MINUTE_TO_SECOND
,
negative
,
v
);
}
}
}
}
if
(
s
.
regionMatches
(
true
,
i
,
"SECOND"
,
0
,
6
))
{
if
(
skipWSEnd
(
s
,
i
+
6
)
==
l
)
{
return
parseInterval
(
IntervalQualifier
.
SECOND
,
negative
,
v
);
}
}
throw
new
IllegalArgumentException
(
s
);
}
private
static
int
skipWS
(
String
s
,
int
i
)
{
for
(
int
l
=
s
.
length
();;
i
++)
{
if
(
i
==
l
)
{
throw
new
IllegalArgumentException
(
s
);
}
if
(!
Character
.
isWhitespace
(
s
.
charAt
(
i
)))
{
return
i
;
}
}
}
private
static
int
skipWSEnd
(
String
s
,
int
i
)
{
for
(
int
l
=
s
.
length
();;
i
++)
{
if
(
i
==
l
)
{
return
i
;
}
if
(!
Character
.
isWhitespace
(
s
.
charAt
(
i
)))
{
return
i
;
}
}
}
/**
* Parses the specified string as {@code INTERVAL} value.
*
* @param qualifier
* the qualifier of interval
* @param negative
* whether the interval is negative
* @param s
* the string to parse
* @return the interval value
*/
public
static
ValueInterval
parseInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
String
s
)
{
long
leading
,
remaining
;
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
break
;
case
SECOND:
{
int
dot
=
s
.
indexOf
(
'.'
);
if
(
dot
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dot
,
negative
);
remaining
=
DateTimeUtils
.
parseNanos
(
s
,
dot
+
1
,
s
.
length
());
}
break
;
}
case
YEAR_TO_MONTH:
return
parseInterval2
(
qualifier
,
s
,
'-'
,
11
,
negative
);
case
DAY_TO_HOUR:
return
parseInterval2
(
qualifier
,
s
,
' '
,
23
,
negative
);
case
DAY_TO_MINUTE:
{
int
space
=
s
.
indexOf
(
' '
);
if
(
space
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
space
,
negative
);
int
colon
=
s
.
indexOf
(
':'
,
space
+
1
);
if
(
colon
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
s
.
length
(),
23
)
*
60
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
60
+
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
);
}
}
break
;
}
case
DAY_TO_SECOND:
{
int
space
=
s
.
indexOf
(
' '
);
if
(
space
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
space
,
negative
);
int
colon
=
s
.
indexOf
(
':'
,
space
+
1
);
if
(
colon
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
s
.
length
(),
23
)
*
NANOS_PER_HOUR
;
}
else
{
int
colon2
=
s
.
indexOf
(
':'
,
colon
+
1
);
if
(
colon2
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
NANOS_PER_HOUR
+
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
)
*
NANOS_PER_MINUTE
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
space
+
1
,
colon
,
23
)
*
NANOS_PER_HOUR
+
parseIntervalRemaining
(
s
,
colon
+
1
,
colon2
,
59
)
*
NANOS_PER_MINUTE
+
parseIntervalRemainingSeconds
(
s
,
colon2
+
1
);
}
}
}
break
;
}
case
HOUR_TO_MINUTE:
return
parseInterval2
(
qualifier
,
s
,
':'
,
59
,
negative
);
case
HOUR_TO_SECOND:
{
int
colon
=
s
.
indexOf
(
':'
);
if
(
colon
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
colon
,
negative
);
int
colon2
=
s
.
indexOf
(
':'
,
colon
+
1
);
if
(
colon2
<
0
)
{
remaining
=
parseIntervalRemaining
(
s
,
colon
+
1
,
s
.
length
(),
59
)
*
NANOS_PER_MINUTE
;
}
else
{
remaining
=
parseIntervalRemaining
(
s
,
colon
+
1
,
colon2
,
59
)
*
NANOS_PER_MINUTE
+
parseIntervalRemainingSeconds
(
s
,
colon2
+
1
);
}
}
break
;
}
case
MINUTE_TO_SECOND:
{
int
dash
=
s
.
indexOf
(
':'
);
if
(
dash
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dash
,
negative
);
remaining
=
parseIntervalRemainingSeconds
(
s
,
dash
+
1
);
}
break
;
}
default
:
throw
new
IllegalArgumentException
();
}
negative
=
leading
<
0
;
if
(
negative
)
{
if
(
leading
!=
Long
.
MIN_VALUE
)
{
leading
=
-
leading
;
}
else
{
leading
=
0
;
}
}
return
ValueInterval
.
from
(
qualifier
,
negative
,
leading
,
remaining
);
}
static
ValueInterval
parseInterval2
(
IntervalQualifier
qualifier
,
String
s
,
char
ch
,
int
max
,
boolean
negative
)
{
long
leading
;
long
remaining
;
int
dash
=
s
.
indexOf
(
ch
,
1
);
if
(
dash
<
0
)
{
leading
=
parseIntervalLeading
(
s
,
0
,
s
.
length
(),
negative
);
remaining
=
0
;
}
else
{
leading
=
parseIntervalLeading
(
s
,
0
,
dash
,
negative
);
remaining
=
parseIntervalRemaining
(
s
,
dash
+
1
,
s
.
length
(),
max
);
}
negative
=
leading
<
0
;
if
(
negative
)
{
if
(
leading
!=
Long
.
MIN_VALUE
)
{
leading
=
-
leading
;
}
else
{
leading
=
0
;
}
}
return
ValueInterval
.
from
(
qualifier
,
negative
,
leading
,
remaining
);
}
private
static
long
parseIntervalLeading
(
String
s
,
int
start
,
int
end
,
boolean
negative
)
{
long
leading
=
Long
.
parseLong
(
s
.
substring
(
start
,
end
));
if
(
leading
==
0
)
{
return
negative
^
s
.
charAt
(
start
)
==
'-'
?
Long
.
MIN_VALUE
:
0
;
}
return
negative
?
-
leading
:
leading
;
}
private
static
long
parseIntervalRemaining
(
String
s
,
int
start
,
int
end
,
int
max
)
{
int
v
=
StringUtils
.
parseUInt31
(
s
,
start
,
end
);
if
(
v
>
max
)
{
throw
new
IllegalArgumentException
(
s
);
}
return
v
;
}
private
static
long
parseIntervalRemainingSeconds
(
String
s
,
int
start
)
{
int
seconds
,
nanos
;
int
dot
=
s
.
indexOf
(
'.'
,
start
+
1
);
if
(
dot
<
0
)
{
seconds
=
StringUtils
.
parseUInt31
(
s
,
start
,
s
.
length
());
nanos
=
0
;
}
else
{
seconds
=
StringUtils
.
parseUInt31
(
s
,
start
,
dot
);
nanos
=
DateTimeUtils
.
parseNanos
(
s
,
dot
+
1
,
s
.
length
());
}
if
(
seconds
>
59
)
{
throw
new
IllegalArgumentException
(
s
);
}
return
seconds
*
NANOS_PER_SECOND
+
nanos
;
}
/**
* Formats interval as a string.
*
* @param qualifier
* qualifier of the interval
* @param negative
* whether interval is negative
* @param leading
* the value of leading field
* @param remaining
* the value of all remaining fields
* @return string representation of the specified interval
*/
public
static
String
intervalToString
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
StringBuilder
buff
=
new
StringBuilder
().
append
(
"INTERVAL "
);
buff
.
append
(
'\''
);
if
(
negative
)
{
buff
.
append
(
'-'
);
}
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
buff
.
append
(
leading
);
break
;
case
SECOND:
buff
.
append
(
leading
);
appendNanos
(
buff
,
remaining
);
break
;
case
YEAR_TO_MONTH:
buff
.
append
(
leading
).
append
(
'-'
).
append
(
remaining
);
break
;
case
DAY_TO_HOUR:
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
);
break
;
case
DAY_TO_MINUTE:
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
60
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
%
60
);
break
;
case
DAY_TO_SECOND:
{
long
nanos
=
remaining
%
NANOS_PER_MINUTE
;
remaining
/=
NANOS_PER_MINUTE
;
buff
.
append
(
leading
).
append
(
' '
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
60
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
%
60
);
buff
.
append
(
':'
);
appendSecondsWithNanos
(
buff
,
nanos
);
break
;
}
case
HOUR_TO_MINUTE:
buff
.
append
(
leading
).
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
);
break
;
case
HOUR_TO_SECOND:
buff
.
append
(
leading
).
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
remaining
/
NANOS_PER_MINUTE
);
buff
.
append
(
':'
);
appendSecondsWithNanos
(
buff
,
remaining
%
NANOS_PER_MINUTE
);
break
;
case
MINUTE_TO_SECOND:
buff
.
append
(
leading
).
append
(
':'
);
appendSecondsWithNanos
(
buff
,
remaining
);
break
;
}
buff
.
append
(
"' "
).
append
(
qualifier
);
return
buff
.
toString
();
}
private
static
void
appendSecondsWithNanos
(
StringBuilder
buff
,
long
nanos
)
{
StringUtils
.
appendZeroPadded
(
buff
,
2
,
nanos
/
NANOS_PER_SECOND
);
appendNanos
(
buff
,
nanos
%
NANOS_PER_SECOND
);
}
private
static
void
appendNanos
(
StringBuilder
buff
,
long
nanos
)
{
if
(
nanos
>
0
)
{
buff
.
append
(
'.'
);
StringUtils
.
appendZeroPadded
(
buff
,
9
,
nanos
);
DateTimeUtils
.
stripTrailingZeroes
(
buff
);
}
}
/**
* Converts interval value to an absolute value.
*
* @param interval
* the interval value
* @return absolute value in months for year-month intervals, in nanoseconds
* for day-time intervals
*/
public
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
)
{
BigInteger
r
;
switch
(
interval
.
getQualifier
())
{
case
YEAR:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
12
));
break
;
case
MONTH:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
());
break
;
case
DAY:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_DAY
));
break
;
case
HOUR:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
));
break
;
case
MINUTE:
r
=
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
));
break
;
case
SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_SECOND
);
break
;
case
YEAR_TO_MONTH:
r
=
intervalToAbsolute
(
interval
,
12
);
break
;
case
DAY_TO_HOUR:
r
=
intervalToAbsolute
(
interval
,
24
,
NANOS_PER_HOUR
);
break
;
case
DAY_TO_MINUTE:
r
=
intervalToAbsolute
(
interval
,
24
*
60
,
NANOS_PER_MINUTE
);
break
;
case
DAY_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_DAY
);
break
;
case
HOUR_TO_MINUTE:
r
=
intervalToAbsolute
(
interval
,
60
,
NANOS_PER_MINUTE
);
break
;
case
HOUR_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_HOUR
);
break
;
case
MINUTE_TO_SECOND:
r
=
intervalToAbsolute
(
interval
,
NANOS_PER_MINUTE
);
break
;
default
:
throw
new
IllegalArgumentException
();
}
return
interval
.
isNegative
()
?
r
.
negate
()
:
r
;
}
private
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
,
long
multiplier
,
long
totalMultiplier
)
{
return
intervalToAbsolute
(
interval
,
multiplier
).
multiply
(
BigInteger
.
valueOf
(
totalMultiplier
));
}
private
static
BigInteger
intervalToAbsolute
(
ValueInterval
interval
,
long
multiplier
)
{
return
BigInteger
.
valueOf
(
interval
.
getLeading
()).
multiply
(
BigInteger
.
valueOf
(
multiplier
))
.
add
(
BigInteger
.
valueOf
(
interval
.
getRemaining
()));
}
/**
* Converts absolute value to an interval value.
*
* @param qualifier
* the qualifier of interval
* @param absolute
* absolute value in months for year-month intervals, in
* nanoseconds for day-time intervals
* @return the interval value
*/
public
static
ValueInterval
intervalFromAbsolute
(
IntervalQualifier
qualifier
,
BigInteger
absolute
)
{
switch
(
qualifier
)
{
case
YEAR:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
12
))),
0
);
case
MONTH:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
),
0
);
case
DAY:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_DAY
))),
0
);
case
HOUR:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
))),
0
);
case
MINUTE:
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
))),
0
);
case
SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_SECOND
);
case
YEAR_TO_MONTH:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
12
);
case
DAY_TO_HOUR:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_HOUR
)),
24
);
case
DAY_TO_MINUTE:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
)),
24
*
60
);
case
DAY_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_DAY
);
case
HOUR_TO_MINUTE:
return
intervalFromAbsolute
(
qualifier
,
absolute
.
divide
(
BigInteger
.
valueOf
(
NANOS_PER_MINUTE
)),
60
);
case
HOUR_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_HOUR
);
case
MINUTE_TO_SECOND:
return
intervalFromAbsolute
(
qualifier
,
absolute
,
NANOS_PER_MINUTE
);
default
:
throw
new
IllegalArgumentException
();
}
}
private
static
ValueInterval
intervalFromAbsolute
(
IntervalQualifier
qualifier
,
BigInteger
absolute
,
long
divisor
)
{
BigInteger
[]
dr
=
absolute
.
divideAndRemainder
(
BigInteger
.
valueOf
(
divisor
));
return
ValueInterval
.
from
(
qualifier
,
absolute
.
signum
()
<
0
,
leadingExact
(
dr
[
0
]),
Math
.
abs
(
dr
[
1
].
longValue
()));
}
private
static
long
leadingExact
(
BigInteger
absolute
)
{
if
(
absolute
.
compareTo
(
BigInteger
.
valueOf
(
999_999_999_999_999_999L
))
>
0
||
absolute
.
compareTo
(
BigInteger
.
valueOf
(-
999_999_999_999_999_999L
))
<
0
)
{
throw
DbException
.
get
(
ErrorCode
.
NUMERIC_VALUE_OUT_OF_RANGE_1
,
absolute
.
toString
());
}
return
Math
.
abs
(
absolute
.
longValue
());
}
/**
* Ensures that all fields in interval are valid.
*
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return fixed value of negative field
*/
public
static
boolean
validateInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
if
(
qualifier
==
null
)
{
throw
new
NullPointerException
();
}
if
(
leading
==
0L
&&
remaining
==
0L
)
{
return
false
;
}
// Upper bound for remaining value (exclusive)
long
bound
;
switch
(
qualifier
)
{
case
YEAR:
case
MONTH:
case
DAY:
case
HOUR:
case
MINUTE:
bound
=
1
;
break
;
case
SECOND:
bound
=
NANOS_PER_SECOND
;
break
;
case
YEAR_TO_MONTH:
bound
=
12
;
break
;
case
DAY_TO_HOUR:
bound
=
24
;
break
;
case
DAY_TO_MINUTE:
bound
=
24
*
60
;
break
;
case
DAY_TO_SECOND:
bound
=
NANOS_PER_DAY
;
break
;
case
HOUR_TO_MINUTE:
bound
=
60
;
break
;
case
HOUR_TO_SECOND:
bound
=
NANOS_PER_HOUR
;
break
;
case
MINUTE_TO_SECOND:
bound
=
NANOS_PER_MINUTE
;
break
;
default
:
throw
DbException
.
getInvalidValueException
(
"interval"
,
qualifier
);
}
if
(
leading
<
0L
||
leading
>=
1_000_000_000_000_000_000L
)
{
throw
DbException
.
getInvalidValueException
(
"interval"
,
Long
.
toString
(
leading
));
}
if
(
remaining
<
0L
||
remaining
>=
bound
)
{
throw
DbException
.
getInvalidValueException
(
"interval"
,
Long
.
toString
(
remaining
));
}
return
negative
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return years, or 0
*/
public
static
long
yearsFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
if
(
qualifier
==
IntervalQualifier
.
YEAR
||
qualifier
==
IntervalQualifier
.
YEAR_TO_MONTH
)
{
long
v
=
leading
;
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
else
{
return
0
;
}
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return months, or 0
*/
public
static
long
monthsFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
if
(
qualifier
==
IntervalQualifier
.
MONTH
)
{
v
=
leading
;
}
else
if
(
qualifier
==
IntervalQualifier
.
YEAR_TO_MONTH
)
{
v
=
remaining
;
}
else
{
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return months, or 0
*/
public
static
long
daysFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
switch
(
qualifier
)
{
case
DAY:
case
DAY_TO_HOUR:
case
DAY_TO_MINUTE:
case
DAY_TO_SECOND:
long
v
=
leading
;
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
default
:
return
0
;
}
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return hours, or 0
*/
public
static
long
hoursFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
HOUR:
case
HOUR_TO_MINUTE:
case
HOUR_TO_SECOND:
v
=
leading
;
break
;
case
DAY_TO_HOUR:
v
=
remaining
;
break
;
case
DAY_TO_MINUTE:
v
=
remaining
/
60
;
break
;
case
DAY_TO_SECOND:
v
=
remaining
/
NANOS_PER_HOUR
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return minutes, or 0
*/
public
static
long
minutesFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
MINUTE:
case
MINUTE_TO_SECOND:
v
=
leading
;
break
;
case
DAY_TO_MINUTE:
v
=
remaining
%
60
;
break
;
case
DAY_TO_SECOND:
v
=
remaining
/
NANOS_PER_MINUTE
%
60
;
break
;
case
HOUR_TO_MINUTE:
v
=
remaining
;
break
;
case
HOUR_TO_SECOND:
v
=
remaining
/
NANOS_PER_MINUTE
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
/**
* @param qualifier
* qualifier
* @param negative
* whether interval is negative
* @param leading
* value of leading field
* @param remaining
* values of all remaining fields
* @return nanoseconds, or 0
*/
public
static
long
nanosFromInterval
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
long
v
;
switch
(
qualifier
)
{
case
SECOND:
v
=
leading
*
NANOS_PER_SECOND
+
remaining
;
break
;
case
DAY_TO_SECOND:
case
HOUR_TO_SECOND:
v
=
remaining
%
NANOS_PER_MINUTE
;
break
;
case
MINUTE_TO_SECOND:
v
=
remaining
;
break
;
default
:
return
0
;
}
if
(
negative
)
{
v
=
-
v
;
}
return
v
;
}
}
h2/src/main/org/h2/util/LocalDateTimeUtils.java
浏览文件 @
f0169c88
...
...
@@ -397,7 +397,7 @@ public class LocalDateTimeUtils {
if
(
DataType
.
isYearMonthIntervalType
(
value
.
getType
()))
{
throw
DbException
.
get
(
ErrorCode
.
DATA_CONVERSION_ERROR_1
,
(
Throwable
)
null
,
value
.
getString
());
}
BigInteger
[]
dr
=
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
value
)
BigInteger
[]
dr
=
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
value
)
.
divideAndRemainder
(
BigInteger
.
valueOf
(
1_000_000_000
));
try
{
return
DURATION_OF_SECONDS
.
invoke
(
null
,
dr
[
0
].
longValue
(),
dr
[
1
].
longValue
());
...
...
h2/src/main/org/h2/value/Value.java
浏览文件 @
f0169c88
...
...
@@ -28,6 +28,7 @@ import org.h2.store.DataHandler;
import
org.h2.tools.SimpleResultSet
;
import
org.h2.util.Bits
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
import
org.h2.util.JdbcUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.StringUtils
;
...
...
@@ -1234,7 +1235,7 @@ public abstract class Value {
case
Value
.
STRING_FIXED
:
{
String
s
=
getString
();
try
{
return
(
ValueInterval
)
DateTime
Utils
return
(
ValueInterval
)
Interval
Utils
.
parseFormattedInterval
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
s
)
.
convertTo
(
targetType
);
}
catch
(
Exception
e
)
{
...
...
@@ -1244,8 +1245,8 @@ public abstract class Value {
case
Value
.
INTERVAL_YEAR
:
case
Value
.
INTERVAL_MONTH
:
case
Value
.
INTERVAL_YEAR_TO_MONTH
:
return
DateTime
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
this
));
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
this
));
}
throw
getDataConversionError
(
targetType
);
}
...
...
@@ -1257,7 +1258,7 @@ public abstract class Value {
case
Value
.
STRING_FIXED
:
{
String
s
=
getString
();
try
{
return
(
ValueInterval
)
DateTime
Utils
return
(
ValueInterval
)
Interval
Utils
.
parseFormattedInterval
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
s
)
.
convertTo
(
targetType
);
}
catch
(
Exception
e
)
{
...
...
@@ -1274,8 +1275,8 @@ public abstract class Value {
case
Value
.
INTERVAL_HOUR_TO_MINUTE
:
case
Value
.
INTERVAL_HOUR_TO_SECOND
:
case
Value
.
INTERVAL_MINUTE_TO_SECOND
:
return
DateTime
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
this
));
return
Interval
Utils
.
intervalFromAbsolute
(
IntervalQualifier
.
valueOf
(
targetType
-
Value
.
INTERVAL_YEAR
),
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
this
));
}
throw
getDataConversionError
(
targetType
);
}
...
...
h2/src/main/org/h2/value/ValueInterval.java
浏览文件 @
f0169c88
...
...
@@ -12,6 +12,7 @@ import org.h2.api.Interval;
import
org.h2.api.IntervalQualifier
;
import
org.h2.message.DbException
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
/**
* Implementation of the INTERVAL data type.
...
...
@@ -58,7 +59,7 @@ public class ValueInterval extends Value {
* @return interval value
*/
public
static
ValueInterval
from
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
)
{
negative
=
DateTime
Utils
.
validateInterval
(
qualifier
,
negative
,
leading
,
remaining
);
negative
=
Interval
Utils
.
validateInterval
(
qualifier
,
negative
,
leading
,
remaining
);
return
(
ValueInterval
)
Value
.
cache
(
new
ValueInterval
(
qualifier
.
ordinal
()
+
INTERVAL_YEAR
,
negative
,
leading
,
remaining
));
}
...
...
@@ -203,7 +204,7 @@ public class ValueInterval extends Value {
@Override
public
String
getString
()
{
return
DateTime
Utils
.
intervalToString
(
getQualifier
(),
negative
,
leading
,
remaining
);
return
Interval
Utils
.
intervalToString
(
getQualifier
(),
negative
,
leading
,
remaining
);
}
@Override
...
...
@@ -298,14 +299,14 @@ public class ValueInterval extends Value {
@Override
public
Value
add
(
Value
v
)
{
return
DateTime
Utils
.
intervalFromAbsolute
(
getQualifier
(),
DateTimeUtils
.
intervalToAbsolute
(
this
).
add
(
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
v
)));
return
Interval
Utils
.
intervalFromAbsolute
(
getQualifier
(),
IntervalUtils
.
intervalToAbsolute
(
this
).
add
(
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
v
)));
}
@Override
public
Value
subtract
(
Value
v
)
{
return
DateTime
Utils
.
intervalFromAbsolute
(
getQualifier
(),
DateTimeUtils
.
intervalToAbsolute
(
this
).
subtract
(
DateTime
Utils
.
intervalToAbsolute
((
ValueInterval
)
v
)));
return
Interval
Utils
.
intervalFromAbsolute
(
getQualifier
(),
IntervalUtils
.
intervalToAbsolute
(
this
).
subtract
(
Interval
Utils
.
intervalToAbsolute
((
ValueInterval
)
v
)));
}
@Override
...
...
h2/src/test/org/h2/test/unit/TestDateTimeUtils.java
浏览文件 @
f0169c88
...
...
@@ -15,11 +15,12 @@ import java.util.TimeZone;
import
org.h2.api.IntervalQualifier
;
import
org.h2.test.TestBase
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IntervalUtils
;
import
org.h2.value.ValueInterval
;
import
org.h2.value.ValueTimestamp
;
/**
* Unit tests for the DateTimeUtils
class
* Unit tests for the DateTimeUtils
and IntervalUtils classes.
*/
public
class
TestDateTimeUtils
extends
TestBase
{
...
...
@@ -257,7 +258,7 @@ public class TestDateTimeUtils extends TestBase {
private
void
testParseIntervalImpl
(
IntervalQualifier
qualifier
,
boolean
negative
,
long
leading
,
long
remaining
,
String
s
,
String
full
)
{
ValueInterval
expected
=
ValueInterval
.
from
(
qualifier
,
negative
,
leading
,
remaining
);
assertEquals
(
expected
,
DateTime
Utils
.
parseInterval
(
qualifier
,
negative
,
s
));
assertEquals
(
expected
,
Interval
Utils
.
parseInterval
(
qualifier
,
negative
,
s
));
StringBuilder
b
=
new
StringBuilder
();
b
.
append
(
"INTERVAL "
).
append
(
'\''
);
if
(
negative
)
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论