package com.red.circle.other.infra.utils;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.red.circle.tool.core.date.ZonedId;

import java.sql.Timestamp;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.HashMap;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;

/**
 * @author pengliang on 2020/4/23 19:05
 */
@Slf4j
public final class ZonedDateTimeUtils {

    /**
     * <p>获取今日距离指定时间间隔</p>
     * <p>【正常】nowDateTime < nowEndDateTime(hour,minute,second) = 今天间隔时间<p/>
     * <p>
     * 【跨天】nowDateTime > nowEndDateTime(hour,minute,second) = nowEndDateTime + 1 时间的间隔
     * 如果结束时间小于开始时间那么就会计算，会在结束时间的基础上+1天
     * <p/>
     *
     * @param zoneId 时区
     * @param hour   小时
     * @return ignore
     */
    public static Duration todayInterval(ZoneId zoneId, int hour, int minute, int second) {
        ZonedDateTime startTime = ZonedDateTime.now(zoneId);
        ZonedDateTime endTime = ZonedDateTime.now(zoneId).withHour(hour).withMinute(minute)
                .withSecond(second).withNano(0);
        return startTime.isBefore(endTime)
                ? Duration.between(startTime, endTime)
                : Duration.between(startTime, endTime.plusDays(1));
    }


    /**
     * <p>获取今日距离指定时间间隔</p>
     *
     * @param zoneId 时区
     * @param hour   小时
     * @return ignore
     */
    public static Duration todayInterval(ZoneId zoneId, int hour) {
        return todayInterval(zoneId, hour, 0, 0);
    }

    /**
     * 获取一天的结束剩余间隔时间.
     *
     * @param zoneId 时区
     * @return ignore
     */
    public static Duration endOfTheDayInterval(ZoneId zoneId) {
        return ZonedDateTimeUtils.todayInterval(zoneId, 23, 59, 59);
    }

    /**
     * 获取一天的结束剩余间隔时间-转换毫秒.
     *
     * @param zoneId 时区
     * @return ignore
     */
    public static long endOfTheDayIntervalToMillis(ZoneId zoneId) {
        return endOfTheDayInterval(zoneId).toMillis();
    }


    /**
     * 获取指定时区日期
     *
     * @param zoneId 时区
     * @return 时间
     */
    public static LocalDate nowLocalDate(ZoneId zoneId) {
        return ZonedDateTime.now(zoneId).toLocalDate();
    }

    /**
     * 获取指定时区日期
     *
     * @param zoneId  时区
     * @param pattern 格式化
     * @return 时间
     */
    public static String nowLocalDate(ZoneId zoneId, DateFormatEnum pattern) {
        return nowLocalDate(zoneId).format(DateTimeFormatter.ofPattern(pattern.getPattern()));
    }

    /**
     * 获取指定时区日期时间
     *
     * @param zoneId 时区
     * @return 时间
     */
    public static LocalDateTime nowLocalDateTime(ZoneId zoneId) {
        return ZonedDateTime.now(zoneId).toLocalDateTime();
    }


    /**
     * 获取指定时区日期时间
     *
     * @param zoneId  时区
     * @param pattern 格式化
     * @return 时间
     */
    public static String now(ZoneId zoneId, DateFormatEnum pattern) {
        return nowLocalDateTime(zoneId).format(DateTimeFormatter.ofPattern(pattern.getPattern()));
    }

    /**
     * 当前utc时间.
     */
    public static ZonedDateTime nowUtc() {
        return ZonedDateTime.now(ZoneId.of("UTC"));
    }

    /**
     * 当前时间，沙特阿拉伯-Riyadh 时区.
     *
     * @return ignore
     */
    public static ZonedDateTime nowAsiaRiyadh() {
        return ZonedDateTime.now(ZonedId.ASIA_RIYADH.getZonedId());
    }

    /**
     * 当前时间，上海-Shanghai 时区.
     *
     * @return ignore
     */
    public static ZonedDateTime nowAsiaShanghai() {
        return ZonedDateTime.now(ZonedId.ASIA_SHANGHAI.getZonedId());
    }

    /**
     * 转换，沙特阿拉伯-Riyadh 时区.
     *
     * @return ignore
     */
    public static ZonedDateTime toAsiaRiyadh(LocalDateTime localDateTime) {
        return ZonedDateTime.of(localDateTime, ZonedId.ASIA_RIYADH.getZonedId());
    }

    /**
     * 转换-格式化，沙特阿拉伯-Riyadh 时区.
     *
     * @return ignore
     */
    public static String toAsiaRiyadhFormat(LocalDateTime localDateTime,
                                            DateFormatEnum pattern) {
        return toAsiaRiyadh(localDateTime).format(DateTimeFormatter.ofPattern(pattern.getPattern()));
    }

    /**
     * 获得沙特时间昨天.
     */
    public static Integer getAsiaRiyadhYesterday() {

        return Integer.parseInt(nowAsiaRiyadh().minusDays(1)
                .format(DateTimeFormatter.ofPattern(DateFormatEnum.yyyyMMdd.getPattern())));
    }

    /**
     * 获得沙特时间本周一.
     */
    public static Integer getAsiaRiyadhThisMonday() {

        return Integer.parseInt(nowAsiaRiyadh().with(DayOfWeek.MONDAY)
                .format(DateTimeFormatter.ofPattern(DateFormatEnum.yyyyMMdd.getPattern())));
    }

    /**
     * 获取本周一.
     */
    public static Integer getWeekMonday(ZonedDateTime zonedDateTime) {
        return Integer.parseInt(format(zonedDateTime.with(DayOfWeek.MONDAY), DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获取本周日.
     */
    public static Integer getWeekSunday(ZonedDateTime zonedDateTime) {
        return Integer.parseInt(
                format(zonedDateTime.with(DayOfWeek.SUNDAY), DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获取本周日 ，沙特阿拉伯-Riyadh 时区 .
     */
    public static ZonedDateTime nowAsiaRiyadhWeekSunday() {

        return nowAsiaRiyadh().with(DayOfWeek.SUNDAY)
                .withHour(23)
                .withMinute(59)
                .withSecond(59)
                .withNano(999999999);
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区,当前日期.
     *
     * @param pattern 格式化
     * @return 时间
     */
    public static String nowAsiaRiyadh(DateFormatEnum pattern) {
        return nowAsiaRiyadh().format(DateTimeFormatter.ofPattern(pattern.getPattern()));
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区 当前日期数值.
     *
     * @return 时间
     */
    public static Integer nowAsiaRiyadhToInt() {
        return Integer.valueOf(nowAsiaRiyadh(DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区 当前日期.
     *
     * @return 时间 yyyy.MM.dd
     */
    public static String nowAsiaRiyadhToDateStr() {
        return nowAsiaRiyadh(DateFormatEnum.yyyy_point_MM_point_dd);
    }

    /**
     * 获得沙特时间上一个月（年月数值）.
     */
    public static Integer getAsiaRiyadhLastMonth() {

        return Integer.parseInt(nowAsiaRiyadh().minusMonths(1)
                .format(DateTimeFormatter.ofPattern(DateFormatEnum.yyyy_MM.getPattern())));
    }

    /**
     * 获得沙特时间上一个月（年月数值）.
     */
    public static String getAsiaRiyadhLastMonthStr() {

        return nowAsiaRiyadh().minusMonths(1)
                .format(DateTimeFormatter.ofPattern(DateFormatEnum.MM_SLASH_YYYY.getPattern()));
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区 (当前年月数值).
     *
     * @return 时间
     */
    public static Integer nowAsiaRiyadhYearMonthToInt() {
        return Integer.valueOf(nowAsiaRiyadh(DateFormatEnum.yyyy_MM));
    }


    /**
     * 获取 沙特阿拉伯-Riyadh 时区 日期数值（每月1号）.
     *
     * @return 时间
     */
    public static Integer nowAsiaRiyadhFirstDayOfMonthToInt() {
        return Integer.valueOf(nowAsiaRiyadhFirstDayOfMonth().format(
                DateTimeFormatter.ofPattern(DateFormatEnum.yyyyMMdd.getPattern())));
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区(每月1号).
     *
     * @return 时间
     */
    public static ZonedDateTime nowAsiaRiyadhFirstDayOfMonth() {
        return nowAsiaRiyadh().with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 本月1号，沙特阿拉伯-Riyadh.
     */
    public static ZonedDateTime nowAsiaRiyadhFirstDayOfMonthStart() {
        return nowAsiaRiyadhFirstDayOfMonth()
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 本月1号，utc时间.
     */
    public static ZonedDateTime nowUtcFirstDayOfMonthStart() {
        return nowUtc().with(TemporalAdjusters.firstDayOfMonth())
                .withHour(0)
                .withMinute(0)
                .withSecond(0)
                .withNano(0);
    }

    /**
     * 获取 沙特阿拉伯-Riyadh 时区 日期数值（上月1号）.
     *
     * @return 时间
     */
    public static Integer nowAsiaRiyadhFirstDayOfLastMonthToInt() {
        return Integer.valueOf(nowAsiaRiyadh().minusMonths(1).with(
                TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ofPattern("yyyyMMdd")));
    }

    /**
     * 获取本周一 沙特阿拉伯-Riyadh 时区 .
     */
    public static ZonedDateTime nowAsiaRiyadhWeekMonday() {
        return nowAsiaRiyadh().with(DayOfWeek.MONDAY);
    }

    /**
     * 获取本周一 沙特阿拉伯-Riyadh 时区 .
     */
    public static Integer nowAsiaRiyadhWeekMondayToInt() {
        return Integer.parseInt(format(nowAsiaRiyadhWeekMonday(), DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获取下周一 ，沙特阿拉伯-Riyadh 时区 .
     */
    public static ZonedDateTime nowAsiaRiyadhNextWeekMonday() {
        return nowAsiaRiyadh().with(TemporalAdjusters.next(DayOfWeek.MONDAY));
    }

    /**
     * 获取下周一 ，沙特阿拉伯-Riyadh 时区 .
     */
    public static Integer nowAsiaRiyadhNextWeekMondayToInt() {
        return Integer.parseInt(format(nowAsiaRiyadhNextWeekMonday(), DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获得上周一,沙特阿拉伯-Riyadh 时区 .
     */
    public static Integer getAsiaRiyadhLastWeekMondayToInt() {
        return Integer.parseInt(format(getAsiaRiyadhLastWeekMonday(), DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获得上周一,沙特阿拉伯-Riyadh 时区 .
     */
    public static String getAsiaRiyadhLastWeekMondayToFormat(DateFormatEnum pattern) {
        return format(getAsiaRiyadhLastWeekMonday(), pattern);
    }

    /**
     * 获取上周一 沙特阿拉伯-Riyadh 时区 .
     *
     * @return ignore
     */
    public static ZonedDateTime getAsiaRiyadhLastWeekMonday() {
        ZonedDateTime now = nowAsiaRiyadh();
        return now.minusDays(7 + now.getDayOfWeek().getValue() - 1);
    }

    /**
     * 获取上周日 沙特阿拉伯-Riyadh 时区 .
     *
     * @return ignore
     */
    public static ZonedDateTime getAsiaRiyadhLastWeekSunday() {
        return nowAsiaRiyadh().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
    }

    /**
     * 获取上周日 沙特阿拉伯-Riyadh 时区 .
     *
     * @return ignore
     */
    public static String getAsiaRiyadhLastWeekSunday(DateFormatEnum pattern) {

        return format(nowAsiaRiyadh().with(TemporalAdjusters.previous(DayOfWeek.SUNDAY)),
                pattern);
    }

    /**
     * 获取当前月最后一天.
     */
    public static Integer getLastDayOfMonthToInt(ZonedDateTime zonedDateTime) {
        return Integer.parseInt(format(zonedDateTime.with(TemporalAdjusters.lastDayOfMonth()),
                DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获取当前月最后一天.
     */
    public static ZonedDateTime getLastDayOfMonth() {

        return nowAsiaRiyadh().with(TemporalAdjusters.lastDayOfMonth())
                .withHour(23)
                .withMinute(59)
                .withSecond(59)
                .withNano(999999999);
    }

    /**
     * 获取当前月第一天.
     */
    public static Integer getFirstDayOfMonthToInt(ZonedDateTime zonedDateTime) {
        return Integer.parseInt(format(zonedDateTime.with(TemporalAdjusters.firstDayOfMonth()),
                DateFormatEnum.yyyyMMdd));
    }

    /**
     * 获得沙特时间上一个月第一天.
     */
    public static String getAsiaRiyadhFirstDayOfMonthByLastMonth(DateFormatEnum pattern) {

        return format(nowAsiaRiyadh().minusMonths(1)
                .with(TemporalAdjusters.firstDayOfMonth()), pattern);
    }

    /**
     * 获得沙特时间上一个月最后一天.
     */
    public static String getAsiaRiyadhLastDayOfMonthByLastMonth(DateFormatEnum pattern) {

        return format(nowAsiaRiyadh().minusMonths(1)
                .with(TemporalAdjusters.lastDayOfMonth()), pattern);
    }

    /**
     * 格式化.
     */
    public static String format(ZonedDateTime time, DateFormatEnum format) {
        return time.format(DateTimeFormatter.ofPattern(format.getPattern()));
    }

    /**
     * localDateTime 转毫秒
     * @param localDateTime
     * @return
     */
    public static long toTimestampMillis(LocalDateTime localDateTime) {
      if (localDateTime == null) {
        throw new IllegalArgumentException("LocalDateTime cannot be null");
      }
      return localDateTime.atZone(ZonedId.ASIA_RIYADH.getZonedId()).toInstant().toEpochMilli();
    }

    /**
     * localDateTime 转时间戳
     * @param localDateTime
     * @return
     */
    public static Timestamp toTimestamp(LocalDateTime localDateTime) {
      if (localDateTime == null) {
        return null;
      }
      return Timestamp.from(localDateTime.atZone(ZonedId.ASIA_RIYADH.getZonedId()).toInstant());
    }

    public static Timestamp toTimestampDefault(LocalDateTime localDateTime) {
      if (localDateTime == null) {
        return null;
      }
      return Timestamp.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 生成周标识（ISO 8601标准，周一为一周的开始）.
     */
    public static String getWeekKey() {
        LocalDate now = LocalDate.now();
        int year = now.get(WeekFields.ISO.weekBasedYear());  // 使用ISO周年
        int weekOfYear = now.get(WeekFields.ISO.weekOfWeekBasedYear());  // ISO周数
        return String.format("%dW%02d", year, weekOfYear);
    }

    /**
     * 转换zoneId
     *
     * @param zoneId id
     * @return obj
     */
    public static ZoneId getZoneIdObj(String zoneId) {
        try {
            return ZoneId.of(zoneId);
        } catch (Exception ex) {
            log.warn("getClientZoneIdDefaultUtc-one:{}", ex.getMessage());
        }

        try {
            return ZoneId.of(zoneId, ZoneId.SHORT_IDS);
        } catch (Exception ex) {
            log.warn("getClientZoneIdDefaultUtc-two:{}", ex.getMessage());
        }
        return ZoneId.of("UTC");
    }


    private static final HashMap<String, String> timeZonesMap = new HashMap<>() {
        {
            put("PR", "America/Puerto_Rico");
            ;
            put("PS", "Asia/Hebron");
            put("PT", "Europe/Lisbon");
            put("PW", "Pacific/Palau");
            put("PY", "America/Asuncion");
            put("QA", "Asia/Qatar");
            put("AD", "Europe/Andorra");
            put("AE", "Asia/Dubai");
            put("AF", "Asia/Kabul");
            put("AG", "America/Antigua");
            put("AI", "America/Anguilla");
            put("AL", "Europe/Tirane");
            put("AM", "Asia/Yerevan");
            put("AO", "Africa/Luanda");
            put("AQ", "Antarctica/McMurdo");
            put("AR", "America/Argentina/San_Juan");
            put("AS", "Pacific/Pago_Pago");
            put("RE", "Indian/Reunion");
            put("AT", "Europe/Vienna");
            put("AU", "Australia/Brisbane");
            put("AW", "America/Aruba");
            put("AX", "Europe/Mariehamn");
            put("AZ", "Asia/Baku");
            put("RO", "Europe/Bucharest");
            put("BA", "Europe/Sarajevo");
            put("BB", "America/Barbados");
            put("RS", "Europe/Belgrade");
            put("BD", "Asia/Dhaka");
            put("BE", "Europe/Brussels");
            put("RU", "Asia/Magadan");
            put("BF", "Africa/Ouagadougou");
            put("BG", "Europe/Sofia");
            put("RW", "Africa/Kigali");
            put("BH", "Asia/Bahrain");
            put("BI", "Africa/Bujumbura");
            put("BJ", "Africa/Porto-Novo");
            put("BL", "America/St_Barthelemy");
            put("BM", "Atlantic/Bermuda");
            put("BN", "Asia/Brunei");
            put("BO", "America/La_Paz");
            put("SA", "Asia/Riyadh");
            put("SB", "Pacific/Guadalcanal");
            put("BQ", "America/Kralendijk");
            put("SC", "Indian/Mahe");
            put("BR", "America/Cuiaba");
            put("BS", "America/Nassau");
            put("SD", "Africa/Khartoum");
            put("SE", "Europe/Stockholm");
            put("BT", "Asia/Thimphu");
            put("SG", "Asia/Singapore");
            put("SH", "Atlantic/St_Helena");
            put("BW", "Africa/Gaborone");
            put("SI", "Europe/Ljubljana");
            put("BY", "Europe/Minsk");
            put("SJ", "Arctic/Longyearbyen");
            put("SK", "Europe/Bratislava");
            put("BZ", "America/Belize");
            put("SL", "Africa/Freetown");
            put("SM", "Europe/San_Marino");
            put("SN", "Africa/Dakar");
            put("SO", "Africa/Mogadishu");
            put("CA", "America/Inuvik");
            put("SR", "America/Paramaribo");
            put("CC", "Indian/Cocos");
            put("SS", "Africa/Juba");
            put("ST", "Africa/Sao_Tome");
            put("CD", "Africa/Lubumbashi");
            put("SV", "America/El_Salvador");
            put("CF", "Africa/Bangui");
            put("CG", "Africa/Brazzaville");
            put("CH", "Europe/Zurich");
            put("SX", "America/Lower_Princes");
            put("SY", "Asia/Damascus");
            put("CI", "Africa/Abidjan");
            put("SZ", "Africa/Mbabane");
            put("CK", "Pacific/Rarotonga");
            put("CL", "America/Santiago");
            put("CM", "Africa/Douala");
            put("CN", "Asia/Shanghai");
            put("CO", "America/Bogota");
            put("TC", "America/Grand_Turk");
            put("CR", "America/Costa_Rica");
            put("TD", "Africa/Ndjamena");
            put("TF", "Indian/Kerguelen");
            put("CU", "America/Havana");
            put("CV", "Atlantic/Cape_Verde");
            put("TG", "Africa/Lome");
            put("TH", "Asia/Bangkok");
            put("CW", "America/Curacao");
            put("CX", "Indian/Christmas");
            put("CY", "Asia/Nicosia");
            put("TJ", "Asia/Dushanbe");
            put("TK", "Pacific/Fakaofo");
            put("CZ", "Europe/Prague");
            put("TL", "Asia/Dili");
            put("TM", "Asia/Ashgabat");
            put("TN", "Africa/Tunis");
            put("TO", "Pacific/Tongatapu");
            put("TR", "Europe/Istanbul");
            put("TT", "America/Port_of_Spain");
            put("DE", "Europe/Berlin");
            put("TV", "Pacific/Funafuti");
            put("TW", "Asia/Taipei");
            put("DJ", "Africa/Djibouti");
            put("TZ", "Africa/Dar_es_Salaam");
            put("DK", "Europe/Copenhagen");
            put("DM", "America/Dominica");
            put("DO", "America/Santo_Domingo");
            put("UA", "Europe/Kyiv");
            put("UG", "Africa/Kampala");
            put("DZ", "Africa/Algiers");
            put("UM", "Pacific/Wake");
            put("EC", "Pacific/Galapagos");
            put("US", "America/Sitka");
            put("EE", "Europe/Tallinn");
            put("EG", "Africa/Cairo");
            put("UY", "America/Montevideo");
            put("UZ", "Asia/Samarkand");
            put("VA", "Europe/Vatican");
            put("VC", "America/St_Vincent");
            put("ER", "Africa/Asmara");
            put("ES", "Europe/Madrid");
            put("VE", "America/Caracas");
            put("ET", "Africa/Addis_Ababa");
            put("VG", "America/Tortola");
            put("VI", "America/St_Thomas");
            put("VN", "Asia/Ho_Chi_Minh");
            put("VU", "Pacific/Efate");
            put("FI", "Europe/Helsinki");
            put("FJ", "Pacific/Fiji");
            put("FK", "Atlantic/Stanley");
            put("FM", "Pacific/Pohnpei");
            put("FO", "Atlantic/Faroe");
            put("FR", "Europe/Paris");
            put("WF", "Pacific/Wallis");
            put("GA", "Africa/Libreville");
            put("GB", "Europe/London");
            put("WS", "Pacific/Apia");
            put("GD", "America/Grenada");
            put("GE", "Asia/Tbilisi");
            put("GF", "America/Cayenne");
            put("GG", "Europe/Guernsey");
            put("GH", "Africa/Accra");
            put("GI", "Europe/Gibraltar");
            put("GL", "America/Thule");
            put("GM", "Africa/Banjul");
            put("GN", "Africa/Conakry");
            put("GP", "America/Guadeloupe");
            put("GQ", "Africa/Malabo");
            put("GR", "Europe/Athens");
            put("GS", "Atlantic/South_Georgia");
            put("GT", "America/Guatemala");
            put("GU", "Pacific/Guam");
            put("GW", "Africa/Bissau");
            put("GY", "America/Guyana");
            put("HK", "Asia/Hong_Kong");
            put("HN", "America/Tegucigalpa");
            put("HR", "Europe/Zagreb");
            put("YE", "Asia/Aden");
            put("HT", "America/Port-au-Prince");
            put("HU", "Europe/Budapest");
            put("YT", "Indian/Mayotte");
            put("ID", "Asia/Pontianak");
            put("IE", "Europe/Dublin");
            put("IL", "Asia/Jerusalem");
            put("IM", "Europe/Isle_of_Man");
            put("IN", "Asia/Kolkata");
            put("IO", "Indian/Chagos");
            put("ZA", "Africa/Johannesburg");
            put("IQ", "Asia/Baghdad");
            put("IR", "Asia/Tehran");
            put("IS", "Atlantic/Reykjavik");
            put("IT", "Europe/Rome");
            put("ZM", "Africa/Lusaka");
            put("JE", "Europe/Jersey");
            put("ZW", "Africa/Harare");
            put("JM", "America/Jamaica");
            put("JO", "Asia/Amman");
            put("JP", "Asia/Tokyo");
            put("KE", "Africa/Nairobi");
            put("KG", "Asia/Bishkek");
            put("KH", "Asia/Phnom_Penh");
            put("KI", "Pacific/Kiritimati");
            put("KM", "Indian/Comoro");
            put("KN", "America/St_Kitts");
            put("KP", "Asia/Pyongyang");
            put("KR", "Asia/Seoul");
            put("KW", "Asia/Kuwait");
            put("KY", "America/Cayman");
            put("KZ", "Asia/Aqtobe");
            put("LA", "Asia/Vientiane");
            put("LB", "Asia/Beirut");
            put("LC", "America/St_Lucia");
            put("LI", "Europe/Vaduz");
            put("LK", "Asia/Colombo");
            put("LR", "Africa/Monrovia");
            put("LS", "Africa/Maseru");
            put("LT", "Europe/Vilnius");
            put("LU", "Europe/Luxembourg");
            put("LV", "Europe/Riga");
            put("LY", "Africa/Tripoli");
            put("MA", "Africa/El_Aaiun");
            put("MC", "Europe/Monaco");
            put("MD", "Europe/Chisinau");
            put("ME", "Europe/Podgorica");
            put("MF", "America/Marigot");
            put("MG", "Indian/Antananarivo");
            put("MH", "Pacific/Majuro");
            put("MK", "Europe/Skopje");
            put("ML", "Africa/Bamako");
            put("MM", "Asia/Yangon");
            put("MN", "Asia/Ulaanbaatar");
            put("MO", "Asia/Macau");
            put("MP", "Pacific/Saipan");
            put("MQ", "America/Martinique");
            put("MR", "Africa/Nouakchott");
            put("MS", "America/Montserrat");
            put("MT", "Europe/Malta");
            put("MU", "Indian/Mauritius");
            put("MV", "Indian/Maldives");
            put("MW", "Africa/Blantyre");
            put("MX", "America/Monterrey");
            put("MY", "Asia/Kuching");
            put("MZ", "Africa/Maputo");
            put("NA", "Africa/Windhoek");
            put("NC", "Pacific/Noumea");
            put("NE", "Africa/Niamey");
            put("NF", "Pacific/Norfolk");
            put("NG", "Africa/Lagos");
            put("NI", "America/Managua");
            put("NL", "Europe/Amsterdam");
            put("NO", "Europe/Oslo");
            put("NP", "Asia/Kathmandu");
            put("NR", "Pacific/Nauru");
            put("NU", "Pacific/Niue");
            put("NZ", "Pacific/Chatham");
            put("OM", "Asia/Muscat");
            put("PA", "America/Panama");
            put("PE", "America/Lima");
            put("PF", "Pacific/Marquesas");
            put("PG", "Pacific/Port_Moresby");
            put("PH", "Asia/Manila");
            put("PK", "Asia/Karachi");
            put("PL", "Europe/Warsaw");
            put("PM", "America/Miquelon");
            put("PN", "Pacific/Pitcairn");
        }
    };

    public static String getTimeZonesData(String region) {
        String s = timeZonesMap.get(region);
        if (StringUtils.isEmpty(s)) {

//            默认印度
            return "Asia/Kolkata";
        }
        return s;
    }    public static String getRegionByZone(String zone) {

        return timeZonesMap.entrySet().stream().filter(e -> e.getValue().equals(zone)).findFirst()
                .map(Map.Entry::getKey).orElse("CN");
    }


}
