All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.spark.util.DayTimeIntervalUtils Maven / Gradle / Ivy

The newest version!
/*
 * 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.spark.util;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.apache.spark.SparkException;

// Replicating code from SparkIntervalUtils so code in the 'common' space can work with
// year-month intervals.
public class DayTimeIntervalUtils {
  private static final byte DAY = 0;
  private static final byte HOUR = 1;
  private static final byte MINUTE = 2;
  private static final byte SECOND = 3;
  private static final long HOURS_PER_DAY = 24;
  private static final long MINUTES_PER_HOUR = 60;
  private static final long SECONDS_PER_MINUTE = 60;
  private static final long MILLIS_PER_SECOND = 1000;
  private static final long MICROS_PER_MILLIS = 1000;
  private static final long MICROS_PER_SECOND = MICROS_PER_MILLIS * MILLIS_PER_SECOND;
  private static final long MICROS_PER_MINUTE = SECONDS_PER_MINUTE * MICROS_PER_SECOND;
  private static final long MICROS_PER_HOUR = MINUTES_PER_HOUR * MICROS_PER_MINUTE;
  private static final long MICROS_PER_DAY = HOURS_PER_DAY * MICROS_PER_HOUR;
  private static final long MAX_HOUR = Long.MAX_VALUE / MICROS_PER_HOUR;
  private static final long MAX_MINUTE = Long.MAX_VALUE / MICROS_PER_MINUTE;
  private static final long MAX_SECOND = Long.MAX_VALUE / MICROS_PER_SECOND;

  public static String fieldToString(byte field) throws SparkException {
    if (field == DAY) {
      return "DAY";
    } else if (field == HOUR) {
      return "HOUR";
    } else if (field == MINUTE) {
      return "MINUTE";
    } else if (field == SECOND) {
      return "SECOND";
    } else {
      throw new SparkException("Invalid field in day-time interval: " + field +
              ". Supported fields are: DAY, HOUR, MINUTE, SECOND");
    }
  }

  // Used to convert microseconds representing a day-time interval with given start and end fields
  // to its ANSI SQL string representation. Throws a SparkException if startField or endField are
  // out of bounds.
  public static String toDayTimeIntervalANSIString(long micros, byte startField, byte endField)
          throws SparkException {
    String sign = "";
    long rest = micros;
    String from = fieldToString(startField).toUpperCase();
    String to = fieldToString(endField).toUpperCase();
    String prefix = "INTERVAL '";
    String postfix = startField == endField ? "' " + from : "' " + from + " TO " + to;
    if (micros < 0) {
      if (micros == Long.MIN_VALUE) {
        // Especial handling of minimum `Long` value because negate op overflows `Long`.
        // seconds = 106751991 * (24 * 60 * 60) + 4 * 60 * 60 + 54 = 9223372036854
        // microseconds = -9223372036854000000L-775808 == Long.MinValue
        String baseStr = "-106751991 04:00:54.775808000";
        long MAX_DAY = Long.MAX_VALUE / MICROS_PER_DAY;
        String firstStr = "-" + (startField == DAY ? Long.toString(MAX_DAY) :
                (startField == HOUR ? Long.toString(MAX_HOUR) :
                        (startField == MINUTE ? Long.toString(MAX_MINUTE) :
                                MAX_SECOND + ".775808")));
        if (startField == endField) {
          return prefix + firstStr + postfix;
        } else {
          int substrStart = startField == DAY ? 10 : (startField == HOUR ? 13 : 16);
          int substrEnd = endField == HOUR ? 13 : (endField == MINUTE ? 16 : 26);
          return prefix + firstStr + baseStr.substring(substrStart, substrEnd) + postfix;
        }
      } else {
        sign = "-";
        rest = -rest;
      }
    }
    StringBuilder formatBuilder = new StringBuilder(sign);
    List formatArgs = new ArrayList<>();
    if (startField == DAY) {
      formatBuilder.append(rest / MICROS_PER_DAY);
      rest %= MICROS_PER_DAY;
    } else if (startField == HOUR) {
      formatBuilder.append("%02d");
      formatArgs.add(rest / MICROS_PER_HOUR);
      rest %= MICROS_PER_HOUR;
    } else if (startField == MINUTE) {
      formatBuilder.append("%02d");
      formatArgs.add(rest / MICROS_PER_MINUTE);
      rest %= MICROS_PER_MINUTE;
    } else if (startField == SECOND) {
      String leadZero = rest < 10 * MICROS_PER_SECOND ? "0" : "";
      formatBuilder.append(leadZero).append(BigDecimal.valueOf(rest, 6)
              .stripTrailingZeros().toPlainString());
    }

    if (startField < HOUR && HOUR <= endField) {
      formatBuilder.append(" %02d");
      formatArgs.add(rest / MICROS_PER_HOUR);
      rest %= MICROS_PER_HOUR;
    }
    if (startField < MINUTE && MINUTE <= endField) {
      formatBuilder.append(":%02d");
      formatArgs.add(rest / MICROS_PER_MINUTE);
      rest %= MICROS_PER_MINUTE;
    }
    if (startField < SECOND && SECOND <= endField) {
      String leadZero = rest < 10 * MICROS_PER_SECOND ? "0" : "";
      formatBuilder.append(":").append(leadZero).append(BigDecimal.valueOf(rest, 6)
              .stripTrailingZeros().toPlainString());
    }
    return prefix + String.format(formatBuilder.toString(), formatArgs.toArray()) + postfix;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy