package com.energy.manage.common.util;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Minutes;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * Created by lt on 2017/3/20.
 */
public class DateTools {
    private static final String DATE = "yyyy-MM-dd";
    private static final String DATE_TIME = "yyyy-MM-dd HH:mm";
    private static final String DATE_TIME_WEB = "yyyy/MM/dd HH:mm";
    private static final String TIME = "yyyy-MM-dd HH:mm:ss";
    private static final String HOUR_SECOND = "HH:mm";
    private static final String UTC_TIME = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";


    private static final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE);
    private static final SimpleDateFormat dateTimeFormat = new SimpleDateFormat(DATE_TIME);
    private static final SimpleDateFormat dateWebTimeFormat = new SimpleDateFormat(DATE_TIME_WEB);
    private static final SimpleDateFormat timeFormat = new SimpleDateFormat(TIME);
    private static final SimpleDateFormat hourMinutesFormat = new SimpleDateFormat(HOUR_SECOND);
    private static final SimpleDateFormat utcFormat = new SimpleDateFormat(UTC_TIME);

    private static HashMap<Integer, String> dayMap = new HashMap<Integer, String>();

    static {
        dayMap.put(1, "周一");
        dayMap.put(2, "周二");
        dayMap.put(3, "周三");
        dayMap.put(4, "周四");
        dayMap.put(5, "周五");
        dayMap.put(6, "周六");
        dayMap.put(7, "周日");
    }

    public static Date getCurrentDateTime() {
        Date date = new Date();
        return date;
    }

    public static int daysOfTime(Date start, Date end) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date fDate = sdf.parse(getFormatData(start.getTime()));
            Date oDate = sdf.parse(getFormatData(end.getTime()));
            int days = (int) (oDate.getTime() - fDate.getTime()) / (1000 * 3600 * 24);
            return days;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static Date str2Date(String date, String format) {
        if (StringTools.isNotBlank(date)) {
            DateFormat parser = new SimpleDateFormat(format);
            try {
                return parser.parse(date);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    /**
     * 获取时分秒毫秒
     *
     * @return
     */
    public static String getDayMonth() {
        Calendar c = Calendar.getInstance();//可以对每个时间域单独修改
        String year = StringTools.getString(c.get(Calendar.YEAR));
        String month = StringTools.getString(c.get(Calendar.MONTH) + 1);
        String date = StringTools.getString(c.get(Calendar.DATE));
        String hour = StringTools.getString(c.get(Calendar.HOUR_OF_DAY));
        String minute = StringTools.getString(c.get(Calendar.MINUTE));
        String second = StringTools.getString(c.get(Calendar.SECOND));
        String millisecond = StringTools.getString(c.get(Calendar.MILLISECOND));
        return year + month + date + hour + minute + second + millisecond;
    }

    /**
     * 获取距离当前日期N天的日期 正值为之后日期 负值为之前日期
     */
    public static Date getDateByDays(Date oldDate, int days) {
        Calendar theCa = Calendar.getInstance();
        theCa.setTime(oldDate);
        theCa.add(theCa.DAY_OF_MONTH, days);
        Date date = theCa.getTime();
        return date;
    }

    public static int getWeeks(Date startdate, Date enddate) {
        int temp = 0;
        try {
            temp = (int) ((enddate.getTime() - startdate.getTime()) / 86400000 / 7);
            if ((enddate.getTime() - startdate.getTime()) % 86400000 > 0) {
                temp = temp + 1;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }

    public static int getWeeks(String startdate, String enddate) {
        int temp = 0;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date dateStart = sdf.parse(startdate);
            Date dateEnd = sdf.parse(enddate);
            temp = (int) ((dateEnd.getTime() - dateStart.getTime()) / 86400000 / 7);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return temp;
    }


    /**
     * 根据时间戳返回时间串
     *
     * @return
     */
    public static String getFormatData(long date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateString = sdf.format(new Date(date));
        return dateString;

    }

    /**
     * 根据时间戳返回时间串
     *
     * @return
     */
    public static String getFormatDataCN(long date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String dateString = sdf.format(new Date(date));
        return dateString;

    }

    /**
     * 根据时间戳返回时间串
     *
     * @return
     */
    public static String getYearFormat(long date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        String dateString = sdf.format(new Date(date));
        return dateString;

    }


    /**
     * 根据时间戳返回时间串
     *
     * @return
     */
    public static Date formatFormat(String date) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date dateString = sdf.parse(date);
            return dateString;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据时间戳返回时间串
     *
     * @return
     */
    public static String formatFormat(Date date, String format) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            String dateString = sdf.format(date);
            return dateString;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 判断是否相等
     *
     * @param d1
     * @param d2
     * @return
     */
    public static boolean sameDate(Date d1, Date d2) {
        if (null == d1 || null == d2)
            return false;
        //return getOnlyDate(d1).equals(getOnlyDate(d2));
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(d1);
        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(d2);
        return cal1.get(0) == cal2.get(0) && cal1.get(1) == cal2.get(1) && cal1.get(6) == cal2.get(6);
    }

    //判断两个日期是否为同一天
    public static boolean isSameDate(Date date1, Date date2) {
        Calendar cal1 = Calendar.getInstance();
        cal1.setTime(date1);

        Calendar cal2 = Calendar.getInstance();
        cal2.setTime(date2);

        boolean isSameYear = cal1.get(Calendar.YEAR) == cal2
                .get(Calendar.YEAR);
        boolean isSameMonth = isSameYear
                && cal1.get(Calendar.MONTH) == cal2.get(Calendar.MONTH);
        boolean isSameDate = isSameMonth
                && cal1.get(Calendar.DAY_OF_MONTH) == cal2
                .get(Calendar.DAY_OF_MONTH);

        return isSameDate;
    }

    public static String getDateFromString(Date time, String pattern) {
        if (time == null) {
            return "";
        }
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        return formatter.format(time);

    }

    // 获取当前时间所在年的周数
    public static int getWeekOfYear(Date date) {
        Calendar c = new GregorianCalendar();
        c.setFirstDayOfWeek(Calendar.MONDAY);
        c.setMinimalDaysInFirstWeek(7);
        c.setTime(date);

        return c.get(Calendar.WEEK_OF_YEAR);
    }

    // 获取当前时间所在年的最大周数
    public static int getMaxWeekNumOfYear(int year) {
        Calendar c = new GregorianCalendar();
        c.set(year, Calendar.DECEMBER, 31, 23, 59, 59);

        return getWeekOfYear(c.getTime());
    }

    public static int getZygjWeeks(Date startdate, Date enddate) {
        int startYear = 0;
        int endYear = 0;
        int startWeeks = 0;
        int endWeeks = 0;
        int temp = 0;
        Calendar caSta = Calendar.getInstance();
        Calendar caEnd = Calendar.getInstance();
        caSta.clear();
        caSta.clear();
        caSta.setTime(startdate);
        caEnd.setTime(enddate);
        startYear = caSta.get(Calendar.YEAR);
        endYear = caEnd.get(Calendar.YEAR);
        try {
            if (endYear > startYear) {
                int endSameYearEnd = getMaxWeekNumOfYear(startYear);
                startWeeks = caSta.get(Calendar.WEEK_OF_YEAR);
                //endWeeks = caEnd.get(Calendar.WEEK_OF_YEAR);

                //startWeeks=getYearWeek(caSta);
                endWeeks = getYearWeek(caEnd);
                int day = 1;
                return endSameYearEnd - startWeeks + day + endWeeks;
            } else {
                startWeeks = caSta.get(Calendar.WEEK_OF_YEAR);
                //endWeeks = caEnd.get(Calendar.WEEK_OF_YEAR);
                endWeeks = getYearWeek(caEnd);
                int day = 1;
                return endWeeks - startWeeks + day;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


    /**
     * 计算开始日期所在周的周一
     *
     * @param time
     * @return
     */
    public static Date convertWeekMondayDate(Date time) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //设置时间格式

        Calendar cal = Calendar.getInstance();

        cal.setTime(time);

        //判断要计算的日期是否是周日，如果是则减一天计算周六的，否则会出问题，计算到下一周去了

        int dayWeek = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天

        if (1 == dayWeek) {

            cal.add(Calendar.DAY_OF_MONTH, -1);

        }
        cal.setFirstDayOfWeek(Calendar.MONDAY);//设置一个星期的第一天，按中国的习惯一个星期的第一天是星期一
        int day = cal.get(Calendar.DAY_OF_WEEK);//获得当前日期是一个星期的第几天
        cal.add(Calendar.DATE, cal.getFirstDayOfWeek() - day);//根据日历的规则，给当前日期减去星期几与一个星期第一天的差值
        return cal.getTime();


    }

    // 获取第几周所在的月份
    public static int getWeekNumOfMonth(int num, Map<Integer, Map<Integer, String>> weekNumDate) {

        Map<Integer, String> weekMap = weekNumDate.get(num);
        Calendar theCa = Calendar.getInstance();
        theCa.setTime(str2Date(weekMap.get(7), "yyyy-MM-dd"));
        return theCa.get(Calendar.MONTH) + 1;

    }

    // 获取第几周所在的月份
    public static int getWeekNumOfMonth(Date date) {
        Calendar theCa = Calendar.getInstance();
        theCa.setTime(date);
        return theCa.get(Calendar.MONTH) + 1;

    }

    public static boolean betweenDate(Date date, Date begin, Date end) {
        if (date.getTime() >= begin.getTime() && date.getTime() <= end.getTime()) {
            return true;
        } else {
            return false;
        }
    }

    public static boolean compareDate(Date begin, Date end) {
        if (begin.before(end)) {
            //表示bt小于et
            return false;
        } else {
            return true;
        }
    }

    public static String compareDateDay(Date date1, Date date2) {
        if (date1 == null) {
            return StringTools.getString(0);
        }
        int days = 0;
        try {
            double diff = (double) date1.getTime() - date2.getTime();
            days = (int) Math.floor((diff / (1000 * 60 * 60 * 24)));
        } catch (Exception e) {
        }
        return String.valueOf(days);
    }

    /**
     * 判断时间是否在时间段内 *
     *
     * @param date         当前时间 yyyy-MM-dd HH:mm:ss
     * @param strDateBegin 开始时间 00:00:00
     * @param strDateEnd   结束时间 00:05:00
     * @return
     */
    public static boolean isInDate(Date date, String strDateBegin,

                                   String strDateEnd) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        String strDate = sdf.format(date);

// 截取当前时间时分秒

        int strDateH = Integer.parseInt(strDate.substring(11, 13));

        int strDateM = Integer.parseInt(strDate.substring(14, 16));

        int strDateS = Integer.parseInt(strDate.substring(17, 19));

// 截取开始时间时分秒

        int strDateBeginH = Integer.parseInt(strDateBegin.substring(0, 2));

        int strDateBeginM = Integer.parseInt(strDateBegin.substring(3, 5));

        int strDateBeginS = Integer.parseInt(strDateBegin.substring(6, 8));

// 截取结束时间时分秒

        int strDateEndH = Integer.parseInt(strDateEnd.substring(0, 2));

        int strDateEndM = Integer.parseInt(strDateEnd.substring(3, 5));

        int strDateEndS = Integer.parseInt(strDateEnd.substring(6, 8));

        if ((strDateH >= strDateBeginH && strDateH <= strDateEndH)) {

// 当前时间小时数在开始时间和结束时间小时数之间

            if (strDateH > strDateBeginH && strDateH < strDateEndH) {

                return true;

// 当前时间小时数等于开始时间小时数，分钟数在开始和结束之间

            } else if (strDateH == strDateBeginH && strDateM >= strDateBeginM

                    && strDateM <= strDateEndM) {

                return true;

// 当前时间小时数等于开始时间小时数，分钟数等于开始时间分钟数，秒数在开始和结束之间

            } else if (strDateH == strDateBeginH && strDateM == strDateBeginM

                    && strDateS >= strDateBeginS && strDateS <= strDateEndS) {

                return true;

            }

// 当前时间小时数大等于开始时间小时数，等于结束时间小时数，分钟数小等于结束时间分钟数

            else if (strDateH >= strDateBeginH && strDateH == strDateEndH

                    && strDateM <= strDateEndM) {

                return true;

// 当前时间小时数大等于开始时间小时数，等于结束时间小时数，分钟数等于结束时间分钟数，秒数小等于结束时间秒数

            } else if (strDateH >= strDateBeginH && strDateH == strDateEndH

                    && strDateM == strDateEndM && strDateS <= strDateEndS) {

                return true;

            } else {

                return false;

            }

        } else {

            return false;

        }

    }


    /**
     * 判断时间是否在时间段内 *
     *
     * @param date    当前时间 yyyy-MM-dd HH:mm:ss
     * @param staDate 开始时间 00:00:00
     * @param endDate 结束时间 00:05:00
     * @return
     */
    public static boolean isInDate(Date date, Date staDate, Date endDate) {

        long current = date.getTime();
        long staTime = staDate.getTime();
        long endTime = endDate.getTime();
        if (current - staTime < 0) {
            return false;//当前时间在开始时间之前
        }
        if (current - endTime > 0) {
            return false;//当前时间在结束时间之后
        }
        if ((current - staTime > 0) && (current - endTime < 0)) {
            return true;
        }
        return false;
    }

    /**
     * 判断时间是否在时间段内(判断专用) *
     *
     * @param date    当前时间 yyyy-MM-dd HH:mm:ss
     * @param staDate 开始时间 00:00:00
     * @param endDate 结束时间 00:05:00
     * @return
     */
    public static boolean isInDate2(Date date, Date staDate, Date endDate) {

        return (date.getTime() >= staDate.getTime()) && (date.getTime() <= endDate.getTime());
    }

    /**
     * 把一个时间重置成0点
     *
     * @param startDate
     * @return
     */
    public static Date getStartDate(Date startDate) {
        Calendar calendarStart = Calendar.getInstance();
        calendarStart.setTime(startDate);
        calendarStart.set(calendarStart.get(Calendar.YEAR),
                calendarStart.get(Calendar.MONTH),
                calendarStart.get(Calendar.DATE),
                0, 0, 0);

        startDate = calendarStart.getTime();
        return startDate;
    }

    /**
     * 把数字星期几转化为中文
     *
     * @param day
     * @return
     */
    public static String getWeekOfDay(int day) {
        return dayMap.get(day);
    }

    public static String date2Str(Date date, String format) {
        if (date != null) {
            DateFormat parser = new SimpleDateFormat(format);
            try {
                return parser.format(date);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    public static int daysBetween(Date date1, Date date2) {
        return Days.daysBetween(new DateTime(date1), new DateTime(date2)).getDays();
    }

    public static int minuteBetween(Date date1, Date date2) {
        return Minutes.minutesBetween(new DateTime(date1), new DateTime(date2)).getMinutes();
    }


    /**
     * 获取周数，如果一年最后一天如果是周日，周数不对，推算倒数第二天周数,如果一般周日，算到前一周
     *
     * @param
     * @return
     */
    public static int getYearWeek(Calendar calendar) {
        //周日
        if (calendar.get(Calendar.DAY_OF_WEEK) == 1) {
            //Date temp=calendar.getTime();

            Calendar temp = Calendar.getInstance();
            temp.clear();
            temp.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
            temp.roll(Calendar.DAY_OF_YEAR, -1);
            //一年最后一天
            if (temp.getTimeInMillis() == calendar.getTimeInMillis()) {
                temp.roll(Calendar.DAY_OF_YEAR, -1);
                return temp.get(Calendar.WEEK_OF_YEAR);
            } else {
                //正常周日
                return calendar.get(Calendar.WEEK_OF_YEAR) - 1;
            }
        } else {
            //周一到周六
            return calendar.get(Calendar.WEEK_OF_YEAR);
        }
    }

    /**
     * 在当前时间基础加一天或者减几天
     *
     * @param num 为正表示加几天，为负表示减几天
     * @return
     */
    public static Date plusOrMinusDay(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, num);
        return calendar.getTime();
    }

    /**
     * 处理日期只留年月日
     *
     * @param date
     * @param num
     * @return
     */
    public static Date plusOrMinusDayByTime(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, num);
        Date dateTime = calendar.getTime();
        return formatFormat(getFormatData(dateTime.getTime()) + " 00:00:00");
    }

    public static Date addMonth(Date date1, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date1);
        calendar.add(Calendar.MONTH, month);
        return calendar.getTime();
    }

    public static String[] getMonthRange(Date startTime, Date endTime) {
        ArrayList<String> dates = new ArrayList<String>();
        dates.add(getYearFormat(startTime.getTime()));
        String end = getYearFormat(endTime.getTime());
        int number = 0;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);
        while (number++ < 11) {
            calendar.add(Calendar.MONTH, 1);
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            String time = getYearFormat(calendar.getTimeInMillis());
            dates.add(time);
            if (end.equals(time)) {
                calendar.add(Calendar.MONTH, 1);
                calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
                dates.add(getYearFormat(calendar.getTimeInMillis()));
                break;
            }
        }
        String[] strings = new String[dates.size()];
        dates.toArray(strings);
        return strings;
    }


    public static Date getDate(String strTime) {
        if (strTime == null || strTime.length() == 0) {
            return null;
        }
        return new Date(StringTools.getLong(strTime));
    }

    public static String format(Date date, DateType dateType) {
        if (date == null) {
            return null;
        }
        if (Objects.equals(dateType.name(), DateType.DATE.name())) {
            return dateFormat.format(date);
        } else if (Objects.equals(dateType.name(), DateType.DATE_TIME.name())) {
            return dateTimeFormat.format(date);
        } else if (Objects.equals(dateType.name(), DateType.DATE_TIME_WEB.name())) {
            return dateWebTimeFormat.format(date);
        } else if (Objects.equals(dateType.name(), DateType.TIME.name())) {
            return timeFormat.format(date);
        } else if (Objects.equals(dateType.name(), DateType.HOUR_MINUTES.name())) {
            return hourMinutesFormat.format(date);
        }
        return "";
    }


    public enum DateType {
        DATE,
        DATE_TIME,
        DATE_TIME_WEB,
        TIME,
        HOUR_MINUTES
    }

    /**
     * LocalDateTime转毫秒时间戳
     *
     * @param localDateTime LocalDateTime
     * @return 时间戳
     */
    public static Long localDateTimeToTimestamp(LocalDateTime localDateTime) {
        try {
            ZoneId zoneId = ZoneId.systemDefault();
            Instant instant = localDateTime.atZone(zoneId).toInstant();
            return instant.toEpochMilli();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param timestamp 时间戳
     * @return LocalDateTime
     */
    public static LocalDateTime timestampToLocalDateTime(long timestamp) {
        try {
            Instant instant = Instant.ofEpochMilli(timestamp);
            ZoneId zone = ZoneId.systemDefault();
            return LocalDateTime.ofInstant(instant, zone);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Date转LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        try {
            Instant instant = date.toInstant();
            ZoneId zoneId = ZoneId.systemDefault();
            return instant.atZone(zoneId).toLocalDateTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * LocalDateTime转Date
     *
     * @param localDateTime LocalDateTime
     * @return Date
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        try {
            ZoneId zoneId = ZoneId.systemDefault();
            ZonedDateTime zdt = localDateTime.atZone(zoneId);
            return Date.from(zdt.toInstant());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
