Skip to content

Commit b45289f

Browse files
wt0530githubgxll
authored andcommitted
[feat][runtime,common] Reconstruct time, date and time zone issues
1 parent d9d856a commit b45289f

File tree

73 files changed

+3984
-505
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+3984
-505
lines changed

coding/src/main/java/io/dingodb/expr/coding/ValCoder.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public CodingFlag visitLongType(@NonNull LongType type, OutputStream obj) {
8787
@SneakyThrows
8888
@Override
8989
public CodingFlag visitDateType(@NonNull DateType type, OutputStream obj) {
90+
// TODO ?
9091
Date value = (Date) val.getValue();
9192
if (value != null) {
9293
long milliseconds = value.getTime();

common/src/main/java/io/dingodb/expr/common/timezone/DateTimeUtils.java

Lines changed: 567 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2021 DataCanvas
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.dingodb.expr.common.timezone;
18+
19+
import io.dingodb.expr.common.timezone.core.DateTimeType;
20+
import io.dingodb.expr.common.timezone.core.DingoDateTime;
21+
22+
import java.time.ZoneId;
23+
24+
public class InputTypeAnalyzer {
25+
26+
public enum TimeZoneSensitivity {
27+
SENSITIVE, // Explicit time zone sensitivity
28+
INSENSITIVE, // Explicit time zone insensitivity
29+
AMBIGUOUS, // Fuzzy, requires contextual judgment
30+
UNKNOWN // unknown
31+
}
32+
33+
public static TimeZoneSensitivity analyzeSensitivity(Object input, DateTimeType targetType, ZoneId contextZone) {
34+
if (input == null) {
35+
return TimeZoneSensitivity.UNKNOWN;
36+
}
37+
38+
if (targetType.isTimeZoneSensitive()) {
39+
return analyzeForTimeZoneSensitiveTarget(input, contextZone);
40+
} else {
41+
return analyzeForTimeZoneInsensitiveTarget(input, contextZone);
42+
}
43+
}
44+
45+
private static TimeZoneSensitivity analyzeForTimeZoneSensitiveTarget(Object input, ZoneId contextZone) {
46+
if (input instanceof String) {
47+
return analyzeStringInput((String) input);
48+
} else if (input instanceof java.sql.Timestamp) {
49+
return TimeZoneSensitivity.SENSITIVE;
50+
} else if (input instanceof java.sql.Date) {
51+
// sql.Date is designed to be time zone insensitive, but actually stores timestamps
52+
return TimeZoneSensitivity.AMBIGUOUS;
53+
} else if (input instanceof java.sql.Time) {
54+
return TimeZoneSensitivity.AMBIGUOUS;
55+
} else if (input instanceof java.util.Date) {
56+
// java.util.Date is essentially time zone sensitive (stores UTC timestamp)
57+
return TimeZoneSensitivity.SENSITIVE;
58+
} else if (input instanceof DingoDateTime) {
59+
return ((DingoDateTime) input).isTimeZoneSensitive()
60+
? TimeZoneSensitivity.SENSITIVE : TimeZoneSensitivity.INSENSITIVE;
61+
}
62+
63+
return TimeZoneSensitivity.UNKNOWN;
64+
}
65+
66+
private static TimeZoneSensitivity analyzeForTimeZoneInsensitiveTarget(Object input, ZoneId contextZone) {
67+
// For time zone insensitive targets, most inputs are treated as insensitive
68+
if (input instanceof String) {
69+
return analyzeStringInput((String) input);
70+
} else if (input instanceof java.sql.Date) {
71+
return TimeZoneSensitivity.INSENSITIVE;
72+
} else if (input instanceof java.sql.Time) {
73+
return TimeZoneSensitivity.INSENSITIVE;
74+
} else if (input instanceof DingoDateTime) {
75+
return ((DingoDateTime) input).isTimeZoneSensitive()
76+
? TimeZoneSensitivity.AMBIGUOUS : TimeZoneSensitivity.INSENSITIVE;
77+
}
78+
79+
return TimeZoneSensitivity.AMBIGUOUS;
80+
}
81+
82+
private static TimeZoneSensitivity analyzeStringInput(String input) {
83+
if (input == null || input.trim().isEmpty()) {
84+
return TimeZoneSensitivity.UNKNOWN;
85+
}
86+
87+
// Analyze whether a string contains time zone information
88+
String trimmed = input.trim();
89+
if (trimmed.contains("+") || trimmed.contains("-") || trimmed.contains("Z") || trimmed.contains("T")) {
90+
if (trimmed.matches(".*[+-]\\d{2}:?\\d{2}") || trimmed.matches(".*[Zz]$")
91+
|| (trimmed.contains("[") && trimmed.contains("]"))) {
92+
return TimeZoneSensitivity.SENSITIVE;
93+
}
94+
}
95+
return TimeZoneSensitivity.INSENSITIVE;
96+
}
97+
}
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
* Copyright 2021 DataCanvas
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.dingodb.expr.common.timezone.converter;
18+
19+
import io.dingodb.expr.common.timezone.core.DateTimeType;
20+
import io.dingodb.expr.common.timezone.core.DingoDateTime;
21+
import io.dingodb.expr.common.timezone.core.SimpleTimeZoneConfig;
22+
23+
import java.time.Instant;
24+
import java.time.LocalDate;
25+
import java.time.LocalDateTime;
26+
import java.time.LocalTime;
27+
import java.time.ZoneId;
28+
import java.time.ZonedDateTime;
29+
30+
public class DateTimeConverter {
31+
32+
private final ZoneId defaultZone;
33+
34+
public DateTimeConverter(ZoneId defaultZone) {
35+
this.defaultZone = defaultZone;
36+
}
37+
38+
public DateTimeConverter() {
39+
this(SimpleTimeZoneConfig.getApplicationZone());
40+
}
41+
42+
public DingoDateTime convertInput(Object input, DateTimeType targetType) {
43+
if (input == null || targetType == null) {
44+
return null;
45+
}
46+
47+
if (input instanceof java.sql.Date) {
48+
return convertSqlDate((java.sql.Date) input, targetType);
49+
} else if (input instanceof java.sql.Time) {
50+
return convertSqlTime((java.sql.Time) input, targetType);
51+
} else if (input instanceof java.sql.Timestamp) {
52+
return convertSqlTimestamp((java.sql.Timestamp) input, targetType);
53+
} else if (input instanceof java.util.Date) {
54+
return convertUtilDate((java.util.Date) input, targetType);
55+
} else if (input instanceof String) {
56+
StringDateTimeParser parser = new StringDateTimeParser();
57+
return parser.parseString((String) input, targetType, defaultZone);
58+
} else if (input instanceof DingoDateTime) {
59+
return convertDingoDateTime((DingoDateTime) input, targetType);
60+
} else {
61+
throw new IllegalArgumentException("Unsupported input type: " + input.getClass());
62+
}
63+
}
64+
65+
private DingoDateTime convertUtilDate(java.util.Date utilDate, DateTimeType targetType) {
66+
Instant instant = utilDate.toInstant();
67+
68+
if (targetType.isTimeZoneSensitive()) {
69+
return new DingoDateTime.DingoTimestampTZ(instant, defaultZone);
70+
} else {
71+
LocalDateTime localDateTime = instant.atZone(defaultZone).toLocalDateTime();
72+
73+
switch (targetType) {
74+
case DATE:
75+
return new DingoDateTime.DingoLocalDate(localDateTime.toLocalDate());
76+
case TIME:
77+
return new DingoDateTime.DingoLocalTime(localDateTime.toLocalTime());
78+
case TIMESTAMP:
79+
return new DingoDateTime.DingoLocalDateTime(localDateTime);
80+
default:
81+
throw new IllegalArgumentException("Unsupported target type: " + targetType);
82+
}
83+
}
84+
}
85+
86+
private DingoDateTime convertSqlDate(java.sql.Date sqlDate, DateTimeType targetType) {
87+
if (targetType.isTimeZoneSensitive()) {
88+
Instant instant = Instant.ofEpochMilli(sqlDate.getTime());
89+
return new DingoDateTime.DingoTimestampTZ(instant, defaultZone);
90+
} else {
91+
LocalDate localDate = sqlDate.toLocalDate();
92+
93+
switch (targetType) {
94+
case DATE:
95+
return new DingoDateTime.DingoLocalDate(localDate);
96+
case TIME:
97+
throw new IllegalArgumentException("Cannot convert DATE to TIME");
98+
case TIMESTAMP:
99+
LocalDateTime localDateTime = localDate.atStartOfDay();
100+
return new DingoDateTime.DingoLocalDateTime(localDateTime);
101+
default:
102+
throw new IllegalArgumentException("Unsupported target type: " + targetType);
103+
}
104+
}
105+
}
106+
107+
private DingoDateTime convertSqlTime(java.sql.Time sqlTime, DateTimeType targetType) {
108+
if (targetType.isTimeZoneSensitive()) {
109+
Instant instant = Instant.ofEpochMilli(sqlTime.getTime());
110+
return new DingoDateTime.DingoTimestampTZ(instant, defaultZone);
111+
} else {
112+
LocalTime localTime = sqlTime.toLocalTime();
113+
114+
switch (targetType) {
115+
case DATE:
116+
// throw new IllegalArgumentException("Cannot convert TIME to DATE");
117+
return null;
118+
case TIME:
119+
return new DingoDateTime.DingoLocalTime(localTime);
120+
case TIMESTAMP:
121+
/*LocalDateTime localDateTime = LocalDateTime.of(
122+
LocalDate.of(1970, 1, 1), localTime);
123+
return new DingoDateTime.DingoLocalDateTime(localDateTime);*/
124+
return null;
125+
default:
126+
throw new IllegalArgumentException("Unsupported target type: " + targetType);
127+
}
128+
}
129+
}
130+
131+
private DingoDateTime convertSqlTimestamp(java.sql.Timestamp timestamp, DateTimeType targetType) {
132+
Instant instant = timestamp.toInstant();
133+
134+
if (targetType.isTimeZoneSensitive()) {
135+
return new DingoDateTime.DingoTimestampTZ(instant, defaultZone);
136+
} else {
137+
LocalDateTime localDateTime = instant.atZone(defaultZone).toLocalDateTime();
138+
139+
switch (targetType) {
140+
case DATE:
141+
return new DingoDateTime.DingoLocalDate(localDateTime.toLocalDate());
142+
case TIME:
143+
return new DingoDateTime.DingoLocalTime(localDateTime.toLocalTime());
144+
case TIMESTAMP:
145+
return new DingoDateTime.DingoLocalDateTime(localDateTime);
146+
default:
147+
throw new IllegalArgumentException("Unsupported target type: " + targetType);
148+
}
149+
}
150+
}
151+
152+
private DingoDateTime convertDingoDateTime(DingoDateTime dingoDateTime, DateTimeType targetType) {
153+
if (dingoDateTime.getType() == targetType) {
154+
return dingoDateTime;
155+
}
156+
157+
if (dingoDateTime.isTimeZoneSensitive()) {
158+
DingoDateTime.DingoTimestampTZ tzValue = (DingoDateTime.DingoTimestampTZ) dingoDateTime;
159+
160+
if (targetType.isTimeZoneSensitive()) {
161+
return dingoDateTime;
162+
} else {
163+
switch (targetType) {
164+
case DATE:
165+
LocalDate localDate = tzValue.getUtcValue()
166+
.atZone(tzValue.getOriginalZone())
167+
.toLocalDate();
168+
return new DingoDateTime.DingoLocalDate(localDate);
169+
case TIME:
170+
LocalTime localTime = tzValue.getUtcValue()
171+
.atZone(tzValue.getOriginalZone())
172+
.toLocalTime();
173+
return new DingoDateTime.DingoLocalTime(localTime);
174+
case TIMESTAMP:
175+
LocalDateTime localDateTime = tzValue.getUtcValue()
176+
.atZone(tzValue.getOriginalZone())
177+
.toLocalDateTime();
178+
return new DingoDateTime.DingoLocalDateTime(localDateTime);
179+
default:
180+
throw new IllegalArgumentException("Unsupported target type: " + targetType);
181+
}
182+
}
183+
} else {
184+
if (targetType.isTimeZoneSensitive()) {
185+
ZoneId targetZone = defaultZone;
186+
187+
if (dingoDateTime instanceof DingoDateTime.DingoLocalDate) {
188+
DingoDateTime.DingoLocalDate localDate = (DingoDateTime.DingoLocalDate) dingoDateTime;
189+
LocalDateTime localDateTime = localDate.getValue().atStartOfDay();
190+
ZonedDateTime zdt = localDateTime.atZone(targetZone);
191+
return new DingoDateTime.DingoTimestampTZ(zdt.toInstant(), targetZone);
192+
} else if (dingoDateTime instanceof DingoDateTime.DingoLocalTime) {
193+
DingoDateTime.DingoLocalTime localTime = (DingoDateTime.DingoLocalTime) dingoDateTime;
194+
LocalDateTime localDateTime = LocalDate.now().atTime(localTime.getValue());
195+
ZonedDateTime zdt = localDateTime.atZone(targetZone);
196+
return new DingoDateTime.DingoTimestampTZ(zdt.toInstant(), targetZone);
197+
} else if (dingoDateTime instanceof DingoDateTime.DingoLocalDateTime) {
198+
DingoDateTime.DingoLocalDateTime localDateTime = (DingoDateTime.DingoLocalDateTime) dingoDateTime;
199+
ZonedDateTime zdt = localDateTime.getValue().atZone(targetZone);
200+
return new DingoDateTime.DingoTimestampTZ(zdt.toInstant(), targetZone);
201+
}
202+
} else {
203+
if (dingoDateTime instanceof DingoDateTime.DingoLocalDate) {
204+
DingoDateTime.DingoLocalDate localDate = (DingoDateTime.DingoLocalDate) dingoDateTime;
205+
switch (targetType) {
206+
case DATE:
207+
return dingoDateTime;
208+
case TIMESTAMP:
209+
return new DingoDateTime.DingoLocalDateTime(localDate.getValue().atStartOfDay());
210+
default:
211+
throw new IllegalArgumentException("Unsupported conversion: DATE to " + targetType);
212+
}
213+
} else if (dingoDateTime instanceof DingoDateTime.DingoLocalTime) {
214+
DingoDateTime.DingoLocalTime localTime = (DingoDateTime.DingoLocalTime) dingoDateTime;
215+
switch (targetType) {
216+
case TIME:
217+
return dingoDateTime;
218+
case TIMESTAMP:
219+
LocalDateTime localDateTime = LocalDate.of(1970, 1, 1).atTime(localTime.getValue());
220+
return new DingoDateTime.DingoLocalDateTime(localDateTime);
221+
default:
222+
throw new IllegalArgumentException("Unsupported conversion: TIME to " + targetType);
223+
}
224+
} else if (dingoDateTime instanceof DingoDateTime.DingoLocalDateTime) {
225+
DingoDateTime.DingoLocalDateTime localDateTime = (DingoDateTime.DingoLocalDateTime) dingoDateTime;
226+
switch (targetType) {
227+
case DATE:
228+
return new DingoDateTime.DingoLocalDate(localDateTime.getValue().toLocalDate());
229+
case TIME:
230+
return new DingoDateTime.DingoLocalTime(localDateTime.getValue().toLocalTime());
231+
case TIMESTAMP:
232+
return dingoDateTime;
233+
default:
234+
throw new IllegalArgumentException("Unsupported conversion: TIMESTAMP to " + targetType);
235+
}
236+
}
237+
}
238+
}
239+
240+
throw new IllegalArgumentException("Unsupported DingoDateTime conversion: "
241+
+ dingoDateTime.getType() + " to " + targetType);
242+
}
243+
}

0 commit comments

Comments
 (0)