| /* |
| * 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.iotdb.db.utils; |
| |
| import org.apache.iotdb.commons.conf.CommonDescriptor; |
| import org.apache.iotdb.commons.utils.TestOnly; |
| import org.apache.iotdb.db.protocol.session.SessionManager; |
| |
| import org.apache.tsfile.utils.TimeDuration; |
| |
| import java.time.DateTimeException; |
| import java.time.Instant; |
| import java.time.LocalDateTime; |
| import java.time.ZoneId; |
| import java.time.ZoneOffset; |
| import java.time.ZonedDateTime; |
| import java.time.format.DateTimeFormatter; |
| import java.time.format.DateTimeFormatterBuilder; |
| import java.time.format.DateTimeParseException; |
| import java.time.format.SignStyle; |
| import java.time.temporal.ChronoField; |
| import java.util.Calendar; |
| import java.util.concurrent.TimeUnit; |
| |
| public class DateTimeUtils { |
| |
| private DateTimeUtils() { |
| // forbidding instantiation |
| } |
| |
| public static final DateTimeFormatter ISO_LOCAL_DATE_WIDTH_1_2; |
| |
| static { |
| ISO_LOCAL_DATE_WIDTH_1_2 = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.YEAR, 4, 19, SignStyle.NEVER) |
| .appendLiteral('-') |
| .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) |
| .appendLiteral('-') |
| .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03'. */ |
| public static final DateTimeFormatter ISO_LOCAL_DATE_WITH_SLASH; |
| |
| static { |
| ISO_LOCAL_DATE_WITH_SLASH = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.YEAR, 4, 19, SignStyle.NEVER) |
| .appendLiteral('/') |
| .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) |
| .appendLiteral('/') |
| .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03'. */ |
| public static final DateTimeFormatter ISO_LOCAL_DATE_WITH_DOT; |
| |
| static { |
| ISO_LOCAL_DATE_WITH_DOT = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.YEAR, 4, 19, SignStyle.NEVER) |
| .appendLiteral('.') |
| .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) |
| .appendLiteral('.') |
| .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) |
| .toFormatter(); |
| } |
| |
| /** such as '10:15:30' or '10:15:30.123'. */ |
| public static final DateTimeFormatter ISO_LOCAL_TIME_WITH_MS; |
| |
| static { |
| ISO_LOCAL_TIME_WITH_MS = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.HOUR_OF_DAY, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.MINUTE_OF_HOUR, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.SECOND_OF_MINUTE, 2) |
| .optionalStart() |
| .appendFraction(ChronoField.MILLI_OF_SECOND, 0, 3, true) |
| .toFormatter(); |
| } |
| |
| /** such as '10:15:30' or '10:15:30.123456'. */ |
| public static final DateTimeFormatter ISO_LOCAL_TIME_WITH_US; |
| |
| static { |
| ISO_LOCAL_TIME_WITH_US = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.HOUR_OF_DAY, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.MINUTE_OF_HOUR, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.SECOND_OF_MINUTE, 2) |
| .optionalStart() |
| .appendFraction(ChronoField.MICRO_OF_SECOND, 0, 6, true) |
| .toFormatter(); |
| } |
| |
| /** such as '10:15:30' or '10:15:30.123456789'. */ |
| public static final DateTimeFormatter ISO_LOCAL_TIME_WITH_NS; |
| |
| static { |
| ISO_LOCAL_TIME_WITH_NS = |
| new DateTimeFormatterBuilder() |
| .appendValue(ChronoField.HOUR_OF_DAY, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.MINUTE_OF_HOUR, 2) |
| .appendLiteral(':') |
| .appendValue(ChronoField.SECOND_OF_MINUTE, 2) |
| .optionalStart() |
| .appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true) |
| .optionalEnd() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_MS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_MS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WIDTH_1_2) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WIDTH_1_2) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WIDTH_1_2) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral('T') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SPACE; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SPACE = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(DateTimeFormatter.ISO_LOCAL_DATE) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SPACE_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SPACE_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(DateTimeFormatter.ISO_LOCAL_DATE) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SPACE_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SPACE_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(DateTimeFormatter.ISO_LOCAL_DATE) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_SLASH) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_MS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123456+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_US; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_US = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_US) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123456789+01:00'. */ |
| public static final DateTimeFormatter ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_NS; |
| |
| static { |
| ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_NS = |
| new DateTimeFormatterBuilder() |
| .parseCaseInsensitive() |
| .append(ISO_LOCAL_DATE_WITH_DOT) |
| .appendLiteral(' ') |
| .append(ISO_LOCAL_TIME_WITH_NS) |
| .appendOffsetId() |
| .toFormatter(); |
| } |
| |
| public static final DateTimeFormatter formatter = |
| new DateTimeFormatterBuilder() |
| /** |
| * The ISO date-time formatter that formats or parses a date-time with an offset, such as |
| * '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123+01:00'. |
| */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_MS) |
| |
| /** such as '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_US) |
| |
| /** such as '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_NS) |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH) |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH_US) |
| |
| /** such as '2011/12/03T10:15:30+01:00' or '2011/12/03T10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH_NS) |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT) |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT_US) |
| |
| /** such as '2011.12.03T10:15:30+01:00' or '2011.12.03T10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT_NS) |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SPACE) |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SPACE_US) |
| |
| /** such as '2011-12-03 10:15:30+01:00' or '2011-12-03 10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SPACE_NS) |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE) |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_US) |
| |
| /** such as '2011/12/03 10:15:30+01:00' or '2011/12/03 10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_SLASH_WITH_SPACE_NS) |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE) |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123456+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_US) |
| |
| /** such as '2011.12.03 10:15:30+01:00' or '2011.12.03 10:15:30.123456789+01:00'. */ |
| .appendOptional(ISO_OFFSET_DATE_TIME_WITH_DOT_WITH_SPACE_NS) |
| .toFormatter(); |
| |
| public static long convertTimestampOrDatetimeStrToLongWithDefaultZone(String timeStr) { |
| try { |
| return Long.parseLong(timeStr); |
| } catch (NumberFormatException e) { |
| return DateTimeUtils.convertDatetimeStrToLong(timeStr, ZoneId.systemDefault()); |
| } |
| } |
| |
| public static long convertDatetimeStrToLong(String str, ZoneId zoneId) { |
| return convertDatetimeStrToLong( |
| str, |
| toZoneOffset(zoneId), |
| 0, |
| CommonDescriptor.getInstance().getConfig().getTimestampPrecision()); |
| } |
| |
| public static long convertDatetimeStrToLong( |
| String str, ZoneId zoneId, String timestampPrecision) { |
| return convertDatetimeStrToLong(str, toZoneOffset(zoneId), 0, timestampPrecision); |
| } |
| |
| public static long getInstantWithPrecision(String str, String timestampPrecision) { |
| try { |
| ZonedDateTime zonedDateTime = ZonedDateTime.parse(str, formatter); |
| Instant instant = zonedDateTime.toInstant(); |
| if ("us".equals(timestampPrecision)) { |
| if (instant.getEpochSecond() < 0 && instant.getNano() > 0) { |
| // adjustment can reduce the loss of the division |
| long millis = Math.multiplyExact(instant.getEpochSecond() + 1, 1000_000L); |
| long adjustment = instant.getNano() / 1000 - 1L; |
| return Math.addExact(millis, adjustment); |
| } else { |
| long millis = Math.multiplyExact(instant.getEpochSecond(), 1000_000L); |
| return Math.addExact(millis, instant.getNano() / 1000); |
| } |
| } else if ("ns".equals(timestampPrecision)) { |
| long millis = Math.multiplyExact(instant.getEpochSecond(), 1000_000_000L); |
| return Math.addExact(millis, instant.getNano()); |
| } |
| return instant.toEpochMilli(); |
| } catch (DateTimeParseException e) { |
| throw new RuntimeException(e.getMessage()); |
| } |
| } |
| |
| /** convert date time string to millisecond, microsecond or nanosecond. */ |
| public static long convertDatetimeStrToLong( |
| String str, ZoneOffset offset, int depth, String timestampPrecision) { |
| if (depth >= 2) { |
| throw new DateTimeException( |
| String.format( |
| "Failed to convert %s to millisecond, zone offset is %s, " |
| + "please input like 2011-12-03T10:15:30 or 2011-12-03T10:15:30+01:00", |
| str, offset)); |
| } |
| if (str.contains("Z")) { |
| return convertDatetimeStrToLong( |
| str.substring(0, str.indexOf('Z')) + "+00:00", offset, depth, timestampPrecision); |
| } else if (str.length() == 10) { |
| return convertDatetimeStrToLong(str + "T00:00:00", offset, depth, timestampPrecision); |
| } else if (str.length() - str.lastIndexOf('+') != 6 |
| && str.length() - str.lastIndexOf('-') != 6) { |
| return convertDatetimeStrToLong(str + offset, offset, depth + 1, timestampPrecision); |
| } else if (str.contains("[") || str.contains("]")) { |
| throw new DateTimeException( |
| String.format( |
| "%s with [time-region] at end is not supported now, " |
| + "please input like 2011-12-03T10:15:30 or 2011-12-03T10:15:30+01:00", |
| str)); |
| } |
| return getInstantWithPrecision(str, timestampPrecision); |
| } |
| |
| /** |
| * Convert duration string to time value. CurrentTime is used to calculate the days of natural |
| * month. If it's set as -1, which means a context free situation, then '1mo' will be thought as |
| * 30 days. |
| * |
| * @param duration represent duration string like: 12d8m9ns, 1y1mo, etc. |
| * @return time in milliseconds, microseconds, or nanoseconds depending on the profile |
| */ |
| public static long convertDurationStrToLong(String duration) { |
| return convertDurationStrToLong(-1, duration, false); |
| } |
| |
| public static long convertDurationStrToLong(String duration, boolean convertYearToMonth) { |
| return convertDurationStrToLong(-1, duration, convertYearToMonth); |
| } |
| |
| public static long convertDurationStrToLong( |
| String duration, String timestampPrecision, boolean convertYearToMonth) { |
| return convertDurationStrToLong(-1, duration, timestampPrecision, convertYearToMonth); |
| } |
| |
| public static long convertDurationStrToLong( |
| long currentTime, String duration, boolean convertYearToMonth) { |
| return convertDurationStrToLong( |
| currentTime, |
| duration, |
| CommonDescriptor.getInstance().getConfig().getTimestampPrecision(), |
| convertYearToMonth); |
| } |
| |
| /** |
| * convert duration string to time value. |
| * |
| * @param duration represent duration string like: 12d8m9ns, 1y1mo, etc. |
| * @param convertYearToMonth if we need convert year to month. eg: 1y -> 12mo |
| * @return time in milliseconds, microseconds, or nanoseconds depending on the profile |
| */ |
| public static long convertDurationStrToLong( |
| long currentTime, String duration, String timestampPrecision, boolean convertYearToMonth) { |
| long total = 0; |
| long temp = 0; |
| for (int i = 0; i < duration.length(); i++) { |
| char ch = duration.charAt(i); |
| if (Character.isDigit(ch)) { |
| temp *= 10; |
| temp += (ch - '0'); |
| } else { |
| String unit = String.valueOf(duration.charAt(i)); |
| // This is to identify units with two letters. |
| if (i + 1 < duration.length() && !Character.isDigit(duration.charAt(i + 1))) { |
| i++; |
| unit += duration.charAt(i); |
| } |
| unit = unit.toLowerCase(); |
| if (convertYearToMonth && unit.equals("y")) { |
| temp *= 12; |
| unit = "mo"; |
| } |
| total += |
| DateTimeUtils.convertDurationStrToLong( |
| currentTime == -1 ? -1 : currentTime + total, temp, unit, timestampPrecision); |
| temp = 0; |
| } |
| } |
| return total; |
| } |
| |
| @TestOnly |
| public static long convertDurationStrToLongForTest( |
| long value, String unit, String timestampPrecision) { |
| return convertDurationStrToLong(-1, value, unit, timestampPrecision); |
| } |
| |
| /** convert duration string to millisecond, microsecond or nanosecond. */ |
| public static long convertDurationStrToLong( |
| long currentTime, long value, String unit, String timestampPrecision) { |
| DurationUnit durationUnit = DurationUnit.valueOf(unit); |
| long res = value; |
| switch (durationUnit) { |
| case y: |
| res *= 365 * 86_400_000L; |
| break; |
| case mo: |
| if (currentTime == -1) { |
| res *= 30 * 86_400_000L; |
| } else { |
| Calendar calendar = Calendar.getInstance(); |
| calendar.setTimeZone(SessionManager.getInstance().getSessionTimeZone()); |
| calendar.setTimeInMillis(currentTime); |
| calendar.add(Calendar.MONTH, (int) (value)); |
| res = calendar.getTimeInMillis() - currentTime; |
| } |
| break; |
| case w: |
| res *= 7 * 86_400_000L; |
| break; |
| case d: |
| res *= 86_400_000L; |
| break; |
| case h: |
| res *= 3_600_000L; |
| break; |
| case m: |
| res *= 60_000L; |
| break; |
| case s: |
| res *= 1_000L; |
| break; |
| default: |
| break; |
| } |
| |
| if ("us".equals(timestampPrecision)) { |
| if (unit.equals(DurationUnit.ns.toString())) { |
| return value / 1000; |
| } else if (unit.equals(DurationUnit.us.toString())) { |
| return value; |
| } else { |
| return res * 1000; |
| } |
| } else if ("ns".equals(timestampPrecision)) { |
| if (unit.equals(DurationUnit.ns.toString())) { |
| return value; |
| } else if (unit.equals(DurationUnit.us.toString())) { |
| return value * 1000; |
| } else { |
| return res * 1000_000; |
| } |
| } else { |
| if (unit.equals(DurationUnit.ns.toString())) { |
| return value / 1000_000; |
| } else if (unit.equals(DurationUnit.us.toString())) { |
| return value / 1000; |
| } else { |
| return res; |
| } |
| } |
| } |
| |
| public static TimeUnit timestampPrecisionStringToTimeUnit(String timestampPrecision) { |
| if ("us".equals(timestampPrecision)) { |
| return TimeUnit.MICROSECONDS; |
| } else if ("ns".equals(timestampPrecision)) { |
| return TimeUnit.NANOSECONDS; |
| } else { |
| return TimeUnit.MILLISECONDS; |
| } |
| } |
| |
| public static String convertLongToDate(long timestamp) { |
| return convertLongToDate( |
| timestamp, CommonDescriptor.getInstance().getConfig().getTimestampPrecision()); |
| } |
| |
| public static String convertLongToDate(long timestamp, String sourcePrecision) { |
| switch (sourcePrecision) { |
| case "ns": |
| timestamp /= 1000_000; |
| break; |
| case "us": |
| timestamp /= 1000; |
| break; |
| } |
| return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault()) |
| .toString(); |
| } |
| |
| public static ZoneOffset toZoneOffset(ZoneId zoneId) { |
| return zoneId.getRules().getOffset(Instant.now()); |
| } |
| |
| public static ZonedDateTime convertMillsecondToZonedDateTime(long millisecond) { |
| return ZonedDateTime.ofInstant(Instant.ofEpochMilli(millisecond), ZoneId.systemDefault()); |
| } |
| |
| public enum DurationUnit { |
| y, |
| mo, |
| w, |
| d, |
| h, |
| m, |
| s, |
| ms, |
| us, |
| ns |
| } |
| |
| public static TimeUnit toTimeUnit(String t) { |
| switch (t) { |
| case "h": |
| return TimeUnit.HOURS; |
| case "m": |
| return TimeUnit.MINUTES; |
| case "s": |
| return TimeUnit.SECONDS; |
| case "ms": |
| return TimeUnit.MILLISECONDS; |
| case "u": |
| return TimeUnit.MICROSECONDS; |
| case "n": |
| return TimeUnit.NANOSECONDS; |
| default: |
| throw new IllegalArgumentException("time precision must be one of: h,m,s,ms,u,n"); |
| } |
| } |
| |
| public static final long MS_TO_MONTH = 30 * 86400_000L; |
| |
| public static long calcPositiveIntervalByMonth(long startTime, TimeDuration duration) { |
| return TimeDuration.calcPositiveIntervalByMonth( |
| startTime, |
| duration, |
| SessionManager.getInstance().getSessionTimeZone(), |
| TimestampPrecisionUtils.currPrecision); |
| } |
| |
| /** |
| * Storage the duration into two parts: month part and non-month part, the non-month part's |
| * precision is depended on current time precision. e.g. ms precision: '1y1mo1ms' -> monthDuration |
| * = 13, nonMonthDuration = 1, ns precision: '1y1mo1ms' -> monthDuration = 13, nonMonthDuration = |
| * 1000_000. |
| * |
| * @param duration the input duration string |
| * @return the TimeDuration instance contains month part and non-month part |
| */ |
| public static TimeDuration constructTimeDuration(String duration) { |
| duration = duration.toLowerCase(); |
| String currTimePrecision = CommonDescriptor.getInstance().getConfig().getTimestampPrecision(); |
| long temp = 0; |
| long monthDuration = 0; |
| long nonMonthDuration = 0; |
| for (int i = 0; i < duration.length(); i++) { |
| char ch = duration.charAt(i); |
| if (Character.isDigit(ch)) { |
| temp *= 10; |
| temp += (ch - '0'); |
| } else { |
| String unit = String.valueOf(duration.charAt(i)); |
| // This is to identify units with two letters. |
| if (i + 1 < duration.length() && !Character.isDigit(duration.charAt(i + 1))) { |
| i++; |
| unit += duration.charAt(i); |
| } |
| if (unit.equals("y")) { |
| monthDuration += temp * 12; |
| temp = 0; |
| continue; |
| } |
| if (unit.equals("mo")) { |
| monthDuration += temp; |
| temp = 0; |
| continue; |
| } |
| nonMonthDuration += |
| DateTimeUtils.convertDurationStrToLong(-1, temp, unit, currTimePrecision); |
| temp = 0; |
| } |
| } |
| return new TimeDuration((int) monthDuration, nonMonthDuration); |
| } |
| } |