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

net.snowflake.client.core.json.DateTimeConverter Maven / Gradle / Ivy

/*
 * Copyright (c) 2012-2024 Snowflake Computing Inc. All rights reserved.
 */

package net.snowflake.client.core.json;

import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.TimeZone;
import net.snowflake.client.core.ResultUtil;
import net.snowflake.client.core.SFBaseSession;
import net.snowflake.client.core.SFException;
import net.snowflake.client.core.arrow.ArrowResultUtil;
import net.snowflake.client.jdbc.ErrorCode;
import net.snowflake.client.jdbc.SnowflakeDateWithTimezone;
import net.snowflake.client.jdbc.SnowflakeTimeWithTimezone;
import net.snowflake.client.jdbc.SnowflakeTimestampWithTimezone;
import net.snowflake.client.jdbc.SnowflakeUtil;
import net.snowflake.common.core.SFTime;
import net.snowflake.common.core.SFTimestamp;

public class DateTimeConverter {
  private final TimeZone sessionTimeZone;
  private final long resultVersion;
  private final boolean honorClientTZForTimestampNTZ;
  private final boolean treatNTZAsUTC;
  private final boolean useSessionTimezone;
  private final boolean formatDateWithTimeZone;
  private final SFBaseSession session;

  public DateTimeConverter(
      TimeZone sessionTimeZone,
      SFBaseSession session,
      long resultVersion,
      boolean honorClientTZForTimestampNTZ,
      boolean treatNTZAsUTC,
      boolean useSessionTimezone,
      boolean formatDateWithTimeZone) {
    this.sessionTimeZone = sessionTimeZone;
    this.session = session;
    this.resultVersion = resultVersion;
    this.honorClientTZForTimestampNTZ = honorClientTZForTimestampNTZ;
    this.treatNTZAsUTC = treatNTZAsUTC;
    this.useSessionTimezone = useSessionTimezone;
    this.formatDateWithTimeZone = formatDateWithTimeZone;
  }

  public Timestamp getTimestamp(
      Object obj, int columnType, int columnSubType, TimeZone tz, int scale) throws SFException {
    if (obj == null) {
      return null;
    }
    if (Types.TIMESTAMP == columnType || Types.TIMESTAMP_WITH_TIMEZONE == columnType) {
      if (tz == null) {
        tz = TimeZone.getDefault();
      }
      SFTimestamp sfTS =
          ResultUtil.getSFTimestamp(
              obj.toString(), scale, columnSubType, resultVersion, sessionTimeZone, session);

      Timestamp res = sfTS.getTimestamp();
      if (res == null) {
        return null;
      }
      // If we want to display format with no session offset, we have to use session timezone for
      // ltz and tz types but UTC timezone for ntz type.
      if (useSessionTimezone) {
        if (columnSubType == SnowflakeUtil.EXTRA_TYPES_TIMESTAMP_LTZ
            || columnSubType == SnowflakeUtil.EXTRA_TYPES_TIMESTAMP_TZ) {
          TimeZone specificSessionTimezone = adjustTimezoneForTimestampTZ(obj, columnSubType);
          res = new SnowflakeTimestampWithTimezone(res, specificSessionTimezone);
        } else {
          res = new SnowflakeTimestampWithTimezone(res);
        }
      }
      // If timestamp type is NTZ and JDBC_TREAT_TIMESTAMP_NTZ_AS_UTC=true, keep
      // timezone in UTC to avoid daylight savings errors
      else if (treatNTZAsUTC && columnSubType == Types.TIMESTAMP) {
        res = new SnowflakeTimestampWithTimezone(res);
      }
      // If JDBC_TREAT_TIMESTAMP_NTZ_AS_UTC=false, default behavior is to honor
      // client timezone for NTZ time. Move NTZ timestamp offset to correspond to
      // client's timezone. JDBC_USE_SESSION_TIMEZONE overrides other params.
      if (columnSubType == Types.TIMESTAMP
          && ((!treatNTZAsUTC && honorClientTZForTimestampNTZ) || useSessionTimezone)) {
        res = sfTS.moveToTimeZone(tz).getTimestamp();
      }
      // Adjust time if date happens before year 1582 for difference between
      // Julian and Gregorian calendars
      return ResultUtil.adjustTimestamp(res);
    } else if (Types.DATE == columnType) {
      Date d = getDate(obj, columnType, columnSubType, tz, scale);
      if (d == null) {
        return null;
      }
      return new Timestamp(d.getTime());
    } else if (Types.TIME == columnType) {
      Time t = getTime(obj, columnType, columnSubType, tz, scale);
      if (t == null) {
        return null;
      }
      if (useSessionTimezone) {
        SFTime sfTime = ResultUtil.getSFTime(obj.toString(), scale, session);
        return new SnowflakeTimestampWithTimezone(
            sfTime.getFractionalSeconds(ResultUtil.DEFAULT_SCALE_OF_SFTIME_FRACTION_SECONDS),
            sfTime.getNanosecondsWithinSecond(),
            TimeZone.getTimeZone("UTC"));
      }
      return new Timestamp(t.getTime());
    } else {
      throw new SFException(
          ErrorCode.INVALID_VALUE_CONVERT, columnType, SnowflakeUtil.TIMESTAMP_STR, obj);
    }
  }

  public Time getTime(Object obj, int columnType, int columnSubType, TimeZone tz, int scale)
      throws SFException {
    if (obj == null) {
      return null;
    }
    if (Types.TIME == columnType) {
      SFTime sfTime = ResultUtil.getSFTime(obj.toString(), scale, session);
      Time ts =
          new Time(
              sfTime.getFractionalSeconds(ResultUtil.DEFAULT_SCALE_OF_SFTIME_FRACTION_SECONDS));
      if (useSessionTimezone) {
        ts =
            SnowflakeUtil.getTimeInSessionTimezone(
                SnowflakeUtil.getSecondsFromMillis(ts.getTime()),
                sfTime.getNanosecondsWithinSecond());
      }
      return ts;
    } else if (Types.TIMESTAMP == columnType || Types.TIMESTAMP_WITH_TIMEZONE == columnType) {
      Timestamp ts = getTimestamp(obj, columnType, columnSubType, tz, scale);
      if (ts == null) {
        return null;
      }
      if (useSessionTimezone) {
        ts = getTimestamp(obj, columnType, columnSubType, sessionTimeZone, scale);
        TimeZone sessionTimeZone = adjustTimezoneForTimestampTZ(obj, columnSubType);
        return new SnowflakeTimeWithTimezone(ts, sessionTimeZone, useSessionTimezone);
      }
      return new Time(ts.getTime());
    } else {
      throw new SFException(
          ErrorCode.INVALID_VALUE_CONVERT, columnType, SnowflakeUtil.TIME_STR, obj);
    }
  }

  public Date getDate(Object obj, int columnType, int columnSubType, TimeZone tz, int scale)
      throws SFException {
    if (obj == null) {
      return null;
    }

    if (Types.TIMESTAMP == columnType || Types.TIMESTAMP_WITH_TIMEZONE == columnType) {
      if (tz == null) {
        tz = TimeZone.getDefault();
      }
      if (columnSubType == SnowflakeUtil.EXTRA_TYPES_TIMESTAMP_TZ
          || columnSubType == SnowflakeUtil.EXTRA_TYPES_TIMESTAMP_LTZ) {
        TimeZone specificSessionTimeZone = adjustTimezoneForTimestampTZ(obj, columnSubType);
        return new SnowflakeDateWithTimezone(
            getTimestamp(obj, columnType, columnSubType, tz, scale).getTime(),
            specificSessionTimeZone,
            useSessionTimezone);
      }
      return new Date(getTimestamp(obj, columnType, columnSubType, tz, scale).getTime());

    } else if (Types.DATE == columnType) {
      if (tz == null || !formatDateWithTimeZone) {
        return ArrowResultUtil.getDate(Integer.parseInt((String) obj));
      }
      return ArrowResultUtil.getDate(Integer.parseInt((String) obj), tz, sessionTimeZone);
    }
    // for Types.TIME and all other type, throw user error
    else {
      throw new SFException(
          ErrorCode.INVALID_VALUE_CONVERT, columnType, SnowflakeUtil.DATE_STR, obj);
    }
  }

  private TimeZone adjustTimezoneForTimestampTZ(Object obj, int columnSubType) {
    // If the timestamp is of type timestamp_tz, use the associated offset timezone instead of the
    // session timezone for formatting
    if (obj != null
        && columnSubType == SnowflakeUtil.EXTRA_TYPES_TIMESTAMP_TZ
        && resultVersion > 0) {
      String timestampStr = obj.toString();
      int indexForSeparator = timestampStr.indexOf(' ');
      String timezoneIndexStr = timestampStr.substring(indexForSeparator + 1);
      return SFTimestamp.convertTimezoneIndexToTimeZone(Integer.parseInt(timezoneIndexStr));
    }
    // By default, return session timezone
    return sessionTimeZone;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy