content: /*
   ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
   ~                                                                               ~
   ~ The MIT License (MIT)                                                         ~
   ~                                                                               ~
   ~ Copyright (c) 2015-2025 miaixz.org and other contributors.                    ~
   ~                                                                               ~
   ~ Permission is hereby granted, free of charge, to any person obtaining a copy  ~
   ~ of this software and associated documentation files (the "Software"), to deal ~
   ~ in the Software without restriction, including without limitation the rights  ~
   ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell     ~
   ~ copies of the Software, and to permit persons to whom the Software is         ~
   ~ furnished to do so, subject to the following conditions:                      ~
   ~                                                                               ~
   ~ The above copyright notice and this permission notice shall be included in    ~
   ~ all copies or substantial portions of the Software.                           ~
   ~                                                                               ~
   ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    ~
   ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      ~
   ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   ~
   ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        ~
   ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ~
   ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     ~
   ~ THE SOFTWARE.                                                                 ~
   ~                                                                               ~
   ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
  */
  package org.miaixz.bus.core.center.date;
  
  import java.time.*;
  import java.time.chrono.Era;
  import java.time.format.DateTimeFormatter;
  import java.time.format.DateTimeFormatterBuilder;
  import java.time.temporal.ChronoField;
  import java.time.temporal.ChronoUnit;
  import java.time.temporal.TemporalAccessor;
  import java.time.temporal.TemporalField;
  import java.util.Calendar;
  import java.util.Date;
  import java.util.TimeZone;
  import java.util.concurrent.TimeUnit;
  
  import org.miaixz.bus.core.xyz.ObjectKit;
  import org.miaixz.bus.core.xyz.ZoneKit;
  
  /**
   * 日期转换
   *
   * @author Kimi Liu
   * @since Java 17+
   */
  public class Converter extends Formatter {
  
      /**
       * {@link Calendar}类型时间转为{@link DateTime} 始终根据已有{@link Calendar} 产生新的{@link DateTime}对象
       *
       * @param calendar {@link Calendar}，如果传入{@code null}，返回{@code null}
       * @return 时间对象
       */
      public static DateTime date(final Calendar calendar) {
          if (calendar == null) {
              return null;
          }
          return new DateTime(calendar);
      }
  
      /**
       * {@link TemporalAccessor}类型时间转为{@link DateTime} 始终根据已有{@link TemporalAccessor} 产生新的{@link DateTime}对象
       *
       * @param temporalAccessor {@link TemporalAccessor},常用子类： {@link LocalDateTime}、
       *                         LocalDate，如果传入{@code null}，返回{@code null}
       * @return 时间对象
       */
      public static DateTime date(final TemporalAccessor temporalAccessor) {
          if (temporalAccessor == null) {
              return null;
          }
          return new DateTime(temporalAccessor);
      }
  
      /**
       * 安全获取时间的某个属性，属性不存在返回最小值，一般为0
       * 注意请谨慎使用此方法，某些{@link TemporalAccessor#isSupported(TemporalField)}为{@code false}的方法返回最小值
       *
       * @param temporalAccessor 需要获取的时间对象
       * @param field            需要获取的属性
       * @return 时间的值，如果无法获取则获取最小值，一般为0
       */
      public static int get(final TemporalAccessor temporalAccessor, final TemporalField field) {
          if (temporalAccessor.isSupported(field)) {
              return temporalAccessor.get(field);
          }
  
          return (int) field.range().getMinimum();
      }
  
      /**
       * {@link TemporalAccessor}转换为 时间戳（从1970-01-01T00:00:00Z开始的毫秒数） 如果为{@link Month}，调用{@link Month#getValue()}
       * 如果为{@link DayOfWeek}，调用{@link DayOfWeek#getValue()} 如果为{@link Era}，调用{@link Era#getValue()}
       *
       * @param temporalAccessor Date对象
       * @return {@link Instant}对象
       */
      public static long toEpochMilli(final TemporalAccessor temporalAccessor) {
          if (temporalAccessor instanceof Month) {
              return ((Month) temporalAccessor).getValue();
          } else if (temporalAccessor instanceof DayOfWeek) {
              return ((DayOfWeek) temporalAccessor).getValue();
          } else if (temporalAccessor instanceof Era) {
              return ((Era) temporalAccessor).getValue();
          }
          return toInstant(temporalAccessor).toEpochMilli();
      }
  
      /**
       * {@link TemporalAccessor}转换为 {@link Instant}对象
       *
       * @param temporalAccessor Date对象
       * @return {@link Instant}对象
       */
      public static Instant toInstant(final TemporalAccessor temporalAccessor) {
          if (null == temporalAccessor) {
              return null;
          }
  
          final Instant result;
          if (temporalAccessor instanceof Instant) {
              result = (Instant) temporalAccessor;
          } else if (temporalAccessor instanceof LocalDateTime) {
              result = ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()).toInstant();
          } else if (temporalAccessor instanceof ZonedDateTime) {
              result = ((ZonedDateTime) temporalAccessor).toInstant();
          } else if (temporalAccessor instanceof OffsetDateTime) {
              result = ((OffsetDateTime) temporalAccessor).toInstant();
          } else if (temporalAccessor instanceof LocalDate) {
              result = ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault()).toInstant();
          } else if (temporalAccessor instanceof LocalTime) {
              // 指定本地时间转换 为Instant，取当天日期
              result = ((LocalTime) temporalAccessor).atDate(LocalDate.now()).atZone(ZoneId.systemDefault()).toInstant();
          } else if (temporalAccessor instanceof OffsetTime) {
              // 指定本地时间转换 为Instant，取当天日期
              result = ((OffsetTime) temporalAccessor).atDate(LocalDate.now()).toInstant();
          } else {
              result = toInstant(of(temporalAccessor));
          }
  
          return result;
      }
  
      /**
       * 将 {@link TimeUnit} 转换为 {@link ChronoUnit}.
       *
       * @param unit 被转换的{@link TimeUnit}单位，如果为{@code null}返回{@code null}
       * @return {@link ChronoUnit}
       */
      public static ChronoUnit toChronoUnit(final TimeUnit unit) throws IllegalArgumentException {
          if (null == unit) {
              return null;
          }
          switch (unit) {
              case NANOSECONDS:
                  return ChronoUnit.NANOS;
  
              case MICROSECONDS:
                  return ChronoUnit.MICROS;
  
              case MILLISECONDS:
                  return ChronoUnit.MILLIS;
  
              case SECONDS:
                  return ChronoUnit.SECONDS;
  
              case MINUTES:
                  return ChronoUnit.MINUTES;
  
              case HOURS:
                  return ChronoUnit.HOURS;
  
              case DAYS:
                  return ChronoUnit.DAYS;
  
              default:
                  throw new IllegalArgumentException("Unknown TimeUnit constant");
          }
      }
  
      /**
       * 转换 {@link ChronoUnit} 到 {@link TimeUnit}.
       *
       * @param unit {@link ChronoUnit}，如果为{@code null}返回{@code null}
       * @return {@link TimeUnit}
       * @throws IllegalArgumentException 如果{@link TimeUnit}没有对应单位抛出
       */
      public static TimeUnit toTimeUnit(final ChronoUnit unit) throws IllegalArgumentException {
          if (null == unit) {
              return null;
          }
          switch (unit) {
              case NANOS:
                  return TimeUnit.NANOSECONDS;
  
              case MICROS:
                  return TimeUnit.MICROSECONDS;
  
              case MILLIS:
                  return TimeUnit.MILLISECONDS;
  
              case SECONDS:
                  return TimeUnit.SECONDS;
  
              case MINUTES:
                  return TimeUnit.MINUTES;
  
              case HOURS:
                  return TimeUnit.HOURS;
  
              case DAYS:
                  return TimeUnit.DAYS;
  
              default:
                  throw new IllegalArgumentException("ChronoUnit cannot be converted to TimeUnit: " + unit);
          }
      }
  
      /**
       * {@link Instant}转{@link LocalDateTime}，使用UTC时区 此方法自动将一个UTC时间转换为本地时间，如传入00:00，则结果为08:00
       *
       * @param instant {@link Instant}
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime ofUTC(final Instant instant) {
          return of(instant, ZoneKit.ZONE_ID_UTC);
      }
  
      /**
       * {@link Instant}转{@link LocalDateTime} instant是一个无时区的时间戳，在转换为本地时间时，需指定这个时间戳所在时区 如果所在时区与当前时区不同，会转换时间
       *
       * @param instant {@link Instant}
       * @param zoneId  时区，如果给定的时区与当前时区不同，会转换时间
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final Instant instant, final ZoneId zoneId) {
          if (null == instant) {
              return null;
          }
  
          return LocalDateTime.ofInstant(instant, ObjectKit.defaultIfNull(zoneId, ZoneId::systemDefault));
      }
  
      /**
       * {@link Instant}转{@link LocalDateTime} instant是一个无时区的时间戳，在转换为本地时间时，需指定这个时间戳所在时区 如果所在时区与当前时区不同，会转换时间
       *
       * @param instant  {@link Instant}
       * @param timeZone 时区，如果给定的时区与当前时区不同，会转换时间
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final Instant instant, final TimeZone timeZone) {
          if (null == instant) {
              return null;
          }
  
          return of(instant, ObjectKit.defaultIfNull(timeZone, TimeZone::getDefault).toZoneId());
      }
  
      /**
       * 毫秒转{@link LocalDateTime}，使用默认时区
       *
       * <p>
       * 注意：此方法使用默认时区，如果非UTC，会产生时间偏移
       * </p>
       *
       * @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final long epochMilli) {
          return of(Instant.ofEpochMilli(epochMilli));
      }
  
      /**
       * 毫秒转{@link LocalDateTime}，使用UTC时区
       *
       * @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime ofUTC(final long epochMilli) {
          return ofUTC(Instant.ofEpochMilli(epochMilli));
      }
  
      /**
       * {@link Date}转{@link LocalDateTime}，使用默认时区 如果为{@link DateTime}且提供了时区信息，则按照给定的时区转换为默认时区
       *
       * @param date Date对象
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final Date date) {
          if (null == date) {
              return null;
          }
  
          if (date instanceof DateTime) {
              return of(date.toInstant(), ((DateTime) date).getZoneId());
          }
          return of(date.toInstant());
      }
  
      /**
       * 毫秒转{@link LocalDateTime}，根据时区不同，结果会产生时间偏移
       *
       * @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
       * @param zoneId     时区
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final long epochMilli, final ZoneId zoneId) {
          return of(Instant.ofEpochMilli(epochMilli), zoneId);
      }
  
      /**
       * 毫秒转{@link LocalDateTime}，结果会产生时间偏移
       *
       * @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
       * @param timeZone   时区
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final long epochMilli, final TimeZone timeZone) {
          return of(Instant.ofEpochMilli(epochMilli), timeZone);
      }
  
      /**
       * {@link TemporalAccessor}转{@link LocalDateTime}，使用默认时区
       *
       * @param temporalAccessor {@link TemporalAccessor}
       * @return {@link LocalDateTime}
       */
      public static LocalDateTime of(final TemporalAccessor temporalAccessor) {
          if (null == temporalAccessor) {
              return null;
          }
  
          if (temporalAccessor instanceof LocalDate) {
              return ((LocalDate) temporalAccessor).atStartOfDay();
          } else if (temporalAccessor instanceof Instant) {
              return LocalDateTime.ofInstant((Instant) temporalAccessor, ZoneId.systemDefault());
          }
  
          try {
              return LocalDateTime.from(temporalAccessor);
          } catch (final Exception ignore) {
              // ignore
          }
  
          try {
              return ZonedDateTime.from(temporalAccessor).toLocalDateTime();
          } catch (final Exception ignore) {
              // ignore
          }
  
          try {
              return LocalDateTime.ofInstant(Instant.from(temporalAccessor), ZoneId.systemDefault());
          } catch (final Exception ignore) {
              // ignore
          }
  
          return LocalDateTime.of(
                  get(temporalAccessor, ChronoField.YEAR),
                  get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
                  get(temporalAccessor, ChronoField.DAY_OF_MONTH),
                  get(temporalAccessor, ChronoField.HOUR_OF_DAY),
                  get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),
                  get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),
                  get(temporalAccessor, ChronoField.NANO_OF_SECOND));
      }
  
      /**
       * {@link TemporalAccessor}转{@link LocalDate}，使用默认时区
       *
       * @param temporalAccessor {@link TemporalAccessor}
       * @return {@link LocalDate}
       */
      public static LocalDate ofDate(final TemporalAccessor temporalAccessor) {
          if (null == temporalAccessor) {
              return null;
          }
  
          try {
              return LocalDate.from(temporalAccessor);
          } catch (final Exception ignore) {
              // ignore
          }
  
          if (temporalAccessor instanceof LocalDateTime) {
              return ((LocalDateTime) temporalAccessor).toLocalDate();
          } else if (temporalAccessor instanceof Instant) {
              return of(temporalAccessor).toLocalDate();
          }
  
          return LocalDate.of(
                  get(temporalAccessor, ChronoField.YEAR),
                  get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
                  get(temporalAccessor, ChronoField.DAY_OF_MONTH));
      }
  
      /**
       * {@link TemporalAccessor}转{@link ZonedDateTime}
       *
       * @param temporalAccessor {@link TemporalAccessor}
       * @param zoneId           时区ID
       * @return {@link ZonedDateTime}
       */
      public static ZonedDateTime ofZoned(final TemporalAccessor temporalAccessor, ZoneId zoneId) {
          if (null == temporalAccessor) {
              return null;
          }
          if (null == zoneId) {
              zoneId = ZoneId.systemDefault();
          }
  
          if (temporalAccessor instanceof Instant) {
              return ZonedDateTime.ofInstant((Instant) temporalAccessor, zoneId);
          } else if (temporalAccessor instanceof LocalDateTime) {
              return ZonedDateTime.of((LocalDateTime) temporalAccessor, zoneId);
          } else if (temporalAccessor instanceof LocalDate) {
              return ZonedDateTime.of((LocalDate) temporalAccessor, LocalTime.MIN, zoneId);
          } else if (temporalAccessor instanceof LocalTime) {
              return ZonedDateTime.of(LocalDate.now(), (LocalTime) temporalAccessor, zoneId);
          }
  
          return ZonedDateTime.of(
                  get(temporalAccessor, ChronoField.YEAR),
                  get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
                  get(temporalAccessor, ChronoField.DAY_OF_MONTH),
                  get(temporalAccessor, ChronoField.HOUR_OF_DAY),
                  get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),
                  get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),
                  get(temporalAccessor, ChronoField.NANO_OF_SECOND),
                  zoneId);
      }
  
      /**
       * 通过日期时间字符串构建{@link DateTimeFormatter}
       *
       * @param pattern 格式，如yyyy-MM-dd
       * @return {@link DateTimeFormatter}
       */
      public static DateTimeFormatter ofPattern(final String pattern) {
          return new DateTimeFormatterBuilder().appendPattern(pattern).parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                  .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0).parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                  .parseDefaulting(ChronoField.MILLI_OF_SECOND, 0).toFormatter();
      }
  
  }
  