This is an automated email from the ASF dual-hosted git repository.

kxiao pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-2.0 by this push:
     new 2961a2f9176 [opt](Nereids): new Date/Datetime parser (#24523)
2961a2f9176 is described below

commit 2961a2f9176448e17a43bd9144f5f4d79712d58e
Author: jakevin <[email protected]>
AuthorDate: Wed Oct 11 23:01:08 2023 +0800

    [opt](Nereids): new Date/Datetime parser (#24523)
    
    cherry picked from commit bf808e9aa68c3f1761dfdcec8c9ffae8231ec0d5
---
 .../doris/nereids/parser/LogicalPlanBuilder.java   |   2 +-
 .../expression/rules/FoldConstantRuleOnFE.java     |  19 +-
 .../doris/nereids/trees/expressions/Cast.java      |  19 +-
 .../functions/BuiltinFunctionBuilder.java          |   2 +-
 .../expressions/functions/scalar/ConvertTz.java    |  16 +-
 .../trees/expressions/literal/DateLiteral.java     | 208 ++++++++--
 .../trees/expressions/literal/DateTimeLiteral.java | 227 ++++-------
 .../expressions/literal/DateTimeV2Literal.java     |  85 ++--
 .../trees/expressions/literal/DateV2Literal.java   |  15 +-
 .../apache/doris/nereids/types/DateTimeV2Type.java |   7 +-
 .../doris/nereids/types/coercion/DateLikeType.java |  27 ++
 .../doris/nereids/util/DateTimeFormatterUtils.java |  68 +++-
 .../doris/nereids/util/StandardDateFormat.java     |  53 +++
 .../rules/SimplifyComparisonPredicateSqlTest.java  | 159 ++++++++
 .../rules/SimplifyComparisonPredicateTest.java     |  16 +-
 .../trees/expressions/LiteralEqualTest.java        |  45 +++
 .../trees/expressions/literal/DateLiteralTest.java | 134 +++++++
 .../expressions/literal/DateTimeLiteralTest.java   | 437 +++++++++++++++++++++
 .../doris/nereids/types/AbstractDataTypeTest.java  |   8 +-
 .../nereids/util/DateTimeFormatterUtilsTest.java   |  92 +++--
 .../correctness/test_time_diff_microseconds.out    |   2 +-
 .../array_functions/test_array_with_scale_type.out |  10 +-
 .../cast_function/test_cast_with_scale_type.out    |   6 +-
 .../test_simplify_comparison.groovy                |  51 ---
 24 files changed, 1354 insertions(+), 354 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
index 5fb76afcca5..0fe54f9069b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java
@@ -1111,7 +1111,7 @@ public class LogicalPlanBuilder extends 
DorisParserBaseVisitor<Object> {
         List<String> types = typedVisit(ctx.dataType());
         DataType dataType = DataType.convertPrimitiveFromStrings(types, true);
         Expression cast = ParserUtils.withOrigin(ctx, () ->
-                new Cast(getExpression(ctx.expression()), dataType));
+                new Cast(getExpression(ctx.expression()), dataType, true));
         if (dataType.isStringLikeType() && ((CharacterType) dataType).getLen() 
>= 0) {
             List<Expression> args = ImmutableList.of(
                     cast,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
index c427ea8ec99..008db0dbce2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rules/FoldConstantRuleOnFE.java
@@ -18,6 +18,7 @@
 package org.apache.doris.nereids.rules.expression.rules;
 
 import org.apache.doris.cluster.ClusterNamespace;
+import org.apache.doris.nereids.exceptions.AnalysisException;
 import org.apache.doris.nereids.rules.expression.AbstractExpressionRewriteRule;
 import org.apache.doris.nereids.rules.expression.ExpressionRewriteContext;
 import org.apache.doris.nereids.trees.expressions.AggregateExpression;
@@ -63,10 +64,12 @@ import 
org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
 import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
 import org.apache.doris.nereids.trees.expressions.literal.Literal;
 import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
 import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral;
 import org.apache.doris.nereids.types.BooleanType;
 import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.coercion.DateLikeType;
 import org.apache.doris.nereids.util.ExpressionUtils;
 import org.apache.doris.qe.GlobalVariable;
 
@@ -310,12 +313,24 @@ public class FoldConstantRuleOnFE extends 
AbstractExpressionRewriteRule {
             return checkedExpr.get();
         }
         Expression child = cast.child();
+        DataType dataType = cast.getDataType();
         // todo: process other null case
         if (child.isNullLiteral()) {
-            return new NullLiteral(cast.getDataType());
+            return new NullLiteral(dataType);
+        } else if (child instanceof StringLikeLiteral && dataType instanceof 
DateLikeType) {
+            try {
+                return ((DateLikeType) 
dataType).fromString(((StringLikeLiteral) child).getStringValue());
+            } catch (AnalysisException t) {
+                if (cast.isExplicitType()) {
+                    return new NullLiteral(dataType);
+                } else {
+                    // If cast is from type coercion, we don't use NULL 
literal and will throw exception.
+                    throw t;
+                }
+            }
         }
         try {
-            Expression castResult = child.checkedCastTo(cast.getDataType());
+            Expression castResult = child.checkedCastTo(dataType);
             if (!Objects.equals(castResult, cast) && 
!Objects.equals(castResult, child)) {
                 castResult = rewrite(castResult, context);
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
index c450e7f7a20..e50acf7d01e 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Cast.java
@@ -33,16 +33,31 @@ import java.util.Objects;
  */
 public class Cast extends Expression implements UnaryExpression {
 
+    // CAST can be from SQL Query or Type Coercion.
+    private final boolean isExplicitType;
+
     private final DataType targetType;
 
+    public Cast(Expression child, DataType targetType, boolean isExplicitType) 
{
+        super(ImmutableList.of(child));
+        this.targetType = Objects.requireNonNull(targetType, "targetType can 
not be null");
+        this.isExplicitType = isExplicitType;
+    }
+
     public Cast(Expression child, DataType targetType) {
         super(ImmutableList.of(child));
         this.targetType = Objects.requireNonNull(targetType, "targetType can 
not be null");
+        this.isExplicitType = false;
     }
 
-    private Cast(List<Expression> child, DataType targetType) {
+    private Cast(List<Expression> child, DataType targetType, boolean 
isExplicitType) {
         super(child);
         this.targetType = Objects.requireNonNull(targetType, "targetType can 
not be null");
+        this.isExplicitType = isExplicitType;
+    }
+
+    public boolean isExplicitType() {
+        return isExplicitType;
     }
 
     @Override
@@ -72,7 +87,7 @@ public class Cast extends Expression implements 
UnaryExpression {
     @Override
     public Cast withChildren(List<Expression> children) {
         Preconditions.checkArgument(children.size() == 1);
-        return new Cast(children, getDataType());
+        return new Cast(children, targetType, isExplicitType);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BuiltinFunctionBuilder.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BuiltinFunctionBuilder.java
index 23bc62e5f04..74c4a918cf0 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BuiltinFunctionBuilder.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BuiltinFunctionBuilder.java
@@ -83,7 +83,7 @@ public class BuiltinFunctionBuilder extends FunctionBuilder {
             if (isVariableLength) {
                 return 
builderMethod.newInstance(toVariableLengthArguments(arguments));
             } else {
-                return 
builderMethod.newInstance(arguments.stream().toArray(Object[]::new));
+                return builderMethod.newInstance(arguments.toArray());
             }
         } catch (Throwable t) {
             String argString = arguments.stream()
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
index 17a0ccfb334..75270fa022b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/ConvertTz.java
@@ -18,9 +18,12 @@
 package org.apache.doris.nereids.trees.expressions.functions.scalar;
 
 import org.apache.doris.catalog.FunctionSignature;
+import org.apache.doris.nereids.trees.expressions.Cast;
 import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.functions.AlwaysNullable;
 import 
org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLikeLiteral;
 import org.apache.doris.nereids.trees.expressions.shape.TernaryExpression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeType;
@@ -49,7 +52,18 @@ public class ConvertTz extends ScalarFunction
      * constructor with 3 arguments.
      */
     public ConvertTz(Expression arg0, Expression arg1, Expression arg2) {
-        super("convert_tz", arg0, arg1, arg2);
+        super("convert_tz", castDateTime(arg0), arg1, arg2);
+    }
+
+    private static Expression castDateTime(Expression arg0) {
+        // 
https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_convert-tz
+        // convert_tz() should be explicit cast, so we create a explicit cast 
here
+        try {
+            return arg0 instanceof StringLikeLiteral ? new Cast(arg0, 
DateTimeV2Type.forTypeFromString(
+                    ((StringLikeLiteral) arg0).getStringValue()), true) : arg0;
+        } catch (Exception e) {
+            return new NullLiteral(DateTimeV2Type.SYSTEM_DEFAULT);
+        }
     }
 
     /**
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
index e4447e18477..eef80b6020c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteral.java
@@ -27,14 +27,13 @@ import org.apache.doris.nereids.types.DateType;
 import org.apache.doris.nereids.types.coercion.DateLikeType;
 import org.apache.doris.nereids.util.DateTimeFormatterUtils;
 import org.apache.doris.nereids.util.DateUtils;
+import org.apache.doris.nereids.util.StandardDateFormat;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
 import java.time.LocalDateTime;
 import java.time.Year;
-import java.time.format.DateTimeFormatter;
-import java.time.format.ResolverStyle;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
 
@@ -44,10 +43,7 @@ import java.time.temporal.TemporalAccessor;
 public class DateLiteral extends Literal {
     public static final String JAVA_DATE_FORMAT = "yyyy-MM-dd";
 
-    protected static DateTimeFormatter DATE_FORMATTER = null;
-    protected static DateTimeFormatter DATE_FORMATTER_TWO_DIGIT = null;
     // for cast datetime type to date type.
-    protected static DateTimeFormatter DATE_TIME_FORMATTER = null;
     private static final LocalDateTime startOfAD = LocalDateTime.of(0, 1, 1, 
0, 0, 0);
     private static final LocalDateTime endOfAD = LocalDateTime.of(9999, 12, 
31, 23, 59, 59);
     private static final Logger LOG = LogManager.getLogger(DateLiteral.class);
@@ -55,26 +51,11 @@ public class DateLiteral extends Literal {
     private static final DateLiteral MIN_DATE = new DateLiteral(0000, 1, 1);
     private static final DateLiteral MAX_DATE = new DateLiteral(9999, 12, 31);
     private static final int[] DAYS_IN_MONTH = new int[] {0, 31, 28, 31, 30, 
31, 30, 31, 31, 30, 31, 30, 31};
-    private static final int DATEKEY_LENGTH = 8;
 
     protected long year;
     protected long month;
     protected long day;
 
-    static {
-        try {
-            DATE_FORMATTER = DateUtils.formatBuilder("%Y-%m-%d").toFormatter()
-                    .withResolverStyle(ResolverStyle.STRICT);
-            DATE_FORMATTER_TWO_DIGIT = 
DateUtils.formatBuilder("%y-%m-%d").toFormatter()
-                    .withResolverStyle(ResolverStyle.STRICT);
-            DATE_TIME_FORMATTER = DateUtils.formatBuilder("%Y-%m-%d 
%H:%i:%s").toFormatter()
-                    .withResolverStyle(ResolverStyle.STRICT);
-        } catch (AnalysisException e) {
-            LOG.error("invalid date format", e);
-            System.exit(-1);
-        }
-    }
-
     public DateLiteral(String s) throws AnalysisException {
         this(DateType.INSTANCE, s);
     }
@@ -115,27 +96,176 @@ public class DateLiteral extends Literal {
         this.day = other.day;
     }
 
-    protected void init(String s) throws AnalysisException {
+    // normalize yymmdd -> yyyymmdd
+    static String normalizeBasic(String s) {
+        java.util.function.UnaryOperator<String> normalizeTwoDigit = (input) 
-> {
+            String yy = input.substring(0, 2);
+            int year = Integer.parseInt(yy);
+            if (year >= 0 && year <= 69) {
+                input = "20" + input;
+            } else if (year >= 70 && year <= 99) {
+                input = "19" + input;
+            }
+            return input;
+        };
+
+        // s.len == 6, assume it is "yymmdd"
+        // 'T' exists, assume it is "yymmddT......"
+        if (s.length() == 6
+                || (s.length() > 6 && s.charAt(6) == 'T')) {
+            // check s index 0 - 6 all is digit char
+            for (int i = 0; i < 6; i++) {
+                if (!Character.isDigit(s.charAt(i))) {
+                    return s;
+                }
+            }
+            return normalizeTwoDigit.apply(s);
+        }
+
+        // handle yymmddHHMMSS
+        if (s.length() >= 12) {
+            // check s index 0 - 11 all is digit char
+            for (int i = 0; i < 12; i++) {
+                if (!Character.isDigit(s.charAt(i))) {
+                    return s;
+                }
+            }
+            if (s.length() == 12 || !Character.isDigit(s.charAt(12))) {
+                return normalizeTwoDigit.apply(s);
+            }
+        }
+
+        return s;
+    }
+
+    static String normalize(String s) {
+        StringBuilder sb = new StringBuilder();
+
+        int i = 0;
+
+        // handle two digit year
+        if (s.charAt(2) != '-' && s.charAt(4) != '-') {
+            throw new AnalysisException("date/datetime literal [" + s + "] is 
invalid");
+        }
+        if (s.charAt(2) == '-') {
+            String yy = s.substring(0, 2);
+            int year = Integer.parseInt(yy);
+            if (year >= 0 && year <= 69) {
+                sb.append("20");
+            } else if (year >= 70 && year <= 99) {
+                sb.append("19");
+            }
+            sb.append(yy);
+            i = 2;
+        }
+
+        // normalized leading 0
+        while (i < s.length()) {
+            char c = s.charAt(i);
+
+            if (c == '.') {
+                // skip .microsecond, such as .0001 .000001
+                sb.append(c);  // Append the dot itself
+                i += 1;  // Skip the dot
+
+                // skip the microsecond part
+                while (i < s.length() && Character.isDigit(s.charAt(i))) {
+                    sb.append(s.charAt(i));
+                    i += 1;
+                }
+            } else if (Character.isDigit(c)) {
+                // find consecutive digit
+                int j = i + 1;
+                while (j < s.length() && Character.isDigit(s.charAt(j))) {
+                    j += 1;
+                }
+                int len = j - i;
+                if (len == 4 || len == 2) {
+                    for (int k = i; k < j; k++) {
+                        sb.append(s.charAt(k));
+                    }
+                } else if (len == 1) {
+                    sb.append('0');
+                    sb.append(c);
+                } else {
+                    throw new AnalysisException("date/datetime literal [" + s 
+ "] is invalid");
+                }
+                i = j;
+            } else {
+                sb.append(c);
+                i += 1;
+            }
+        }
+
+        int len = sb.length();
+        // Replace delimiter 'T' with ' '
+        if (len > 10 && sb.charAt(10) == 'T') {
+            sb.setCharAt(10, ' ');
+        }
+
+        // add missing Minute Second in Time part
+        if (len > 10 && sb.charAt(10) == ' ') {
+            if (len == 13 || len > 13 && sb.charAt(13) != ':') {
+                sb.insert(13, ":00:00");
+            } else if (len == 16 || (len > 16 && sb.charAt(16) != ':')) {
+                sb.insert(16, ":00");
+            }
+        }
+
+        len = sb.length();
+        int signIdx = sb.indexOf("+", 10); // from index:10, skip date part 
(it contains '-')
+        signIdx = signIdx == -1 ? sb.indexOf("-", 10) : signIdx;
+        if (signIdx != -1 && len - signIdx == 3) {
+            sb.append(":00");
+        }
+
+        return sb.toString();
+    }
+
+    protected static TemporalAccessor parse(String s) {
+        String originalString = s;
         try {
             TemporalAccessor dateTime;
+
+            // parse condition without '-' and ':'
             if (!s.contains("-") && !s.contains(":")) {
-                dateTime = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER.parse(s);
-            } else if (s.split("-")[0].length() == 2) {
-                dateTime = DATE_FORMATTER_TWO_DIGIT.parse(s);
-            } else if (s.length() == 19) {
-                dateTime = DATE_TIME_FORMATTER.parse(s);
+                s = normalizeBasic(s);
+                // mysql reject "20200219 010101" "200219 010101", can't use ' 
' spilt basic date time.
+                if (!s.contains("T")) {
+                    dateTime = 
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T.parse(s);
+                } else {
+                    dateTime = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER.parse(s);
+                }
+                return dateTime;
+            }
+
+            s = normalize(s);
+
+            if (!s.contains(" ")) {
+                dateTime = DateTimeFormatterUtils.ZONE_DATE_FORMATTER.parse(s);
             } else {
-                dateTime = DATE_FORMATTER.parse(s);
+                dateTime = 
DateTimeFormatterUtils.ZONE_DATE_TIME_FORMATTER.parse(s);
             }
-            year = DateUtils.getOrDefault(dateTime, ChronoField.YEAR);
-            month = DateUtils.getOrDefault(dateTime, 
ChronoField.MONTH_OF_YEAR);
-            day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
+
+            // if Year is not present, throw exception
+            if (!dateTime.isSupported(ChronoField.YEAR)) {
+                throw new AnalysisException("date/datetime literal [" + 
originalString + "] is invalid");
+            }
+
+            return dateTime;
         } catch (Exception ex) {
-            throw new AnalysisException("date literal [" + s + "] is invalid");
+            throw new AnalysisException("date/datetime literal [" + 
originalString + "] is invalid");
         }
+    }
+
+    protected void init(String s) throws AnalysisException {
+        TemporalAccessor dateTime = parse(s);
+        year = DateUtils.getOrDefault(dateTime, ChronoField.YEAR);
+        month = DateUtils.getOrDefault(dateTime, ChronoField.MONTH_OF_YEAR);
+        day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
 
         if (checkRange() || checkDate()) {
-            throw new AnalysisException("date literal [" + s + "] is out of 
range");
+            throw new AnalysisException("date/datetime literal [" + s + "] is 
out of range");
         }
     }
 
@@ -204,16 +334,18 @@ public class DateLiteral extends Literal {
         return day;
     }
 
-    public Expression plusDays(int days) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusDays(days));
+    public Expression plusDays(long days) {
+        return 
fromJavaDateType(DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusDays(days));
     }
 
-    public Expression plusMonths(int months) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusMonths(months));
+    public Expression plusMonths(long months) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusMonths(months));
     }
 
-    public Expression plusYears(int years) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusYears(years));
+    public Expression plusYears(long years) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusYears(years));
     }
 
     public LocalDateTime toJavaDateType() {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
index 1b3d415553d..2d5ea77072b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteral.java
@@ -24,31 +24,24 @@ import 
org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeType;
 import org.apache.doris.nereids.types.coercion.DateLikeType;
-import org.apache.doris.nereids.util.DateTimeFormatterUtils;
 import org.apache.doris.nereids.util.DateUtils;
+import org.apache.doris.nereids.util.StandardDateFormat;
 
-import com.google.common.base.Preconditions;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import java.time.Instant;
 import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeFormatterBuilder;
-import java.time.format.ResolverStyle;
+import java.time.ZoneId;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
-import java.util.Collections;
+import java.time.temporal.TemporalQueries;
 import java.util.Objects;
-import java.util.regex.Pattern;
 
 /**
  * date time literal.
  */
 public class DateTimeLiteral extends DateLiteral {
-    protected static DateTimeFormatter DATE_TIME_FORMATTER_TO_HOUR = null;
-    protected static DateTimeFormatter DATE_TIME_FORMATTER_TO_MINUTE = null;
-    protected static DateTimeFormatter DATE_TIME_FORMATTER_TWO_DIGIT = null;
-    protected static DateTimeFormatter DATE_TIME_FORMATTER_TO_MICRO_SECOND = 
null;
     protected static final int MAX_MICROSECOND = 999999;
 
     private static final DateTimeLiteral MIN_DATETIME = new 
DateTimeLiteral(0000, 1, 1, 0, 0, 0);
@@ -56,35 +49,11 @@ public class DateTimeLiteral extends DateLiteral {
 
     private static final Logger LOG = 
LogManager.getLogger(DateTimeLiteral.class);
 
-    private static final Pattern HAS_OFFSET_PART = 
Pattern.compile("[\\+\\-]\\d{2}:\\d{2}");
-
     protected long hour;
     protected long minute;
     protected long second;
     protected long microSecond;
 
-    static {
-        try {
-            DATE_TIME_FORMATTER = DateUtils.formatBuilder("%Y-%m-%d %H:%i:%s")
-                    .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-            DATE_TIME_FORMATTER_TO_HOUR = DateUtils.formatBuilder("%Y-%m-%d 
%H")
-                    .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-            DATE_TIME_FORMATTER_TO_MINUTE = DateUtils.formatBuilder("%Y-%m-%d 
%H:%i")
-                    .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-            DATE_TIME_FORMATTER_TWO_DIGIT = DateUtils.formatBuilder("%y-%m-%d 
%H:%i:%s")
-                    .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-
-            DATE_TIME_FORMATTER_TO_MICRO_SECOND = new 
DateTimeFormatterBuilder()
-                    .appendPattern("uuuu-MM-dd HH:mm:ss")
-                    .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true)
-                    .toFormatter()
-                    .withResolverStyle(ResolverStyle.STRICT);
-        } catch (AnalysisException e) {
-            LOG.error("invalid date format", e);
-            System.exit(-1);
-        }
-    }
-
     public DateTimeLiteral(String s) {
         this(DateTimeType.INSTANCE, s);
     }
@@ -128,95 +97,60 @@ public class DateTimeLiteral extends DateLiteral {
         return hour == 0 && minute == 0 && second == 0 && microSecond == 0;
     }
 
-    @Override
-    protected void init(String s) throws AnalysisException {
-        try {
-            TemporalAccessor dateTime = null;
-            // parse timezone
-            if (haveTimeZoneOffset(s) || haveTimeZoneName(s)) {
-                if (haveTimeZoneName(s)) { // GMT, UTC+8, Z[, CN, 
Asia/Shanghai]
-                    int split = getTimeZoneSplitPos(s);
-                    Preconditions.checkArgument(split > 0);
-                    s = s.substring(0, split);
-                } else { // +04:30
-                    Preconditions.checkArgument(s.charAt(s.length() - 6) == 
'-' || s.charAt(s.length() - 6) == '+');
-                    s = s.substring(0, s.length() - 6);
-                }
+    /**
+     * determine scale by datetime string
+     */
+    public static int determineScale(String s) {
+        if (!s.contains("-") && !s.contains(":")) {
+            return 0;
+        }
+        s = normalize(s);
+        if (s.length() <= 19 || s.charAt(19) != '.') {
+            return 0;
+        }
+        // from index 19 find the index of first char which is not digit
+        int scale = 0;
+        for (int i = 20; i < s.length(); i++) {
+            if (!Character.isDigit(s.charAt(i))) {
+                break;
             }
-            if (!s.contains("-") && !s.contains(":")) {
-                dateTime = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER.parse(s);
-            } else {
-                String[] datePart = s.contains(" ") ? s.split(" 
")[0].split("-") : s.split("-");
-                DateTimeFormatterBuilder builder = new 
DateTimeFormatterBuilder();
-                if (datePart.length != 3) {
-                    throw new AnalysisException("datetime literal [" + s + "] 
is invalid");
-                }
-                for (int i = 0; i < datePart.length; i++) {
-                    switch (i) {
-                        case 0:
-                            if (datePart[i].length() == 2) {
-                                // If year is represented by two digits, 
number bigger than 70 will be prefixed
-                                // with 19 otherwise 20. e.g. 69 -> 2069, 70 
-> 1970.
-                                builder.appendValueReduced(ChronoField.YEAR, 
2, 2, 1970);
-                            } else {
-                                builder.appendPattern(String.join("", 
Collections.nCopies(datePart[i].length(), "u")));
-                            }
-                            break;
-                        case 1:
-                            builder.appendPattern(String.join("", 
Collections.nCopies(datePart[i].length(), "M")));
-                            break;
-                        case 2:
-                            builder.appendPattern(String.join("", 
Collections.nCopies(datePart[i].length(), "d")));
-                            break;
-                        default:
-                            throw new AnalysisException("two many parts in 
date format " + s);
-                    }
-                    if (i < datePart.length - 1) {
-                        builder.appendLiteral("-");
-                    }
-                }
-                if (s.contains(" ")) {
-                    builder.appendLiteral(" ");
-                }
-                String[] timePart = s.contains(" ") ? s.split(" 
")[1].split(":") : new String[]{};
-                for (int i = 0; i < timePart.length; i++) {
-                    switch (i) {
-                        case 0:
-                            builder.appendPattern(String.join("", 
Collections.nCopies(timePart[i].length(), "H")));
-                            break;
-                        case 1:
-                            builder.appendPattern(String.join("", 
Collections.nCopies(timePart[i].length(), "m")));
-                            break;
-                        case 2:
-                            builder.appendPattern(String.join("", 
Collections.nCopies(timePart[i].contains(".")
-                                    ? timePart[i].split("\\.")[0].length() : 
timePart[i].length(), "s")));
-                            if (timePart[i].contains(".")) {
-                                
builder.appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true);
-                            }
-                            break;
-                        default:
-                            throw new AnalysisException("too many parts in 
time format " + s);
-                    }
-                    if (i < timePart.length - 1) {
-                        builder.appendLiteral(":");
-                    }
-                }
-                // The default resolver style is 'SMART', which parses 
"2022-06-31" as "2022-06-30"
-                // and does not throw an exception. 'STRICT' is used here.
-                DateTimeFormatter formatter = 
builder.toFormatter().withResolverStyle(ResolverStyle.STRICT);
-                dateTime = formatter.parse(s);
+            scale++;
+        }
+        // trim the tailing zero
+        for (int i = 19 + scale; i >= 19; i--) {
+            if (s.charAt(i) != '0') {
+                break;
             }
+            scale--;
+        }
+        return scale;
+    }
 
-            year = DateUtils.getOrDefault(dateTime, ChronoField.YEAR);
-            month = DateUtils.getOrDefault(dateTime, 
ChronoField.MONTH_OF_YEAR);
-            day = DateUtils.getOrDefault(dateTime, ChronoField.DAY_OF_MONTH);
-            hour = DateUtils.getOrDefault(dateTime, ChronoField.HOUR_OF_DAY);
-            minute = DateUtils.getOrDefault(dateTime, 
ChronoField.MINUTE_OF_HOUR);
-            second = DateUtils.getOrDefault(dateTime, 
ChronoField.SECOND_OF_MINUTE);
-            microSecond = DateUtils.getOrDefault(dateTime, 
ChronoField.MICRO_OF_SECOND);
-
-        } catch (Exception ex) {
-            throw new AnalysisException("datetime literal [" + s + "] is 
invalid");
+    @Override
+    protected void init(String s) throws AnalysisException {
+        TemporalAccessor temporal = parse(s);
+
+        year = DateUtils.getOrDefault(temporal, ChronoField.YEAR);
+        month = DateUtils.getOrDefault(temporal, ChronoField.MONTH_OF_YEAR);
+        day = DateUtils.getOrDefault(temporal, ChronoField.DAY_OF_MONTH);
+        hour = DateUtils.getOrDefault(temporal, ChronoField.HOUR_OF_DAY);
+        minute = DateUtils.getOrDefault(temporal, ChronoField.MINUTE_OF_HOUR);
+        second = DateUtils.getOrDefault(temporal, 
ChronoField.SECOND_OF_MINUTE);
+        microSecond = DateUtils.getOrDefault(temporal, 
ChronoField.MICRO_OF_SECOND);
+
+        ZoneId zoneId = temporal.query(TemporalQueries.zone());
+        if (zoneId != null) {
+            int offset = 
DateUtils.getTimeZone().getRules().getOffset(Instant.now()).getTotalSeconds()
+                    - 
zoneId.getRules().getOffset(Instant.now()).getTotalSeconds();
+            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;
+            }
         }
 
         if (checkRange() || checkDate()) {
@@ -265,28 +199,34 @@ public class DateTimeLiteral extends DateLiteral {
         return new org.apache.doris.analysis.DateLiteral(year, month, day, 
hour, minute, second, Type.DATETIME);
     }
 
-    public Expression plusYears(int years) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusYears(years));
+    public Expression plusYears(long years) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusYears(years));
     }
 
-    public Expression plusMonths(int months) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusMonths(months));
+    public Expression plusMonths(long months) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusMonths(months));
     }
 
-    public Expression plusDays(int days) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusDays(days));
+    public Expression plusDays(long days) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusDays(days));
     }
 
-    public Expression plusHours(int hours) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusHours(hours));
+    public Expression plusHours(long hours) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusHours(hours));
     }
 
-    public Expression plusMinutes(int minutes) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusMinutes(minutes));
+    public Expression plusMinutes(long minutes) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusMinutes(minutes));
     }
 
     public Expression plusSeconds(long seconds) {
-        return fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER, 
getStringValue()).plusSeconds(seconds));
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER, 
getStringValue()).plusSeconds(seconds));
     }
 
     public long getHour() {
@@ -328,27 +268,4 @@ public class DateTimeLiteral extends DateLiteral {
                 : new DateTimeLiteral(dateTime.getYear(), 
dateTime.getMonthValue(), dateTime.getDayOfMonth(),
                         dateTime.getHour(), dateTime.getMinute(), 
dateTime.getSecond());
     }
-
-    private static boolean haveTimeZoneOffset(String arg) {
-        Preconditions.checkArgument(arg.length() > 6);
-        return HAS_OFFSET_PART.matcher(arg.substring(arg.length() - 
6)).matches();
-    }
-
-    private static boolean haveTimeZoneName(String arg) {
-        for (char ch : arg.toCharArray()) {
-            if (Character.isUpperCase(ch) && ch != 'T') {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static int getTimeZoneSplitPos(String arg) {
-        int split = arg.length() - 1;
-        for (; !Character.isAlphabetic(arg.charAt(split)); split--) {
-        } // skip +8 of UTC+8
-        for (; split >= 0 && (Character.isUpperCase(arg.charAt(split)) || 
arg.charAt(split) == '/'); split--) {
-        }
-        return split + 1;
-    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
index ef09399a5aa..87b881074f1 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeV2Literal.java
@@ -23,6 +23,9 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateTimeV2Type;
 import org.apache.doris.nereids.util.DateUtils;
+import org.apache.doris.nereids.util.StandardDateFormat;
+
+import com.google.common.base.Preconditions;
 
 import java.time.LocalDateTime;
 
@@ -37,6 +40,7 @@ public class DateTimeV2Literal extends DateTimeLiteral {
 
     public DateTimeV2Literal(DateTimeV2Type dateType, String s) {
         super(dateType, s);
+        roundMicroSecond(dateType.getScale());
     }
 
     public DateTimeV2Literal(long year, long month, long day, long hour, long 
minute, long second) {
@@ -47,9 +51,30 @@ public class DateTimeV2Literal extends DateTimeLiteral {
         super(DateTimeV2Type.SYSTEM_DEFAULT, year, month, day, hour, minute, 
second, microSecond);
     }
 
-    public DateTimeV2Literal(DateTimeV2Type dataType,
+    public DateTimeV2Literal(DateTimeV2Type dateType,
             long year, long month, long day, long hour, long minute, long 
second, long microSecond) {
-        super(dataType, year, month, day, hour, minute, second, microSecond);
+        super(dateType, year, month, day, hour, minute, second, microSecond);
+        roundMicroSecond(dateType.getScale());
+    }
+
+    private void roundMicroSecond(int scale) {
+        Preconditions.checkArgument(scale >= 0 && scale <= 
DateTimeV2Type.MAX_SCALE,
+                "invalid datetime v2 scale: %s", scale);
+        double factor = Math.pow(10, 6 - scale);
+
+        this.microSecond = Math.round(this.microSecond / factor) * (int) 
factor;
+
+        if (this.microSecond >= 1000000) {
+            LocalDateTime localDateTime = 
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND,
+                            getStringValue()).plusSeconds(1);
+            this.year = localDateTime.getYear();
+            this.month = localDateTime.getMonthValue();
+            this.day = localDateTime.getDayOfMonth();
+            this.hour = localDateTime.getHour();
+            this.minute = localDateTime.getMinute();
+            this.second = localDateTime.getSecond();
+            this.microSecond -= 1000000;
+        }
     }
 
     @Override
@@ -76,50 +101,57 @@ public class DateTimeV2Literal extends DateTimeLiteral {
     @Override
     public String getStringValue() {
         return String.format("%04d-%02d-%02d %02d:%02d:%02d"
-                + (getDataType().getScale() > 0 ? ".%0" + 
getDataType().getScale() + "d" : ""),
+                        + (getDataType().getScale() > 0 ? ".%0" + 
getDataType().getScale() + "d" : ""),
                 year, month, day, hour, minute, second,
                 (int) (microSecond / Math.pow(10, DateTimeV2Type.MAX_SCALE - 
getDataType().getScale())));
     }
 
     @Override
-    public Expression plusYears(int years) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusYears(years), getDataType().getScale());
+    public Expression plusYears(long years) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusYears(years), getDataType().getScale());
     }
 
     @Override
-    public Expression plusMonths(int months) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusMonths(months), getDataType().getScale());
+    public Expression plusMonths(long months) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusMonths(months), getDataType().getScale());
     }
 
     @Override
-    public Expression plusDays(int days) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusDays(days), getDataType().getScale());
+    public Expression plusDays(long days) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusDays(days), getDataType().getScale());
     }
 
     @Override
-    public Expression plusHours(int hours) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusHours(hours), getDataType().getScale());
+    public Expression plusHours(long hours) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusHours(hours), getDataType().getScale());
     }
 
     @Override
-    public Expression plusMinutes(int minutes) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusMinutes(minutes), getDataType().getScale());
+    public Expression plusMinutes(long minutes) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusMinutes(minutes), getDataType().getScale());
     }
 
     @Override
     public Expression plusSeconds(long seconds) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusSeconds(seconds), getDataType().getScale());
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusSeconds(seconds), getDataType().getScale());
     }
 
-    public Expression plusMicroSeconds(int microSeconds) {
-        return 
fromJavaDateType(DateUtils.getTime(DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
-                .plusNanos(microSeconds * 1000L), getDataType().getScale());
+    public Expression plusMicroSeconds(long microSeconds) {
+        return fromJavaDateType(
+                
DateUtils.getTime(StandardDateFormat.DATE_TIME_FORMATTER_TO_MICRO_SECOND, 
getStringValue())
+                        .plusNanos(microSeconds * 1000L), 
getDataType().getScale());
     }
 
     /**
@@ -155,11 +187,8 @@ public class DateTimeV2Literal extends DateTimeLiteral {
     }
 
     public DateTimeV2Literal roundFloor(int newScale) {
-        long newMicroSecond = Double.valueOf(
-                microSecond / (int) (Math.pow(10, 6 - newScale)) * 
(Math.pow(10, 6 - newScale)))
-                .longValue();
-        return new DateTimeV2Literal(DateTimeV2Type.of(newScale), year, month, 
day, hour, minute,
-                second, newMicroSecond);
+        // use roundMicroSecond in constructor
+        return new DateTimeV2Literal(DateTimeV2Type.of(newScale), year, month, 
day, hour, minute, second, microSecond);
     }
 
     public static Expression fromJavaDateType(LocalDateTime dateTime) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateV2Literal.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateV2Literal.java
index 928b7ca0f24..c57607892e3 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateV2Literal.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/DateV2Literal.java
@@ -24,6 +24,7 @@ import org.apache.doris.nereids.trees.expressions.Expression;
 import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
 import org.apache.doris.nereids.types.DateV2Type;
 import org.apache.doris.nereids.util.DateUtils;
+import org.apache.doris.nereids.util.StandardDateFormat;
 
 import java.time.LocalDateTime;
 
@@ -50,16 +51,18 @@ public class DateV2Literal extends DateLiteral {
         return visitor.visitDateV2Literal(this, context);
     }
 
-    public Expression plusDays(int days) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusDays(days));
+    public Expression plusDays(long days) {
+        return 
fromJavaDateType(DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusDays(days));
     }
 
-    public Expression plusMonths(int months) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusMonths(months));
+    public Expression plusMonths(long months) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusMonths(months));
     }
 
-    public Expression plusYears(int years) {
-        return fromJavaDateType(DateUtils.getTime(DATE_FORMATTER, 
getStringValue()).plusYears(years));
+    public Expression plusYears(long years) {
+        return fromJavaDateType(
+                DateUtils.getTime(StandardDateFormat.DATE_FORMATTER, 
getStringValue()).plusYears(years));
     }
 
     public static Expression fromJavaDateType(LocalDateTime dateTime) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
index 6a57c7a218c..0b8f64316bd 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DateTimeV2Type.java
@@ -20,6 +20,7 @@ package org.apache.doris.nereids.types;
 import org.apache.doris.catalog.ScalarType;
 import org.apache.doris.catalog.Type;
 import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
 import org.apache.doris.nereids.types.coercion.AbstractDataType;
 import org.apache.doris.nereids.types.coercion.DateLikeType;
 import org.apache.doris.nereids.types.coercion.IntegralType;
@@ -83,10 +84,8 @@ public class DateTimeV2Type extends DateLikeType {
      * may be we need to check for validity?
      */
     public static DateTimeV2Type forTypeFromString(String s) {
-        if (!s.contains(String.valueOf("."))) {
-            return DateTimeV2Type.SYSTEM_DEFAULT;
-        }
-        return DateTimeV2Type.of(s.length() - s.lastIndexOf(".") - 1);
+        int scale = DateTimeLiteral.determineScale(s);
+        return DateTimeV2Type.of(scale);
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/coercion/DateLikeType.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/coercion/DateLikeType.java
index 18b207fdaf7..ff728a73ace 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/coercion/DateLikeType.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/coercion/DateLikeType.java
@@ -17,6 +17,16 @@
 
 package org.apache.doris.nereids.types.coercion;
 
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.literal.DateLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.DateTimeV2Literal;
+import org.apache.doris.nereids.trees.expressions.literal.DateV2Literal;
+import org.apache.doris.nereids.types.DateTimeType;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.types.DateType;
+import org.apache.doris.nereids.types.DateV2Type;
+
 import java.time.temporal.ChronoUnit;
 import java.util.Calendar;
 
@@ -43,4 +53,21 @@ public abstract class DateLikeType extends PrimitiveType {
         Calendar from = toCalendar(low);
         return ChronoUnit.DAYS.between(from.toInstant(), to.toInstant());
     }
+
+    /**
+     * parse string to date like literal.
+     */
+    public DateLiteral fromString(String s) {
+        if (this instanceof DateType) {
+            return new DateLiteral(s);
+        } else if (this instanceof DateV2Type) {
+            return new DateV2Literal(s);
+        } else if (this instanceof DateTimeType) {
+            return new DateTimeLiteral(s);
+        } else if (this instanceof DateTimeV2Type) {
+            return new DateTimeV2Literal((DateTimeV2Type) this, s);
+        } else {
+            throw new AnalysisException("unknown date like type");
+        }
+    }
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
index 1925e100aca..e88aabc018b 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/DateTimeFormatterUtils.java
@@ -39,42 +39,68 @@ import java.time.temporal.ChronoField;
  *      Note incomplete times 'hh:mm:ss', 'hh:mm', 'D hh:mm', 'D hh', or 'ss'
  */
 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().appendValueReduced(ChronoField.YEAR, 2, 2, 
1970).toFormatter())
+    public static final DateTimeFormatter ZONE_FORMATTER = new 
DateTimeFormatterBuilder()
+            .optionalStart()
+            // .appendZoneText(TextStyle.FULL)
+            .appendZoneOrOffsetId()
+            .optionalEnd()
+            .toFormatter()
+            .withResolverStyle(ResolverStyle.STRICT);
+    public static final DateTimeFormatter DATE_FORMATTER = new 
DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4)
             .appendLiteral('-').appendValue(ChronoField.MONTH_OF_YEAR, 2)
             .appendLiteral('-').appendValue(ChronoField.DAY_OF_MONTH, 2)
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-    // Date without delimiter: %Y%m%d
-    public static DateTimeFormatter BASIC_DATE_FORMATTER = new 
DateTimeFormatterBuilder()
-            .appendValue(ChronoField.YEAR, 4)
-            .appendValue(ChronoField.MONTH_OF_YEAR, 2)
-            .appendValue(ChronoField.DAY_OF_MONTH, 2)
-            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-    // Time: %H:%i:%s
-    public static DateTimeFormatter TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+    // HH[:mm][:ss][.microsecond]
+    public static final DateTimeFormatter TIME_FORMATTER = new 
DateTimeFormatterBuilder()
             .appendValue(ChronoField.HOUR_OF_DAY, 2)
             .appendLiteral(':').appendValue(ChronoField.MINUTE_OF_HOUR, 2)
             .appendLiteral(':').appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+            .appendOptional(new DateTimeFormatterBuilder()
+                    .appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, 
true).toFormatter())
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-    // Time without delimiter: HHmmss[microsecond]
-    public static DateTimeFormatter BASIC_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+    // Time without delimiter: HHmmss[.microsecond]
+    private static final DateTimeFormatter BASIC_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
             .appendValue(ChronoField.HOUR_OF_DAY, 2)
             .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
             .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
             .appendOptional(new DateTimeFormatterBuilder()
                     .appendFraction(ChronoField.MICRO_OF_SECOND, 1, 6, 
true).toFormatter())
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
-
+    // yyyymmdd
+    private static final DateTimeFormatter BASIC_DATE_FORMATTER = new 
DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4)
+            .appendValue(ChronoField.MONTH_OF_YEAR, 2)
+            .appendValue(ChronoField.DAY_OF_MONTH, 2)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
     // Date without delimiter
-    public static DateTimeFormatter BASIC_DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+    public static final DateTimeFormatter BASIC_DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
             .append(BASIC_DATE_FORMATTER)
-            .optionalStart()
-            .appendOptional(new 
DateTimeFormatterBuilder().appendLiteral('T').toFormatter())
+            .appendLiteral('T')
             .append(BASIC_TIME_FORMATTER)
-            .optionalEnd()
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    // Date without delimiter
+    public static final DateTimeFormatter BASIC_FORMATTER_WITHOUT_T = new 
DateTimeFormatterBuilder()
+            .append(BASIC_DATE_FORMATTER)
+            .appendOptional(BASIC_TIME_FORMATTER)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+
+    // Datetime
+    public static final DateTimeFormatter DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+            .append(DATE_FORMATTER)
+            .appendLiteral(' ')
+            .append(TIME_FORMATTER)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    public static final DateTimeFormatter ZONE_DATE_FORMATTER = new 
DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4)
+            .appendLiteral('-').appendValue(ChronoField.MONTH_OF_YEAR, 2)
+            .appendLiteral('-').appendValue(ChronoField.DAY_OF_MONTH, 2)
+            .append(ZONE_FORMATTER)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    public static final DateTimeFormatter ZONE_DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+            .append(DATE_FORMATTER)
+            .appendLiteral(' ')
+            .append(TIME_FORMATTER)
+            .append(ZONE_FORMATTER)
             .toFormatter().withResolverStyle(ResolverStyle.STRICT);
 }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/StandardDateFormat.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/StandardDateFormat.java
new file mode 100644
index 00000000000..aa421eeab43
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/StandardDateFormat.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.util;
+
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.ResolverStyle;
+import java.time.temporal.ChronoField;
+
+/**
+ * Following format is *standard* format of date/datetime. It will keep format 
of memory/output/printf is standard.
+ */
+public class StandardDateFormat {
+    // Date: %Y-%m-%d
+    public static DateTimeFormatter DATE_FORMATTER = new 
DateTimeFormatterBuilder()
+            .appendValue(ChronoField.YEAR, 4)
+            .appendLiteral('-').appendValue(ChronoField.MONTH_OF_YEAR, 2)
+            .appendLiteral('-').appendValue(ChronoField.DAY_OF_MONTH, 2)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    // %H:%i:%s
+    public static DateTimeFormatter TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+            .appendValue(ChronoField.HOUR_OF_DAY, 2)
+            .appendLiteral(':').appendValue(ChronoField.MINUTE_OF_HOUR, 2)
+            .appendLiteral(':').appendValue(ChronoField.SECOND_OF_MINUTE, 2)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    public static DateTimeFormatter DATE_TIME_FORMATTER = new 
DateTimeFormatterBuilder()
+            .append(DATE_FORMATTER)
+            .appendLiteral(' ')
+            .append(TIME_FORMATTER)
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+    // "%Y-%m-%d %H:%i:%s.%f"
+    public static DateTimeFormatter DATE_TIME_FORMATTER_TO_MICRO_SECOND = new 
DateTimeFormatterBuilder()
+            .append(DATE_FORMATTER)
+            .appendLiteral(' ')
+            .append(TIME_FORMATTER)
+            .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) // 
Notice: min size is 0
+            .toFormatter().withResolverStyle(ResolverStyle.STRICT);
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateSqlTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateSqlTest.java
new file mode 100644
index 00000000000..b3a2b5c9af0
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateSqlTest.java
@@ -0,0 +1,159 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.expression.rules;
+
+import org.apache.doris.nereids.exceptions.AnalysisException;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.types.DateTimeV2Type;
+import org.apache.doris.nereids.util.MemoPatternMatchSupported;
+import org.apache.doris.nereids.util.PlanChecker;
+import org.apache.doris.utframe.TestWithFeService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class SimplifyComparisonPredicateSqlTest extends TestWithFeService implements 
MemoPatternMatchSupported {
+
+    @Override
+    protected void runBeforeAll() throws Exception {
+        createDatabase("test");
+        connectContext.setDatabase("default_cluster:test");
+        createTables(
+                "CREATE TABLE IF NOT EXISTS `log_items_test` (\n"
+                        + "            a DATETIME(0) NOT NULL,\n"
+                        + "            b decimal(10,2)\n"
+                        + "            ) ENGINE=OLAP\n"
+                        + "            UNIQUE KEY (`a`)\n"
+                        + "            DISTRIBUTED BY HASH(`a`) BUCKETS 120\n"
+                        + "            PROPERTIES (\n"
+                        + "            \"replication_num\" = \"1\",\n"
+                        + "            \"in_memory\" = \"false\",\n"
+                        + "            \"compression\" = \"LZ4\",\n"
+                        + "            \"storage_cooldown_time\" = 
\"9999-12-31 23:59:59\",\n"
+                        + "            \"enable_unique_key_merge_on_write\" = 
\"true\"\n"
+                        + "            );"
+        );
+    }
+
+    @Test
+    void testSql() {
+        PlanChecker.from(connectContext)
+                .analyze("select * from log_items_test where a < '2023-06-15 
23:59:59.999' and b < 111.111;")
+                .rewrite()
+                .matches(
+                    logicalFilter()
+                        .when(f -> f.getConjuncts().stream().anyMatch(e -> 
e.toSql().equals("(a < 2023-06-16 00:00:00)")))
+                        .when(f -> f.getConjuncts().stream().anyMatch(e -> 
e.toSql().equals("(b < 111.12)")))
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select * from log_items_test where a <= '2023-06-15 
23:59:59.999' and b <= 111.111;")
+                .rewrite()
+                .matches(
+                        logicalFilter()
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(a <= 2023-06-16 
00:00:00)")))
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(b <= 111.11)")))
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select * from log_items_test where a = '2023-06-15 
23:59:59.999' and b = 111.111;")
+                .rewrite()
+                .matches(
+                        logicalEmptyRelation()
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select * from log_items_test where a > '2023-06-15 
23:59:59.999' and b > 111.111;")
+                .rewrite()
+                .matches(
+                        logicalFilter()
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(a > 2023-06-16 
00:00:00)")))
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(b > 111.11)")))
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select * from log_items_test where a >= '2023-06-15 
23:59:59.999' and b >= 111.111;")
+                .rewrite()
+                .matches(
+                        logicalFilter()
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(a >= 2023-06-16 
00:00:00)")))
+                                .when(f -> 
f.getConjuncts().stream().anyMatch(e -> e.toSql().equals("(b >= 111.12)")))
+                );
+    }
+
+    @Test
+    void dateLikeOverflow() {
+        PlanChecker.from(connectContext)
+                .analyze("select CAST('2021-01-32 00:00:00' AS DATETIME(6))")
+                .rewrite()
+                .matches(
+                        logicalResultSink(
+                                logicalOneRowRelation().when(p -> 
p.getProjects().get(0).child(0).equals(new NullLiteral(DateTimeV2Type.of(6))))
+                        )
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select CONVERT_TZ('2021-01-32 00:00:00', '+08:00', 
'America/London') = '2021-01-30'")
+                .rewrite()
+                .matches(
+                        logicalResultSink(
+                                logicalOneRowRelation().when(p -> 
p.getProjects().get(0).child(0) instanceof NullLiteral)
+                        )
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select CONVERT_TZ('2021-01-32 00:00:00', '+08:00', 
'America/London')")
+                .rewrite()
+                .matches(
+                        logicalResultSink(
+                                logicalOneRowRelation().when(p -> 
p.getProjects().get(0).child(0) instanceof NullLiteral)
+                        )
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select CONVERT_TZ('2021-01-32 00:00:00.0000001', 
'+08:00', 'America/London')")
+                .rewrite()
+                .matches(
+                        logicalResultSink(
+                                logicalOneRowRelation().when(p -> 
p.getProjects().get(0).child(0) instanceof NullLiteral)
+                        )
+                );
+
+        PlanChecker.from(connectContext)
+                .analyze("select CONVERT_TZ('2021-01-32 00:00:00.001', 
'+08:00', 'America/London') = '2021-01-30'")
+                .rewrite()
+                .matches(
+                        logicalResultSink(
+                                logicalOneRowRelation().when(p -> 
p.getProjects().get(0).child(0) instanceof NullLiteral)
+                        )
+                );
+
+        Assertions.assertThrows(AnalysisException.class, () -> 
PlanChecker.from(connectContext)
+                .analyze("select CAST('2021-01-32 00:00:00' AS DATETIME(6)) = 
'2021-01-32 00:00:00'")
+                .rewrite()
+        );
+        Assertions.assertThrows(AnalysisException.class, () -> 
PlanChecker.from(connectContext)
+                .analyze("select CAST('2021-01-32 00:00:00' AS DATETIME(6)) = 
'2021-01-32 23:00:00'")
+                .rewrite()
+        );
+        Assertions.assertThrows(AnalysisException.class, () -> 
PlanChecker.from(connectContext)
+                .analyze("select CAST('2021-01-32 00:00:00' AS DATETIME(6)) = 
'1000'")
+                .rewrite()
+        );
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java
index 898bc2b619d..6735e31192f 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rules/SimplifyComparisonPredicateTest.java
@@ -36,7 +36,6 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 class SimplifyComparisonPredicateTest extends ExpressionRewriteTestHelper {
-
     @Test
     void testSimplifyComparisonPredicateRule() {
         executor = new ExpressionRuleExecutor(
@@ -112,4 +111,19 @@ class SimplifyComparisonPredicateTest extends 
ExpressionRewriteTestHelper {
         rewrittenExpression = executor.rewrite(typeCoercion(expression), 
context);
         Assertions.assertEquals(left.getDataType(), 
rewrittenExpression.child(0).getDataType());
     }
+
+    @Test
+    void testRound() {
+        executor = new ExpressionRuleExecutor(
+                ImmutableList.of(SimplifyCastRule.INSTANCE, 
SimplifyComparisonPredicate.INSTANCE));
+
+        Expression left = new Cast(new DateTimeLiteral("2021-01-02 
00:00:00.00"), DateTimeV2Type.of(1));
+        Expression right = new DateTimeV2Literal("2021-01-01 23:59:59.99");
+        // (cast(2021-01-02 00:00:00.00 as DATETIMEV2(1)) > 2021-01-01 
23:59:59.99)
+        Expression expression = new GreaterThan(left, right);
+        Expression rewrittenExpression = 
executor.rewrite(typeCoercion(expression), context);
+
+        // right should round to be 2021-01-02 00:00:00.00
+        Assertions.assertEquals(new DateTimeV2Literal("2021-01-02 00:00:00"), 
rewrittenExpression.child(1));
+    }
 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/LiteralEqualTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/LiteralEqualTest.java
new file mode 100644
index 00000000000..84422510fd2
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/LiteralEqualTest.java
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.nereids.trees.expressions.literal.BooleanLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.Literal;
+import org.apache.doris.nereids.trees.expressions.literal.NullLiteral;
+import org.apache.doris.nereids.trees.expressions.literal.StringLiteral;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class LiteralEqualTest {
+
+    @Test
+    void testEqual() {
+        IntegerLiteral one = new IntegerLiteral(1);
+        IntegerLiteral anotherOne = new IntegerLiteral(1);
+        IntegerLiteral two = new IntegerLiteral(2);
+        Assertions.assertNotEquals(one, two);
+        Assertions.assertEquals(one, anotherOne);
+        StringLiteral str1 = new StringLiteral("hello");
+        Assertions.assertNotEquals(str1, one);
+        Assertions.assertTrue(Literal.of("world") instanceof StringLiteral);
+        Assertions.assertTrue(Literal.of(null) instanceof NullLiteral);
+        Assertions.assertTrue(Literal.of(1) instanceof IntegerLiteral);
+        Assertions.assertTrue(Literal.of(false) instanceof BooleanLiteral);
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
new file mode 100644
index 00000000000..a03010e583e
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateLiteralTest.java
@@ -0,0 +1,134 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.literal;
+
+import org.apache.doris.nereids.exceptions.AnalysisException;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.function.Consumer;
+
+class DateLiteralTest {
+    @Test
+    void reject() {
+        // TODO: reject them.
+        // Now parse them as date + offset.
+        // PG parse them as date + offset, MySQL parse them as date + time 
(rubbish behavior!)
+        // So strange! reject these strange case.
+        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01-01"));
+        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01-1"));
+        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01+01"));
+        // Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("2022-01-01+1"));
+    }
+
+    @Test
+    void testNormalize() {
+        String s = DateLiteral.normalize("2021-5");
+        Assertions.assertEquals("2021-05", s);
+        s = DateLiteral.normalize("2021-5-1");
+        Assertions.assertEquals("2021-05-01", s);
+        s = DateLiteral.normalize("2021-5-01");
+        Assertions.assertEquals("2021-05-01", s);
+
+        s = DateLiteral.normalize("2021-5-01 0:0:0");
+        Assertions.assertEquals("2021-05-01 00:00:00", s);
+        s = DateLiteral.normalize("2021-5-01 0:0:0.001");
+        Assertions.assertEquals("2021-05-01 00:00:00.001", s);
+
+        s = DateLiteral.normalize("2021-5-01 0:0:0.001+8:0");
+        Assertions.assertEquals("2021-05-01 00:00:00.001+08:00", s);
+        s = DateLiteral.normalize("2021-5-01 0:0:0.001+8:0:0");
+        Assertions.assertEquals("2021-05-01 00:00:00.001+08:00:00", s);
+
+        s = DateLiteral.normalize("2021-5-01 0:0:0.001UTC+8:0");
+        Assertions.assertEquals("2021-05-01 00:00:00.001UTC+08:00", s);
+        s = DateLiteral.normalize("2021-5-01 0:0:0.001UTC+8:0:0");
+        Assertions.assertEquals("2021-05-01 00:00:00.001UTC+08:00:00", s);
+
+    }
+
+    @Test
+    void testDate() {
+        new DateLiteral("220101");
+        new DateLiteral("22-01-01");
+        new DateLiteral("22-01-1");
+        new DateLiteral("22-1-1");
+
+        new DateLiteral("2022-01-01");
+        new DateLiteral("2022-01-1");
+        new DateLiteral("2022-1-1");
+        new DateLiteral("20220101");
+
+        Assertions.assertThrows(AnalysisException.class, () -> new 
DateLiteral("-01-01"));
+    }
+
+    @Test
+    void testZone() {
+        new DateLiteral("2022-01-01Z");
+        new DateLiteral("2022-01-01UTC");
+        new DateLiteral("2022-01-01GMT");
+        new DateLiteral("2022-01-01UTC+08");
+        new DateLiteral("2022-01-01UTC-06");
+        new DateLiteral("2022-01-01UTC+08:00");
+        new DateLiteral("2022-01-01UTC-06:00");
+        new DateLiteral("2022-01-01Europe/London");
+    }
+
+    @Test
+    void testOffset() {
+        new DateLiteral("2022-01-01+01:00:00");
+        new DateLiteral("2022-01-01+01:00");
+        new DateLiteral("2022-01-01+01");
+        new DateLiteral("2022-01-01+1:0:0");
+        new DateLiteral("2022-01-01+1:0");
+        new DateLiteral("2022-01-01+1");
+
+        new DateLiteral("2022-01-01-01:00:00");
+        new DateLiteral("2022-01-01-01:00");
+        new DateLiteral("2022-01-01-1:0:0");
+        new DateLiteral("2022-01-01-1:0");
+    }
+
+    @Test
+    void testIrregularDate() {
+        Consumer<DateLiteral> assertFunc = (DateLiteral dateLiteral) -> {
+            Assertions.assertEquals("2016-07-02", dateLiteral.toString());
+        };
+        DateLiteral dateLiteral;
+
+        dateLiteral = new DateLiteral("2016-07-02");
+        assertFunc.accept(dateLiteral);
+
+        dateLiteral = new DateLiteral("2016-7-02");
+        assertFunc.accept(dateLiteral);
+        dateLiteral = new DateLiteral("2016-07-2");
+        assertFunc.accept(dateLiteral);
+        dateLiteral = new DateLiteral("2016-7-2");
+        assertFunc.accept(dateLiteral);
+
+        dateLiteral = new DateLiteral("2016-07-02");
+        assertFunc.accept(dateLiteral);
+        dateLiteral = new DateLiteral("2016-07-2");
+        assertFunc.accept(dateLiteral);
+        dateLiteral = new DateLiteral("2016-7-02");
+        assertFunc.accept(dateLiteral);
+        dateLiteral = new DateLiteral("2016-7-2");
+        assertFunc.accept(dateLiteral);
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
new file mode 100644
index 00000000000..950a3c953b9
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/expressions/literal/DateTimeLiteralTest.java
@@ -0,0 +1,437 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions.literal;
+
+import org.apache.doris.nereids.types.DateTimeV2Type;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.function.Consumer;
+
+class DateTimeLiteralTest {
+    @Test
+    void reject() {
+        // Assertions.assertThrows(IllegalArgumentException.class, () -> {
+        //     new DateTimeV2Literal("2022-08-01T01:01:01-00:00");
+        // });
+    }
+
+    @Test
+    void testBasic() {
+        Consumer<DateTimeV2Literal> assertFunc = (datetime) -> {
+            Assertions.assertEquals(2022, datetime.year);
+            Assertions.assertEquals(8, datetime.month);
+            Assertions.assertEquals(1, datetime.day);
+            Assertions.assertEquals(1, datetime.hour);
+            Assertions.assertEquals(1, datetime.minute);
+            Assertions.assertEquals(1, datetime.second);
+        };
+
+        assertFunc.accept(new DateTimeV2Literal("20220801010101"));
+        assertFunc.accept(new DateTimeV2Literal("20220801T010101"));
+        assertFunc.accept(new DateTimeV2Literal("220801010101"));
+        assertFunc.accept(new DateTimeV2Literal("220801T010101"));
+    }
+
+    @Test
+    void testMicrosecond() {
+        DateTimeV2Literal literal;
+        literal = new DateTimeV2Literal("2016-07-02 00:00:00.123");
+        Assertions.assertEquals(123000, literal.microSecond);
+        literal = new DateTimeV2Literal("2016-07-02 00:00:00.123456");
+        Assertions.assertEquals(123456, literal.microSecond);
+        literal = new DateTimeV2Literal("2016-07-02 00:00:00.1");
+        Assertions.assertEquals(100000, literal.microSecond);
+        literal = new DateTimeV2Literal("2016-07-02 00:00:00.000001");
+        Assertions.assertEquals(1, literal.microSecond);
+        literal = new DateTimeV2Literal("2016-07-02 00:00:00.12345");
+        Assertions.assertEquals(123450, literal.microSecond);
+    }
+
+    @Test
+    void testWithoutZoneOrOffset() {
+        new DateTimeV2Literal("2022-08-01");
+
+        new DateTimeV2Literal("2022-08-01 01:01:01");
+        new DateTimeV2Literal("2022-08-01 01:01");
+        new DateTimeV2Literal("2022-08-01 01");
+
+        new DateTimeV2Literal("2022-08-01T01:01:01");
+        new DateTimeV2Literal("2022-08-01T01:01");
+        new DateTimeV2Literal("2022-08-01T01");
+
+        new DateTimeV2Literal("22-08-01T01:01:01");
+        new DateTimeV2Literal("22-08-01T01:01");
+        new DateTimeV2Literal("22-08-01T01");
+    }
+
+    @Test
+    void testDetermineScale() {
+        int scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.0");
+        Assertions.assertEquals(0, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.00000");
+        Assertions.assertEquals(0, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.000001");
+        Assertions.assertEquals(6, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.123456");
+        Assertions.assertEquals(6, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.0001");
+        Assertions.assertEquals(4, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.00010");
+        Assertions.assertEquals(4, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.12010");
+        Assertions.assertEquals(4, scale);
+        scale = DateTimeLiteral.determineScale("2022-08-01T01:01:01.02010");
+        Assertions.assertEquals(4, scale);
+    }
+
+    @Test
+    void testTwoDigitYear() {
+        new DateTimeV2Literal("22-08-01T01");
+        new DateTimeV2Literal("22-08-01 01");
+        new DateTimeV2Literal("22-08-01T01:01");
+        new DateTimeV2Literal("22-08-01 01:01");
+        new DateTimeV2Literal("22-08-01T01:01:01");
+        new DateTimeV2Literal("22-08-01 01:01:01");
+        new DateTimeV2Literal("22-08-01T01");
+        new DateTimeV2Literal("22-08-01 01");
+        new DateTimeV2Literal("22-08-01T01:01");
+        new DateTimeV2Literal("22-08-01 01:01");
+        new DateTimeV2Literal("22-08-01T01:01:01");
+        new DateTimeV2Literal("22-08-01 01:01:01");
+    }
+
+    @Test
+    void testZone() {
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC");
+        new DateTimeV2Literal("2022-08-01 01:01:01UT");
+        new DateTimeV2Literal("2022-08-01 01:01:01GMT");
+        new DateTimeV2Literal("2022-08-01 01:01:01Z");
+        new DateTimeV2Literal("2022-08-01 01:01:01Europe/London");
+        new DateTimeV2Literal("2022-08-01 01:01:01America/New_York");
+        new DateTimeV2Literal("2022-08-01 01:01:01Z");
+        new DateTimeV2Literal("2022-08-01 01:01:01Europe/Berlin");
+        new DateTimeV2Literal("2022-08-01 01:01:01Europe/London");
+    }
+
+    @Test
+    void testZoneOrOffsetRight() {
+        java.util.function.BiConsumer<DateTimeV2Literal, Long> assertHour = 
(dateTimeV2Literal, expectHour) -> {
+            Assertions.assertEquals(dateTimeV2Literal.hour, expectHour);
+        };
+        DateTimeV2Literal dateTimeV2Literal;
+        dateTimeV2Literal = new DateTimeV2Literal("2022-08-01 
00:00:00Europe/London"); // +01:00
+        assertHour.accept(dateTimeV2Literal, 7L);
+        dateTimeV2Literal = new DateTimeV2Literal("2022-08-01 
00:00:00America/New_York"); // -04:00
+        assertHour.accept(dateTimeV2Literal, 12L);
+        dateTimeV2Literal = new DateTimeV2Literal("2022-08-01 
00:00:00Asia/Shanghai");
+        assertHour.accept(dateTimeV2Literal, 0L);
+        dateTimeV2Literal = new DateTimeV2Literal("2022-08-01 00:00:00+01:00");
+        assertHour.accept(dateTimeV2Literal, 7L);
+        dateTimeV2Literal = new DateTimeV2Literal("2022-08-01 00:00:00-01:00");
+        assertHour.accept(dateTimeV2Literal, 9L);
+    }
+
+    @Test
+    void testTwoDigitalYearZone() {
+        new DateTimeV2Literal("22-08-01 01:01:01UTC");
+        new DateTimeV2Literal("22-08-01 01:01:01UT");
+        new DateTimeV2Literal("22-08-01 01:01:01GMT");
+        new DateTimeV2Literal("22-08-01 01:01:01Z");
+        new DateTimeV2Literal("22-08-01 01:01:01Europe/London");
+        new DateTimeV2Literal("22-08-01 01:01:01UTC");
+        new DateTimeV2Literal("22-08-01 01:01:01America/New_York");
+        new DateTimeV2Literal("22-08-01 01:01:01Z");
+        new DateTimeV2Literal("22-08-01 01:01:01Europe/Berlin");
+        new DateTimeV2Literal("22-08-01 01:01:01Europe/London");
+    }
+
+    @Test
+    void testZoneOffset() {
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+01:01:01");
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+1:1:1");
+
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+01:01");
+
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+01");
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+1");
+    }
+
+    @Test
+    void testTwoDigitalYearZoneOffset() {
+        new DateTimeV2Literal("22-08-01 01:01:01UTC+01:01:01");
+        new DateTimeV2Literal("22-08-01 01:01:01UTC+1:1:1");
+
+        new DateTimeV2Literal("22-08-01 01:01:01UTC+01:01");
+
+        new DateTimeV2Literal("22-08-01 01:01:01UTC+01");
+        new DateTimeV2Literal("22-08-01 01:01:01UTC+1");
+    }
+
+    @Test
+    void testOffset() {
+        new DateTimeV2Literal("2022-08-01 01:01:01+01:01:01");
+        new DateTimeV2Literal("2022-08-01 01:01:01+01:01");
+        new DateTimeV2Literal("2022-08-01 01:01:01+01");
+        new DateTimeV2Literal("2022-08-01 01:01:01+01:1:01");
+        new DateTimeV2Literal("2022-08-01 01:01:01+01:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01+01:01:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01+1:1:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01+1:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01+1");
+
+        new DateTimeV2Literal("2022-05-01 01:02:55+02:30");
+        new DateTimeV2Literal("2022-05-01 01:02:55.123-02:30");
+        new DateTimeV2Literal("2022-06-01T01:02:55+04:30");
+        new DateTimeV2Literal("2022-06-01 01:02:55.123-07:30");
+        new DateTimeV2Literal("2022-05-01 01:02:55+02:30");
+
+        new DateTimeV2Literal("2022-05-01 01:02:55.123-02:30");
+        new DateTimeV2Literal("2022-06-01T01:02:55+04:30");
+        new DateTimeV2Literal("2022-06-01 01:02:55.123-07:30");
+        // new DateTimeV2Literal("20220701010255+07:00");
+        // new DateTimeV2Literal("20220701010255-05:00");
+    }
+
+    @Test
+    void testDateTime() {
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+1:1:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+1:1");
+        new DateTimeV2Literal("2022-08-01 01:01:01UTC+1");
+
+        new DateTimeV2Literal("0001-01-01 00:01:01");
+        new DateTimeV2Literal("0001-01-01 00:01:01.001");
+        new DateTimeV2Literal("0001-01-01 00:01:01.00305");
+
+        new DateTimeV2Literal("2022-01-01 01:02:55");
+        new DateTimeV2Literal("2022-01-01 01:02:55.123");
+        new DateTimeV2Literal("2022-02-01 01:02:55Z");
+        new DateTimeV2Literal("2022-02-01 01:02:55.123Z");
+        new DateTimeV2Literal("2022-03-01 01:02:55UTC+8");
+        new DateTimeV2Literal("2022-03-01 01:02:55.123UTC");
+        new DateTimeV2Literal("2022-04-01 01:02:55UTC-6");
+        new DateTimeV2Literal("2022-04-01T01:02:55UTC-6");
+        new DateTimeV2Literal("2022-04-01T01:02:55.123UTC+6");
+
+        new DateTimeV2Literal("2022-01-01 01:02:55");
+        new DateTimeV2Literal("2022-01-01 01:02:55.123");
+        new DateTimeV2Literal("2022-02-01 01:02:55Z");
+        new DateTimeV2Literal("2022-02-01 01:02:55.123Z");
+        new DateTimeV2Literal("2022-03-01 01:02:55UTC+8");
+        new DateTimeV2Literal("2022-03-01 01:02:55.123UTC");
+        new DateTimeV2Literal("2022-04-01T01:02:55UTC-6");
+        new DateTimeV2Literal("2022-04-01T01:02:55.123UTC+6");
+
+        new DateTimeV2Literal("0001-01-01");
+        // new DateTimeV2Literal("20220801GMT+5");
+        // new DateTimeV2Literal("20220801GMT-3");
+    }
+
+    @Test
+    void testIrregularDateTime() {
+        new DateLiteral("2016-07-02 01:01:00");
+
+        new DateLiteral("2016-7-02 01:01:00");
+        new DateLiteral("2016-07-2 01:01:00");
+        new DateLiteral("2016-7-2 01:01:00");
+
+        new DateLiteral("2016-07-02 1:01:00");
+        new DateLiteral("2016-07-02 01:1:00");
+        new DateLiteral("2016-07-02 01:01:0");
+        new DateLiteral("2016-07-02 1:1:00");
+        new DateLiteral("2016-07-02 1:01:0");
+        new DateLiteral("2016-07-02 10:1:0");
+        new DateLiteral("2016-07-02 1:1:0");
+
+        new DateLiteral("2016-7-2 1:1:0");
+        new DateLiteral("2016-7-02 1:01:0");
+        new DateLiteral("2016-07-2 1:1:0");
+        new DateLiteral("2016-7-02 01:01:0");
+        new DateLiteral("2016-7-2 01:1:0");
+    }
+
+    @Test
+    void testIrregularDateTimeHour() {
+        new DateTimeV2Literal("2016-07-02 01");
+        new DateTimeV2Literal("2016-07-02 1");
+
+        new DateTimeV2Literal("2016-7-02 1");
+        new DateTimeV2Literal("2016-7-02 01");
+
+        new DateTimeV2Literal("2016-07-2 1");
+        new DateTimeV2Literal("2016-07-2 01");
+
+        new DateTimeV2Literal("2016-7-2 1");
+        new DateTimeV2Literal("2016-7-2 01");
+    }
+
+    @Test
+    void testIrregularDateTimeHourMinute() {
+        new DateTimeV2Literal("2016-07-02 01:01");
+        new DateTimeV2Literal("2016-07-02 1:01");
+        new DateTimeV2Literal("2016-07-02 01:1");
+        new DateTimeV2Literal("2016-07-02 1:1");
+
+        new DateTimeV2Literal("2016-7-02 01:01");
+        new DateTimeV2Literal("2016-7-02 1:01");
+        new DateTimeV2Literal("2016-7-02 01:1");
+        new DateTimeV2Literal("2016-7-02 1:1");
+
+        new DateTimeV2Literal("2016-07-2 01:01");
+        new DateTimeV2Literal("2016-07-2 1:01");
+        new DateTimeV2Literal("2016-07-2 01:1");
+        new DateTimeV2Literal("2016-07-2 1:1");
+
+        new DateTimeV2Literal("2016-7-2 01:01");
+        new DateTimeV2Literal("2016-7-2 1:01");
+        new DateTimeV2Literal("2016-7-2 01:1");
+        new DateTimeV2Literal("2016-7-2 1:1");
+    }
+
+    @Test
+    void testIrregularDateTimeHourMinuteSecond() {
+        new DateTimeV2Literal("2016-07-02 01:01:01");
+        new DateTimeV2Literal("2016-07-02 1:01:01");
+        new DateTimeV2Literal("2016-07-02 01:1:01");
+        new DateTimeV2Literal("2016-07-02 1:1:01");
+        new DateTimeV2Literal("2016-07-02 01:01:1");
+        new DateTimeV2Literal("2016-07-02 1:01:1");
+        new DateTimeV2Literal("2016-07-02 01:1:1");
+        new DateTimeV2Literal("2016-07-02 1:1:1");
+
+        new DateTimeV2Literal("2016-7-02 01:01:01");
+        new DateTimeV2Literal("2016-7-02 1:01:01");
+        new DateTimeV2Literal("2016-7-02 01:1:01");
+        new DateTimeV2Literal("2016-7-02 1:1:01");
+        new DateTimeV2Literal("2016-7-02 01:01:1");
+        new DateTimeV2Literal("2016-7-02 1:01:1");
+        new DateTimeV2Literal("2016-7-02 01:1:1");
+        new DateTimeV2Literal("2016-7-02 1:1:1");
+
+        new DateTimeV2Literal("2016-07-2 01:01:01");
+        new DateTimeV2Literal("2016-07-2 1:01:01");
+        new DateTimeV2Literal("2016-07-2 01:1:01");
+        new DateTimeV2Literal("2016-07-2 1:1:01");
+        new DateTimeV2Literal("2016-07-2 01:01:1");
+        new DateTimeV2Literal("2016-07-2 1:01:1");
+        new DateTimeV2Literal("2016-07-2 01:1:1");
+        new DateTimeV2Literal("2016-07-2 1:1:1");
+
+        new DateTimeV2Literal("2016-7-2 01:01:01");
+        new DateTimeV2Literal("2016-7-2 1:01:01");
+        new DateTimeV2Literal("2016-7-2 01:1:01");
+        new DateTimeV2Literal("2016-7-2 1:1:01");
+        new DateTimeV2Literal("2016-7-2 01:01:1");
+        new DateTimeV2Literal("2016-7-2 1:01:1");
+        new DateTimeV2Literal("2016-7-2 01:1:1");
+        new DateTimeV2Literal("2016-7-2 1:1:1");
+    }
+
+    @Test
+    void testIrregularDateTimeHourMinuteSecondMicrosecond() {
+        new DateTimeV2Literal("2016-07-02 01:01:01.1");
+        new DateTimeV2Literal("2016-07-02 1:01:01.1");
+        new DateTimeV2Literal("2016-07-02 01:1:01.1");
+        new DateTimeV2Literal("2016-07-02 1:1:01.1");
+        new DateTimeV2Literal("2016-07-02 01:01:1.1");
+        new DateTimeV2Literal("2016-07-02 1:01:1.1");
+        new DateTimeV2Literal("2016-07-02 01:1:1.1");
+        new DateTimeV2Literal("2016-07-02 1:1:1.1");
+
+        new DateTimeV2Literal("2016-7-02 01:01:01.1");
+        new DateTimeV2Literal("2016-7-02 1:01:01.1");
+        new DateTimeV2Literal("2016-7-02 01:1:01.1");
+        new DateTimeV2Literal("2016-7-02 1:1:01.1");
+        new DateTimeV2Literal("2016-7-02 01:01:1.1");
+        new DateTimeV2Literal("2016-7-02 1:01:1.1");
+        new DateTimeV2Literal("2016-7-02 01:1:1.1");
+        new DateTimeV2Literal("2016-7-02 1:1:1.1");
+
+        new DateTimeV2Literal("2016-07-2 01:01:01.1");
+        new DateTimeV2Literal("2016-07-2 1:01:01.1");
+        new DateTimeV2Literal("2016-07-2 01:1:01.1");
+        new DateTimeV2Literal("2016-07-2 1:1:01.1");
+        new DateTimeV2Literal("2016-07-2 01:01:1.1");
+        new DateTimeV2Literal("2016-07-2 1:01:1.1");
+        new DateTimeV2Literal("2016-07-2 01:1:1.1");
+        new DateTimeV2Literal("2016-07-2 1:1:1.1");
+
+        new DateTimeV2Literal("2016-7-2 01:01:01.1");
+        new DateTimeV2Literal("2016-7-2 1:01:01.1");
+        new DateTimeV2Literal("2016-7-2 01:1:01.1");
+        new DateTimeV2Literal("2016-7-2 1:1:01.1");
+        new DateTimeV2Literal("2016-7-2 01:01:1.1");
+        new DateTimeV2Literal("2016-7-2 1:01:1.1");
+        new DateTimeV2Literal("2016-7-2 01:1:1.1");
+        new DateTimeV2Literal("2016-7-2 1:1:1.1");
+
+        // Testing with microsecond of length 2
+        new DateTimeV2Literal("2016-07-02 01:01:01.12");
+        new DateTimeV2Literal("2016-7-02 01:01:01.12");
+
+        // Testing with microsecond of length 3
+        new DateTimeV2Literal("2016-07-02 01:01:01.123");
+        new DateTimeV2Literal("2016-7-02 01:01:01.123");
+
+        // Testing with microsecond of length 4
+        new DateTimeV2Literal("2016-07-02 01:01:01.1234");
+        new DateTimeV2Literal("2016-7-02 01:01:01.1234");
+
+        // Testing with microsecond of length 5
+        new DateTimeV2Literal("2016-07-02 01:01:01.12345");
+        new DateTimeV2Literal("2016-7-02 01:01:01.12345");
+
+        // Testing with microsecond of length 6
+        new DateTimeV2Literal("2016-07-02 01:01:01.123456");
+        new DateTimeV2Literal("2016-7-02 01:01:01.123456");
+    }
+
+    @Test
+    void testDateTimeV2Scale() {
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02 
00:00:00.123"),
+                new DateTimeV2Literal("2016-07-02 00:00:00.123"));
+
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(3), "2016-07-02 
00:00:00.123456"),
+                new DateTimeV2Literal("2016-07-02 00:00:00.123"));
+
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(4), "2016-07-02 
00:00:00.12345"),
+                new DateTimeV2Literal("2016-07-02 00:00:00.12345"));
+
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02 
00:00:00.12345"),
+                new DateTimeV2Literal("2016-07-02 00:00:00.0"));
+
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(0), "2016-07-02 
00:00:00.5123"),
+                new DateTimeV2Literal("2016-07-02 00:00:01.0"));
+
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(5), "2016-07-02 
00:00:00.999999"),
+                new DateTimeV2Literal("2016-07-02 00:00:01.0"));
+
+        // test overflow
+        Assertions.assertEquals(
+                new DateTimeV2Literal(DateTimeV2Type.of(5), "2016-12-31 
23:59:59.999999"),
+                new DateTimeV2Literal("2017-01-01 00:00:00.0"));
+    }
+}
+
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/types/AbstractDataTypeTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/types/AbstractDataTypeTest.java
index 776b80ec47c..3438f168a52 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/types/AbstractDataTypeTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/types/AbstractDataTypeTest.java
@@ -352,8 +352,8 @@ public class AbstractDataTypeTest {
         int scale = Math.min(precision, Math.abs(new Random().nextInt() % 
DecimalV2Type.MAX_SCALE));
         Assertions.assertFalse(dataType.acceptsType(new 
DecimalV2Type(precision, scale)));
         Assertions.assertTrue(dataType.acceptsType(new CharType(new 
Random().nextInt())));
-        Assertions.assertFalse(dataType.acceptsType(new VarcharType(new 
Random().nextInt())));
-        Assertions.assertFalse(dataType.acceptsType(StringType.INSTANCE));
+        Assertions.assertTrue(dataType.acceptsType(new VarcharType(new 
Random().nextInt())));
+        Assertions.assertTrue(dataType.acceptsType(StringType.INSTANCE));
         Assertions.assertFalse(dataType.acceptsType(DateType.INSTANCE));
         Assertions.assertFalse(dataType.acceptsType(DateTimeType.INSTANCE));
     }
@@ -373,7 +373,7 @@ public class AbstractDataTypeTest {
         int precision = Math.abs(new Random().nextInt() % 
(DecimalV2Type.MAX_PRECISION - 1)) + 1;
         int scale = Math.min(precision, Math.abs(new Random().nextInt() % 
DecimalV2Type.MAX_SCALE));
         Assertions.assertFalse(dataType.acceptsType(new 
DecimalV2Type(precision, scale)));
-        Assertions.assertFalse(dataType.acceptsType(new CharType(new 
Random().nextInt())));
+        Assertions.assertTrue(dataType.acceptsType(new CharType(new 
Random().nextInt())));
         Assertions.assertTrue(dataType.acceptsType(new VarcharType(new 
Random().nextInt())));
         Assertions.assertTrue(dataType.acceptsType(StringType.INSTANCE));
         Assertions.assertFalse(dataType.acceptsType(DateType.INSTANCE));
@@ -395,7 +395,7 @@ public class AbstractDataTypeTest {
         int precision = Math.abs(new Random().nextInt() % 
(DecimalV2Type.MAX_PRECISION - 1)) + 1;
         int scale = Math.min(precision, Math.abs(new Random().nextInt() % 
DecimalV2Type.MAX_SCALE));
         Assertions.assertFalse(dataType.acceptsType(new 
DecimalV2Type(precision, scale)));
-        Assertions.assertFalse(dataType.acceptsType(new CharType(new 
Random().nextInt())));
+        Assertions.assertTrue(dataType.acceptsType(new CharType(new 
Random().nextInt())));
         Assertions.assertTrue(dataType.acceptsType(new VarcharType(new 
Random().nextInt())));
         Assertions.assertTrue(dataType.acceptsType(StringType.INSTANCE));
         Assertions.assertFalse(dataType.acceptsType(DateType.INSTANCE));
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
index c40f5c4a85f..853c8e11b41 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/DateTimeFormatterUtilsTest.java
@@ -24,8 +24,23 @@ import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
+import java.util.function.Consumer;
 
 class DateTimeFormatterUtilsTest {
+    @Test
+    void test() {
+        DateTimeFormatter formatter = DateTimeFormatterUtils.ZONE_FORMATTER;
+
+        formatter.parse("");
+
+        formatter.parse("UTC+01:00");
+        formatter.parse("UTC+01:00:00");
+
+        formatter.parse("GMT+01:00");
+        formatter.parse("Asia/Shanghai");
+        formatter.parse("Z");
+    }
+
     private void assertDatePart(TemporalAccessor dateTime) {
         Assertions.assertEquals(2020, dateTime.get(ChronoField.YEAR));
         Assertions.assertEquals(2, dateTime.get(ChronoField.MONTH_OF_YEAR));
@@ -34,49 +49,66 @@ class DateTimeFormatterUtilsTest {
 
     @Test
     void testBasicDateTimeFormatter() {
-        DateTimeFormatter formatter = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER;
+        DateTimeFormatter formatter = 
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T;
         TemporalAccessor dateTime = formatter.parse("20200219");
         assertDatePart(dateTime);
         dateTime = formatter.parse("20200219010101");
         assertDatePart(dateTime);
-        dateTime = formatter.parse("20200219T010101");
+        dateTime = formatter.parse("20200219010101.1");
         assertDatePart(dateTime);
-        // failed case
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("20200219 010101"));
-
-        // microsecond
         dateTime = formatter.parse("20200219010101.000001");
         assertDatePart(dateTime);
-        dateTime = formatter.parse("20200219T010101.000001");
-        assertDatePart(dateTime);
         dateTime = formatter.parse("20200219010101.1");
         assertDatePart(dateTime);
+
+        formatter = DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER;
+        dateTime = formatter.parse("20200219T010101");
+        assertDatePart(dateTime);
         dateTime = formatter.parse("20200219T010101.1");
         assertDatePart(dateTime);
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("20200219010101."));
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("20200219010101.0000001"));
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("20200219T010101."));
-        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("20200219T010101.0000001"));
+        dateTime = formatter.parse("20200219T010101.000001");
+        assertDatePart(dateTime);
+        dateTime = formatter.parse("20200219T010101.1");
+        assertDatePart(dateTime);
+
+        // failed case
+        DateTimeFormatter withT = 
DateTimeFormatterUtils.BASIC_DATE_TIME_FORMATTER;
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219 010101"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219010101."));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219010101.0000001"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219T010101."));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withT.parse("20200219T010101.0000001"));
+        DateTimeFormatter withoutT = 
DateTimeFormatterUtils.BASIC_FORMATTER_WITHOUT_T;
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219 010101"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219010101."));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219010101.0000001"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219T010101."));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
withoutT.parse("20200219T010101.0000001"));
+    }
+
+    @Test
+    void testDateTimeFormatter() {
+        DateTimeFormatter formatter = 
DateTimeFormatterUtils.DATE_TIME_FORMATTER;
+        TemporalAccessor dateTime = formatter.parse("2020-02-19 01:01:01");
+        assertDatePart(dateTime);
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("2020-02-19T01:01:01"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
formatter.parse("2020-02-1901:01:01"));
     }
 
     @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));
-            }
-        }
+    void testTimeFormatter() {
+        // use lambda function to assert time is correct.
+        Consumer<TemporalAccessor> assertTime = (dateTime) ->
+                Assertions.assertEquals(1, 
dateTime.get(ChronoField.HOUR_OF_DAY));
+
+        DateTimeFormatter timeFormatter = 
DateTimeFormatterUtils.TIME_FORMATTER;
+        TemporalAccessor dateTime = timeFormatter.parse("01:01:01.000001");
+        assertTime.accept(dateTime);
+        dateTime = timeFormatter.parse("01:01:01.1");
+        assertTime.accept(dateTime);
+        dateTime = timeFormatter.parse("01:01:01");
+        assertTime.accept(dateTime);
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
timeFormatter.parse("01:01"));
+        Assertions.assertThrows(DateTimeParseException.class, () -> 
timeFormatter.parse("01"));
     }
 }
diff --git a/regression-test/data/correctness/test_time_diff_microseconds.out 
b/regression-test/data/correctness/test_time_diff_microseconds.out
index ce4c6c10f51..dbeeb067f26 100644
--- a/regression-test/data/correctness/test_time_diff_microseconds.out
+++ b/regression-test/data/correctness/test_time_diff_microseconds.out
@@ -25,5 +25,5 @@
 48:00:00.114514
 
 -- !select8 --
-48:00:00.11400
+48:00:00.11500
 
diff --git 
a/regression-test/data/query_p0/sql_functions/array_functions/test_array_with_scale_type.out
 
b/regression-test/data/query_p0/sql_functions/array_functions/test_array_with_scale_type.out
index b887cdf11bc..c20f9977c3e 100644
--- 
a/regression-test/data/query_p0/sql_functions/array_functions/test_array_with_scale_type.out
+++ 
b/regression-test/data/query_p0/sql_functions/array_functions/test_array_with_scale_type.out
@@ -3,7 +3,7 @@
 2022-12-02T22:23:24.999999
 
 -- !select --
-2022-12-02T22:23:24.999
+2022-12-02T22:23:25
 
 -- !select --
 2022-12-01T22:23:24.999
@@ -13,7 +13,7 @@
 2022-12-02T22:23:24.999999
 
 -- !select --
-2022-12-02T22:23:24.999
+2022-12-02T22:23:25
 
 -- !select --
 2022-12-01T23:23:24.999
@@ -80,11 +80,11 @@
 [2022-12-02 22:23:24.999]
 
 -- !select --
-[2022-12-02 22:23:24.999, 2022-12-02 22:23:23.997]
-[2022-12-02 22:23:24.999, 2022-12-02 22:23:23.997]
+[2022-12-02 22:23:25.000, 2022-12-02 22:23:23.998]
+[2022-12-02 22:23:25.000, 2022-12-02 22:23:23.998]
 
 -- !select --
-[2022-12-02 22:23:24.999, 2022-12-02 22:23:23.997]
+[2022-12-02 22:23:25, 2022-12-02 22:23:23.998]
 
 -- !select --
 []
diff --git 
a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
 
b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
index 4fc3d0d1f1d..876b45e501a 100644
--- 
a/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
+++ 
b/regression-test/data/query_p0/sql_functions/cast_function/test_cast_with_scale_type.out
@@ -8,9 +8,9 @@
 2      2022-12-02T22:23:24.999 2022-12-02T22:23:25
 
 -- !select3 --
-2022-12-02T22:23:24.999        2022-12-02T22:23:23.999
-2022-12-02T22:23:24.999        2022-12-02T22:23:23.999
+2022-12-02T22:23:25    2022-12-02T22:23:24
+2022-12-02T22:23:25    2022-12-02T22:23:24
 
 -- !select4 --
-2022-12-02T22:23:24.999        2022-12-02T22:23:23.999
+2022-12-02T22:23:25    2022-12-02T22:23:24
 
diff --git 
a/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy 
b/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy
index 4b3cd3bdca1..9a0a2c5bf59 100644
--- a/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy
+++ b/regression-test/suites/nereids_syntax_p0/test_simplify_comparison.groovy
@@ -19,57 +19,6 @@ suite("test_simplify_comparison") {
     sql "set enable_nereids_planner=true"
     sql 'set enable_fallback_to_original_planner=false;'
     sql 'drop table if exists log_items_test'
-    sql """CREATE TABLE IF NOT EXISTS `log_items_test` (
-            a DATETIME NOT NULL,
-            b decimal(10,2)
-            ) ENGINE=OLAP
-            UNIQUE KEY (`a`)
-            DISTRIBUTED BY HASH(`a`) BUCKETS 120
-            PROPERTIES (
-            "replication_num" = "1",
-            "in_memory" = "false",
-            "compression" = "LZ4",
-            "storage_cooldown_time" = "9999-12-31 23:59:59",
-            "enable_unique_key_merge_on_write" = "true"
-            );"""
-    sql """insert into log_items_test values( "2023-06-06", 111.11 );"""
-
-    explain {
-        sql "verbose select * from log_items_test where a < '2023-06-15 
23:59:59.999' and b < 111.111;"
-        notContains "CAST"
-        contains "< 111.12"
-        contains "< '2023-06-16 00:00:00'"
-    }
-
-    explain {
-        sql "verbose select * from log_items_test where a <= '2023-06-15 
23:59:59.999' and b <= 111.111;"
-        notContains "CAST"
-        contains "<= 111.11"
-        contains "<= '2023-06-15 23:59:59'"
-    }
-
-    explain {
-        sql "verbose select * from log_items_test where a = '2023-06-15 
23:59:59.999' and b = 111.111;"
-        notContains "CAST"
-        notContains "111.12"
-        notContains "2023-06-16 00:00:00"
-        notContains "111.11"
-        notContains "2023-06-15 23:59:59"
-    }
-
-    explain {
-        sql "verbose select * from log_items_test where a > '2023-06-15 
23:59:59.999' and b > 111.111;"
-        notContains "CAST"
-        contains "> 111.11"
-        contains "> '2023-06-15 23:59:59'"
-    }
-
-    explain {
-        sql "verbose select * from log_items_test where a >= '2023-06-15 
23:59:59.999' and b >= 111.111;"
-        notContains "CAST"
-        contains ">= 111.12"
-        contains ">= '2023-06-16 00:00:00'"
-    }
 
     sql "select cast('1234' as decimalv3(18,4)) > 2000;"
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to