TimeRoundSeries.java

// 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.functions.executable;

import org.apache.doris.nereids.annotation.Developing;
import org.apache.doris.nereids.trees.expressions.ExecFunction;
import org.apache.doris.nereids.trees.expressions.Expression;
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.trees.expressions.literal.IntegerLiteral;
import org.apache.doris.nereids.trees.expressions.literal.TimestampTzLiteral;
import org.apache.doris.qe.ConnectContext;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

/**
 * executable functions:
 * year/month/day/hour/minute/second_ceil/floor
 */
@Developing
public class TimeRoundSeries {
    private static final LocalDateTime START_ORIGINAL_DAY = LocalDateTime.of(1, 1, 1, 0, 0, 0);

    enum DATE {
        YEAR,
        QUARTER,
        MONTH,
        DAY,
        HOUR,
        MINUTE,
        SECOND
    }

    // get it's from be/src/vec/functions/function_datetime_floor_ceil.cpp##time_round
    private static LocalDateTime getDateCeilOrFloor(DATE tag, LocalDateTime date, int period, LocalDateTime origin,
            boolean getCeil) {
        if (period < 1) {
            return null;
        }

        DateTimeV2Literal dt = (DateTimeV2Literal) DateTimeV2Literal.fromJavaDateType(date);
        DateTimeV2Literal start = (DateTimeV2Literal) DateTimeV2Literal.fromJavaDateType(origin);
        long diff = 0;
        long trivialPart = 0;
        switch (tag) {
            case YEAR: {
                diff = dt.getYear() - start.getYear();
                trivialPart = (dt.getValue() % 10000000000L) - (start.getValue() % 10000000000L);
                break;
            }
            case QUARTER: {
                diff = (dt.getYear() - start.getYear()) * 4 + (dt.getMonth() - start.getMonth()) / 3;
                // For QUARTER, use same logic as MONTH to preserve month+day+time info for proper comparison
                trivialPart = (((dt.getMonth() - 1) % 3) * 100000000L + (dt.getValue() % 100000000L))
                        - (((start.getMonth() - 1) % 3) * 100000000L + (start.getValue() % 100000000L));
                break;
            }
            case MONTH: {
                diff = (dt.getYear() - start.getYear()) * 12 + (dt.getMonth() - start.getMonth());
                trivialPart = (dt.getValue() % 100000000L) - (start.getValue() % 100000000L);
                break;
            }
            case DAY: {
                diff = dt.getTotalDays() - start.getTotalDays();
                long part2 = dt.getHour() * 3600 + dt.getMinute() * 60 + dt.getSecond();
                long part1 = start.getHour() * 3600 + start.getMinute() * 60 + start.getSecond();
                trivialPart = part2 - part1;
                break;
            }
            case HOUR: {
                diff = (dt.getTotalDays() - start.getTotalDays()) * 24 + (dt.getHour() - start.getHour());
                trivialPart = (dt.getMinute() * 60 + dt.getSecond())
                        - (start.getMinute() * 60 + start.getSecond());
                break;
            }
            case MINUTE: {
                diff = (dt.getTotalDays() - start.getTotalDays()) * 24 * 60 + (dt.getHour() - start.getHour()) * 60
                        + (dt.getMinute() - start.getMinute());
                trivialPart = dt.getSecond() - start.getSecond();
                break;
            }
            case SECOND: {
                diff = (dt.getTotalDays() - start.getTotalDays()) * 24 * 60 * 60
                        + (dt.getHour() - start.getHour()) * 60 * 60
                        + (dt.getMinute() - start.getMinute()) * 60
                        + (dt.getSecond() - start.getSecond());
                trivialPart = dt.getMicroSecond() - start.getMicroSecond();
                break;
            }
            default: {
                return null;
            }
        }
        trivialPart = (trivialPart == 0 ? dt.getMicroSecond() - start.getMicroSecond() : trivialPart);
        if (getCeil) {
            diff = diff + (trivialPart > 0 ? 1 : 0);
        } else {
            diff = diff - (trivialPart < 0 ? 1 : 0);
        }
        long deltaInsidePeriod = (diff % period + period) % period;
        long step = diff - deltaInsidePeriod;
        if (getCeil) {
            step = step + (deltaInsidePeriod == 0 ? 0 : period);
        }
        Expression result = null;
        switch (tag) {
            case YEAR:
                result = start.plusYears(step);
                break;
            case QUARTER:
                result = start.plusMonths(step * 3);
                break;
            case MONTH:
                result = start.plusMonths(step);
                break;
            case DAY:
                result = start.plusDays(step);
                break;
            case HOUR:
                result = start.plusHours(step);
                break;
            case MINUTE:
                result = start.plusMinutes(step);
                break;
            case SECOND:
                result = start.plusSeconds(step);
                break;
            default:
                break;
        }
        if (result != null && result instanceof DateTimeLiteral) {
            return ((DateTimeLiteral) result).toJavaDateType();
        } else {
            return null;
        }
    }

    /**
     * Helper method for TimestampTz ceil/floor operations with timezone conversion.
     * 1. Convert UTC to local time (using session timezone)
     * 2. Perform ceil/floor operation on local time
     * 3. Convert result back to UTC
     */
    private static LocalDateTime getDateCeilOrFloorForTimestampTz(DATE tag, LocalDateTime utcDate, int period,
            LocalDateTime utcOrigin, boolean getCeil) {
        // Get session timezone, default to UTC if not available
        String timeZone = "UTC";
        ConnectContext ctx = ConnectContext.get();
        if (ctx != null && ctx.getSessionVariable() != null) {
            timeZone = ctx.getSessionVariable().timeZone;
        }
        ZoneId zoneId = ZoneId.of(timeZone);

        // Get the ZonedDateTime for the date to determine its offset
        ZonedDateTime zonedDate = utcDate.atZone(ZoneId.of("UTC")).withZoneSameInstant(zoneId);

        // Use the date's offset to ensure consistent conversion for both date and origin
        // This prevents historical timezone offset inconsistencies (e.g., Asia/Shanghai
        // used +08:05:43 before 1900, then +08:00 after) from affecting the calculation
        ZoneId fixedOffsetZone = ZoneId.ofOffset("UTC", zonedDate.getOffset());

        // Convert UTC time to local time using the fixed offset from date
        LocalDateTime localDate = utcDate.atZone(ZoneId.of("UTC")).withZoneSameInstant(fixedOffsetZone)
                .toLocalDateTime();

        // Handle origin: START_ORIGINAL_DAY is already in local time, don't convert it
        // Only convert origin if it's a real UTC timestamp (from TimestampTzLiteral)
        LocalDateTime localOrigin;
        if (utcOrigin.equals(START_ORIGINAL_DAY)) {
            localOrigin = START_ORIGINAL_DAY;
        } else {
            localOrigin = utcOrigin.atZone(ZoneId.of("UTC")).withZoneSameInstant(fixedOffsetZone)
                    .toLocalDateTime();
        }

        // Perform ceil/floor operation on local time
        LocalDateTime localResult = getDateCeilOrFloor(tag, localDate, period, localOrigin, getCeil);

        if (localResult == null) {
            return null;
        }

        // Convert result back to UTC: treat localResult as being in the zoneId timezone
        // and convert to UTC
        LocalDateTime utcResult = localResult.atZone(zoneId).withZoneSameInstant(ZoneId.of("UTC"))
                .toLocalDateTime();
        return utcResult;
    }

    /**
     * datetime arithmetic function year-ceil
     */
    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "year_ceil")
    public static Expression yearCeil(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function quarter-ceil
     */
    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_ceil")
    public static Expression quarterCeil(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function month-ceil
     */
    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "month_ceil")
    public static Expression monthCeil(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function day-ceil
     */
    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "day_ceil")
    public static Expression dayCeil(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function hour-ceil
     */
    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_ceil")
    public static Expression hourCeil(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function minute-ceil
     */
    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_ceil")
    public static Expression minuteCeil(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function SECOND-ceil
     */
    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, true), date.getScale());
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), true), date.commonScale(origin));
    }

    @ExecFunction(name = "second_ceil")
    public static Expression secondCeil(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), true), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function year-floor
     */
    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "year_floor")
    public static Expression yearFloor(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.YEAR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function quarter-floor
     */
    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "quarter_floor")
    public static Expression quarterFloor(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.QUARTER, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function month-floor
     */
    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "month_floor")
    public static Expression monthFloor(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MONTH, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function day-floor
     */
    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "day_floor")
    public static Expression dayFloor(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.DAY, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function hour-floor
     */
    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(DateTimeV2Literal date, IntegerLiteral period, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "hour_floor")
    public static Expression hourFloor(TimestampTzLiteral date, IntegerLiteral period, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.HOUR, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function minute-floor
     */
    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "minute_floor")
    public static Expression minuteFloor(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.MINUTE, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    /**
     * datetime arithmetic function SECOND-floor
     */
    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateV2Literal date) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateV2Literal date, IntegerLiteral period) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateV2Literal date, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateV2Literal date, IntegerLiteral period, DateV2Literal origin) {
        return DateV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateTimeV2Literal date) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateTimeV2Literal date, IntegerLiteral period) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateTimeV2Literal date, DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(DateTimeV2Literal date, IntegerLiteral period,
            DateTimeV2Literal origin) {
        return DateTimeV2Literal.fromJavaDateType(getDateCeilOrFloor(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(TimestampTzLiteral date) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                1, START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(TimestampTzLiteral date, IntegerLiteral period) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), START_ORIGINAL_DAY, false), date.getScale());
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(TimestampTzLiteral date, TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                1, origin.toJavaDateType(), false), date.commonScale(origin));
    }

    @ExecFunction(name = "second_floor")
    public static Expression secondFloor(TimestampTzLiteral date, IntegerLiteral period,
            TimestampTzLiteral origin) {
        return TimestampTzLiteral.fromJavaDateType(getDateCeilOrFloorForTimestampTz(DATE.SECOND, date.toJavaDateType(),
                period.getValue(), origin.toJavaDateType(), false), date.commonScale(origin));
    }
}