package com.xkrs.utils;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期时间工具
 * @author tajochen
 */
public class DateTimeUtil {

    private final static String COMMON_PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss";
    private final static String COMMON_PATTERN_DATE = "yyyy-MM-dd";
    private final static DateTimeFormatter COMMON_FORMATTER_DATETIME = DateTimeFormatter.ofPattern(COMMON_PATTERN_DATETIME);
    private final static DateTimeFormatter COMMON_FORMATTER_DATE = DateTimeFormatter.ofPattern(COMMON_PATTERN_DATE);
    private final static ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.of("+8");

    /**
     * 字符串转LocalDate
     * @param date
     * @return
     */
    public static LocalDate stringToDate(String date) {
        assert date != null;
        return LocalDate.parse(date, COMMON_FORMATTER_DATE);
    }

    /**
     * LocalDate转字符串
     * @param date
     * @return
     */
    public static String dateToString(LocalDate date) {
        assert date != null;
        return COMMON_FORMATTER_DATE.format(date);
    }

    /**
     * LocalDateTime转字符串
     * @param dateTime
     * @return
     */
    public static String dateTimeToString(LocalDateTime dateTime) {
        assert dateTime != null;
        return COMMON_FORMATTER_DATETIME.format(dateTime);
    }

    /**
     * 字符串转LocalDateTime
     * @param dateStr
     * @return
     */
    public static LocalDateTime stringToDateTime(String dateStr) {
        assert dateStr != null;
        return LocalDateTime.parse(dateStr, COMMON_FORMATTER_DATETIME);
    }

    /**
     * 字符串转Instant时间戳
     * @param str
     * @return
     */
    public static Instant stringToInstant(String str) {
        assert str != null;
        return stringToDateTime(str).toInstant(DEFAULT_ZONE_OFFSET);
    }

    /**
     * LocalDateTime转字符串（格式化）
     * @param dateTime
     * @param formatter
     * @return
     */
    public static String dateToStringFormatter(LocalDateTime dateTime, DateTimeFormatter formatter) {
        assert dateTime != null;
        return formatter.format(dateTime);
    }

    /**
     * 字符串转LocalDateTime（格式化）
     * @param dateStr
     * @param formatter
     * @return
     */
    public static LocalDateTime stringToDateTimeFormatter(String dateStr, DateTimeFormatter formatter) {
        assert dateStr != null;
        return LocalDateTime.parse(dateStr, formatter);
    }

    /**
     * 字符串转 local date
     * @param dateStr
     * @return
     */
    public static LocalDate stringToDateFormatter(String dateStr){
        LocalDate date = LocalDate.parse(dateStr, COMMON_FORMATTER_DATE);
        return date;
    }


    /**
     * 日期转时间戳
     * @param dateTime
     * @return
     */
    public static long dateToTimeMillis(LocalDateTime dateTime) {
        assert dateTime != null;
        return dateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli();
    }

    /**
     * 时间戳转日期
     * @param timeMillis
     * @return
     */
    public static LocalDateTime timeMillisToDate(long timeMillis) {
        Instant instant = Instant.ofEpochMilli(timeMillis);
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONE_OFFSET);
    }

    /**
     * 时间戳转时间
     * @param timeMillis
     * @return
     */
    public static LocalDateTime timeMillisToTime(long timeMillis) {
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timeMillis, 0, ZoneOffset.ofHours(8));
        return localDateTime;
    }

    /**
     * 时间戳转时间再转字符串
     * @param timeMillis
     * @return
     */
    public static String timeMillisToString(long timeMillis){
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timeMillis, 0, ZoneOffset.ofHours(8));
        return COMMON_FORMATTER_DATETIME.format(localDateTime);
    }

    /**
     * 获取当前时间 hh:mm:ss:nnn
     * @return
     */
    public static LocalDateTime getNowTime() {
        LocalDateTime now = LocalDateTime.now();
        return now;
    }

    /**
     * 获取当前日期 yyyy-MM-dd
     * @return
     */
    public static LocalDate getToday() {
        LocalDate now = LocalDate.now();
        return now;
    }

    /**
     * 获取当前 Instant 时间戳
     * @return
     */
    public static Instant getInstant() {
        Instant timeStamp = Instant.now();
        return timeStamp;
    }

    /**
     * 获取当前时间 yyyy-MM-ss hh:mm:ss
     * @return
     */
    public static String getNowTimeStr(){
        return COMMON_FORMATTER_DATETIME.format(getNowTime());
    }

    /**
     * 判断日期格式是否合法 "yyyy-MM-dd"
     * @param strDate
     * @return
     */
    public static boolean isValidDate(String strDate) {
        final int minLen = 10;
        if(strDate == null || strDate.length() < minLen) {
            return false;
        }
        //正则表达式校验日期格式 yyyy-MM-dd
        String eL = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-" +
                "(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})" +
                "(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)(([0-9]{3}[1-9]|[0-9]{2}[1-9]" +
                "[0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-" +
                "(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|" +
                "((0[48]|[2468][048]|[3579][26])00))-02-29)";
        Pattern pat = Pattern.compile(eL);
        Matcher matcher = pat.matcher(strDate);
        return matcher.matches();
    }

    /**
     * 判断时间格式 格式必须为 "YYYY-MM-DD HH:mm:ss"
     * @param sDateTime
     * @return
     */
    public static boolean isValidDateTime(String sDateTime) {
        final int minLen = 19;
        if ((sDateTime == null) || (sDateTime.length() < minLen)) {
            return false;
        }
        String eL = "(((01[0-9]{2}|0[2-9][0-9]{2}|[1-9][0-9]{3})-(0?[13578]|1[02])-" +
                "(0?[1-9]|[12]\\\\d|3[01]))|((01[0-9]{2}|0[2-9][0-9]{2}|[1-9][0-9]{3})-" +
                "(0?[13456789]|1[012])-(0?[1-9]|[12]\\\\d|30))|((01[0-9]{2}|0[2-9][0-9]{2}|[1-9][0-9]{3})-0?2-" +
                "(0?[1-9]|1\\\\d|2[0-8]))|(((1[6-9]|[2-9]\\\\d)(0[48]|[2468][048]|[13579][26])|((04|08|12|16|[2468][048]|" +
                "[3579][26])00))-0?2-29)) (20|21|22|23|[0-1]?\\\\d):[0-5]?\\\\d:[0-5]?\\\\d";
        Pattern pat = Pattern.compile(eL);
        Matcher matcher = pat.matcher(sDateTime);
        return matcher.matches();
    }

    public static void main(String[] args) {
        LocalDate now = LocalDate.now();
        LocalDate localDate = now.plusDays(1);
        String s = dateToString(localDate);
        LocalDate localDate1 = stringToDate(s);
        System.out.println(localDate1);
    }

}
