[fix](Nereids): datetime - offset is wrong & support Two-Digital date (#24201)

- bug: datetime - offset is wrong
- support Two-Digital date
- remove useless override code
This commit is contained in:
jakevin
2023-09-12 10:17:56 +08:00
committed by GitHub
parent 6913d68ba0
commit 484215e1cc
3 changed files with 25 additions and 23 deletions

View File

@ -32,7 +32,6 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
@ -129,24 +128,16 @@ public class DateTimeLiteral extends DateLiteral {
protected void init(String s) throws AnalysisException {
try {
TemporalAccessor dateTime = null;
int offset = 0;
// parse timezone
if (haveTimeZoneOffset(s) || haveTimeZoneName(s)) {
String tzString = new String();
if (haveTimeZoneName(s)) { // GMT, UTC+8, Z[, CN, Asia/Shanghai]
int split = getTimeZoneSplitPos(s);
Preconditions.checkArgument(split > 0);
tzString = s.substring(split);
s = s.substring(0, split);
} else { // +04:30
Preconditions.checkArgument(s.charAt(s.length() - 6) == '-' || s.charAt(s.length() - 6) == '+');
tzString = s.substring(s.length() - 6);
s = s.substring(0, s.length() - 6);
}
ZoneId zone = ZoneId.of(tzString);
ZoneId dorisZone = DateUtils.getTimeZone();
offset = dorisZone.getRules().getOffset(java.time.Instant.now()).getTotalSeconds()
- zone.getRules().getOffset(java.time.Instant.now()).getTotalSeconds();
}
if (!s.contains("-") && !s.contains(":")) {
dateTime = DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER.parse(s);
@ -220,16 +211,6 @@ public class DateTimeLiteral extends DateLiteral {
second = DateUtils.getOrDefault(dateTime, ChronoField.SECOND_OF_MINUTE);
microSecond = DateUtils.getOrDefault(dateTime, ChronoField.MICRO_OF_SECOND);
if (offset != 0) {
DateTimeLiteral result = (DateTimeLiteral) this.plusSeconds(offset);
this.second = result.second;
this.minute = result.minute;
this.hour = result.hour;
this.day = result.day;
this.month = result.month;
this.year = result.year;
}
} catch (Exception ex) {
throw new AnalysisException("datetime literal [" + s + "] is invalid");
}

View File

@ -41,12 +41,12 @@ import java.time.temporal.ChronoField;
public class DateTimeFormatterUtils {
// Date: %Y-%m-%d
public static DateTimeFormatter DATE_FORMATTER = new DateTimeFormatterBuilder()
.appendOptional(new DateTimeFormatterBuilder().appendValue(ChronoField.YEAR, 4).toFormatter())
.appendOptional(new DateTimeFormatterBuilder().appendValue(ChronoField.YEAR, 2).toFormatter())
.appendOptional(
new DateTimeFormatterBuilder().appendValue(ChronoField.YEAR, 4).toFormatter())
.appendOptional(
new DateTimeFormatterBuilder().appendValueReduced(ChronoField.YEAR, 2, 2, 1970).toFormatter())
.appendLiteral('-').appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-').appendValue(ChronoField.DAY_OF_MONTH, 2)
// if year isn't present, use -1 as default, so that it can be rejected by check
.parseDefaulting(ChronoField.YEAR, -1)
.toFormatter().withResolverStyle(ResolverStyle.STRICT);
// Date without delimiter: %Y%m%d
public static DateTimeFormatter BASIC_DATE_FORMATTER = new DateTimeFormatterBuilder()

View File

@ -58,4 +58,25 @@ class DateTimeFormatterUtilsTest {
Assertions.assertThrows(DateTimeParseException.class, () -> formatter.parse("20200219T010101."));
Assertions.assertThrows(DateTimeParseException.class, () -> formatter.parse("20200219T010101.0000001"));
}
@Test
void testTwoDigitalDate() {
DateTimeFormatter formatter = DateTimeFormatterUtils.DATE_FORMATTER;
// Year values in the range 00-69 become 2000-2069.
// Year values in the range 70-99 become 1970-199
for (int i = 0; i < 100; i++) {
String str;
if (i < 10) {
str = "0" + i + "-02-19";
} else {
str = i + "-02-19";
}
TemporalAccessor dateTime = formatter.parse(str);
if (i < 70) {
Assertions.assertEquals(2000 + i, dateTime.get(ChronoField.YEAR));
} else {
Assertions.assertEquals(1900 + i, dateTime.get(ChronoField.YEAR));
}
}
}
}