package com.artfess.base.util.time;

import com.artfess.base.util.BeanUtils;
import com.artfess.base.util.string.StringPool;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.text.ParseException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



/**
 * 日期转换、计算工具类
 *
 * @company 阿特菲斯信息技术有限公司
 * @author heyifan
 * @email heyf@jee-soft.cn
 * @date 2018年4月11日
 */
public class DateUtil {

	@SuppressWarnings("unused")
	private static final Log logger = LogFactory.getLog(DateUtil.class);

	/**
	 * 将LocalDate转为Date，时间是00:00:00
	 * @param localDate
	 * @return
	 */
	public static Date asDate(LocalDate localDate) {
		return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
	}

	/**
	 * 将LocalDateTime转为Date
	 * @param localDate
	 * @return
	 */
	public static Date asDate(LocalDateTime localDateTime) {
		return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
	}

	/**
	 * 将Date转为LocalDate
	 * @param date
	 * @return
	 */
	public static LocalDate asLocalDate(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
	}

	/**
	 * 将Date转为LocalDateTime
	 * @param date
	 * @return
	 */
	public static LocalDateTime asLocalDateTime(Date date) {
		return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
	}
	
	public static Calendar toCalendar(LocalDateTime date) {
		Calendar c = Calendar.getInstance();
		ZoneId zone = ZoneId.systemDefault();
	    Instant instant = date.atZone(zone).toInstant();
	    Date udate = Date.from(instant);
		c.setTime(udate);
		return c;
	}
	/**
	 * 将传入时间初始化为当天的最初时间（即00时00分00秒）
	 *
	 * @param date
	 *            时间
	 * @return 当天最初时间
	 */
	public static LocalDateTime setAsBegin(LocalDateTime date) {
		LocalDateTime ndate = LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 0, 0, 0);
		return ndate;
	}

	/**
	 * 将传入时间初始化为当天的结束时间（即23时59分59秒）
	 *
	 * @param date
	 *            时间
	 * @return 当天结束时间
	 */
	public static LocalDateTime setAsEnd(LocalDateTime date) {
		LocalDateTime ndate = LocalDateTime.of(date.getYear(), date.getMonthValue(), date.getDayOfMonth(), 23, 59, 59);
		return ndate;
	}

	/**
	 * 取当前系统日期，并按指定格式或者是默认格式返回
	 *
	 * @param style
	 *            指定格式
	 * @return 当前系统日期（字符串）
	 */
	public static String getCurrentTime(String style) {
		if (StringUtils.isEmpty(style))
			style = StringPool.DATE_FORMAT_DATETIME;
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern(style);
		return LocalDateTime.now().format(formatter);
	}

	/**
	 * 取当前系统日期，并按指定格式（yyyy-MM-dd HH:mm:ss ）
	 *
	 * @return 当前系统日期
	 */
	public static String getCurrentTime() {
		return getCurrentTime("");
	}

	/**
	 * 取当前系统日期（日期格式）
	 *
	 * @return 当前系统日期（日期）
	 */
	public static LocalDateTime getCurrentDate() {
		return LocalDateTime.now();
	}

	/**
	 * 取当前系统日期
	 *
	 * @return 当前系统日期（Long格式）
	 */
	public static long getCurrentTimeInMillis() {
		return Calendar.getInstance().getTimeInMillis();
	}

	/**
	 * 得到两日期间所有日期，含起始和结束日期
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return
	 * @throws Exception
	 */
	public static LocalDateTime[] getDaysBetween(LocalDateTime startDate, LocalDateTime endDate) {
		// 计算之间有多少天
		long day = (startDate.toInstant(ZoneOffset.of("+8")).toEpochMilli() - endDate.toInstant(ZoneOffset.of("+8")).toEpochMilli())
				/ (24 * 60 * 60 * 1000) > 0 ? (startDate.toInstant(ZoneOffset.of("+8")).toEpochMilli() - endDate
				.toInstant(ZoneOffset.of("+8")).toEpochMilli()) / (24 * 60 * 60 * 1000)
				: (endDate.toInstant(ZoneOffset.of("+8")).toEpochMilli() - startDate.toInstant(ZoneOffset.of("+8")).toEpochMilli())
						/ (24 * 60 * 60 * 1000);
		// 声明日期数组
		LocalDateTime[] dateArr = new LocalDateTime[Integer.valueOf(String.valueOf(day + 1))];
		// 将日期加进去
		for (int i = 0; i < dateArr.length; i++) {
			if (i == 0) {
				dateArr[i] = setAsBegin(startDate);
			} else {
				LocalDateTime nextDay = startDate.plusDays(1);
				startDate = DateUtil.setAsBegin(nextDay);
				dateArr[i] = startDate;
			}
		}
		return dateArr;
	}

	/**
	 * 取得指定年月的天数
	 *
	 * @param year
	 *            实际年份
	 * @param mon
	 *            实际月份 数值范围是1~12
	 * @return
	 */
	public static int getDaysOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		return cal.getActualMaximum(Calendar.DAY_OF_MONTH);

	}

	/**
	 * 取得某月第一天为星期几。<br>
	 * 星期天为1。 星期六为7。
	 *
	 * @param year
	 * @param mon
	 * @return
	 */
	public static int getWeekDayOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(year, month - 1, 1);
		return cal.get(Calendar.DAY_OF_WEEK);
	}

	/**
	 * 比较两个时间大小，结束时间是否大于开始时间 传入的是字符串，会转成日期对象在进行比较。
	 *
	 * @param beginDateStr
	 * @param endDateStr
	 * @return
	 */
	public static boolean compare(String beginDateStr, String endDateStr) {
		try {
			LocalDateTime beginDate = DateFormatUtil.parse(beginDateStr);
			LocalDateTime endDate = DateFormatUtil.parse(endDateStr);
			return beginDate.compareTo(endDate) < 0;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * 比较两个时间大小，结束时间是否大于开始时间 传入的是字符串，会转成日期对象在进行比较。
	 *
	 * @param beginDateStr
	 * @param endDateStr
	 * @return
	 */
	public static int compareTo(String beginDateStr, String endDateStr) {
		try {
			LocalDateTime beginDate = DateFormatUtil.parse(beginDateStr);
			LocalDateTime endDate = DateFormatUtil.parse(endDateStr);
			return beginDate.compareTo(endDate);
		} catch (Exception e) {
			return -2;
		}
	}

	/**
	 * 取得日期。
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 * @return
	 */
	public static LocalDateTime getDate(int year, int month, int date) {
		return getDate(year, month, date, 0, 0, 0);
	}

	/**
	 * 取得日期。
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param date
	 *            日
	 * @param hourOfDay
	 *            小时
	 * @param minute
	 *            分钟
	 * @param second
	 *            秒
	 * @return
	 */
	public static LocalDateTime getDate(int year, int month, int date, int hourOfDay,
			int minute, int second) {
		LocalDateTime dateTime = LocalDateTime.of(year, month , date, hourOfDay, minute, second);
		return dateTime;
	}

	/**
	 * 获取开始和结束时间的毫秒差
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return
	 */
	public static long getTime(LocalDateTime startTime, LocalDateTime endTime) {
		ZoneId zone = ZoneId.systemDefault();
	    Instant sinstant = startTime.atZone(zone).toInstant();
	    Instant einstant = endTime.atZone(zone).toInstant();
		return einstant.toEpochMilli() - sinstant.toEpochMilli();
	}

	/**
	 * 获取指定时间到系统时间的持续时间
	 *
	 * @param date
	 *            指定时间
	 * @return
	 */
	public static String getDurationTime(LocalDateTime date) {
		return getDurationTime(date, LocalDateTime.now());
	}

	/**
	 * 获取持续时间
	 *
	 * @param startTime
	 * @param endTime
	 * @return
	 */
	public static String getDurationTime(LocalDateTime startTime, LocalDateTime endTime) {
		if (startTime == null || endTime == null)
			return "";
		Long millseconds = getTime(startTime, LocalDateTime.now());
		return getTime(millseconds);
	}

	/**
	 * 根据长整形的毫秒数返回字符串类型的时间段
	 *
	 * @param millseconds
	 *            毫秒数
	 * @return
	 */
	public static String getTime(Long millseconds) {
		StringBuffer time = new StringBuffer();
		if (millseconds == null)
			return "";
		int days = (int) (long) millseconds / 1000 / 60 / 60 / 24;
		if (days > 0)
			time.append(days).append("天");
		long hourMillseconds = millseconds - days * 1000 * 60 * 60 * 24;
		int hours = (int) hourMillseconds / 1000 / 60 / 60;
		if (hours > 0)
			time.append(hours).append("小时");
		long minuteMillseconds = millseconds - days * 1000 * 60 * 60 * 24
				- hours * 1000 * 60 * 60;
		int minutes = (int) minuteMillseconds / 1000 / 60;
		if (minutes > 0)
			time.append(minutes).append("分钟");
		return time.toString();
	}

	/**
     * 判断时间是否在时间段内
     * @param nowTime
     * @param beginTime
     * @param endTime
     * @return
     */
    public static boolean belongCalendar(LocalDateTime nowTime, LocalDateTime beginTime, LocalDateTime endTime) {
        Calendar date = Calendar.getInstance();
        ZoneId zone = ZoneId.systemDefault();
	    Instant nowinstant = nowTime.atZone(zone).toInstant();
	    Date nowdate = Date.from(nowinstant);
        date.setTime(nowdate);

        Instant begininstant = beginTime.atZone(zone).toInstant();
	    Date begindate = Date.from(begininstant);
        Calendar begin = Calendar.getInstance();
        begin.setTime(begindate);

        Instant endinstant = endTime.atZone(zone).toInstant();
	    Date enddate = Date.from(endinstant);
        Calendar end = Calendar.getInstance();
        end.setTime(enddate);

        if ((date.after(begin)||nowinstant.toEpochMilli()==begininstant.toEpochMilli())
        		&& (date.before(end)||nowinstant.toEpochMilli()==endinstant.toEpochMilli())) {
            return true;
        } else {
            return false;
        }
    }
	/**
	 * 开始时间是否等于结束时间
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return
	 */
	public static boolean isDateEquals(LocalDateTime startTime, LocalDateTime endTime) {
		if (BeanUtils.isEmpty(startTime) && BeanUtils.isEmpty(endTime)) {
			return true;
		}
		if (BeanUtils.isNotEmpty(startTime) && BeanUtils.isNotEmpty(endTime)) {
			return startTime.toEpochSecond(ZoneOffset.of("+8")) - endTime.toEpochSecond(ZoneOffset.of("+8")) == 0;
		}
		return false;

	}

	public static boolean isDateEquals(LocalDateTime startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime) && BeanUtils.isEmpty(endTime)) {
			return true;
		}
		if (BeanUtils.isNotEmpty(startTime) && BeanUtils.isNotEmpty(endTime)) {
			try {
				LocalDateTime date = DateFormatUtil.parse(endTime);
				return startTime.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) < 0;
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		return false;
	}

	public static boolean isDateEquals(String startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime) && BeanUtils.isEmpty(endTime)) {
			return true;
		}
		if (BeanUtils.isNotEmpty(startTime) && BeanUtils.isNotEmpty(endTime)) {
			try {
				LocalDateTime sdate = DateFormatUtil.parse(startTime);
				LocalDateTime date = DateFormatUtil.parse(endTime);
				return sdate.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) < 0;
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		return false;
	}


	public static boolean isDateLarge(LocalDateTime startTime, LocalDateTime endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		return startTime.toEpochSecond(ZoneOffset.of("+8")) - endTime.toEpochSecond(ZoneOffset.of("+8")) > 0;
	}

	public static boolean isDateLarge(LocalDateTime startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		try {
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return startTime.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) > 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}

	public static boolean isDateLarge(String startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		try {
			LocalDateTime sdate = DateFormatUtil.parse(startTime);
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return sdate.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) > 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}


	/**
	 * 开始时间是否小于结束时间
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return
	 */
	public static boolean isDateLittle(LocalDateTime startTime, LocalDateTime endTime) {
		if (BeanUtils.isEmpty(startTime) && BeanUtils.isNotEmpty(endTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		return startTime.toEpochSecond(ZoneOffset.of("+8")) - endTime.toEpochSecond(ZoneOffset.of("+8")) < 0;
	}

	public static boolean isDateLittle(LocalDateTime startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		try {
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return startTime.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) < 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;

	}

	public static boolean isDateLittle(String startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		try {
			LocalDateTime sdate = DateFormatUtil.parse(startTime);
			LocalDateTime edate = DateFormatUtil.parse(endTime);
			return sdate.toEpochSecond(ZoneOffset.of("+8")) - edate.toEpochSecond(ZoneOffset.of("+8")) < 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;

	}




	public static boolean isDateLargeEquals(LocalDateTime startTime, LocalDateTime endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		return startTime.toEpochSecond(ZoneOffset.of("+8")) - endTime.toEpochSecond(ZoneOffset.of("+8")) >= 0;
	}

	public static boolean isDateLargeEquals(LocalDateTime startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		try {
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return startTime.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) >= 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}

	public static boolean isDateLargeEquals(String startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return false;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return true;
		}
		try {
			LocalDateTime sdate = DateFormatUtil.parse(startTime);
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return sdate.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) >= 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}


	/**
	 * 开始时间是否小于等于结束时间
	 *
	 * @param startTime
	 *            开始时间
	 * @param endTime
	 *            结束时间
	 * @return
	 */
	public static boolean isDateLittleEquals(LocalDateTime startTime, LocalDateTime endTime) {
		if (BeanUtils.isEmpty(startTime) && BeanUtils.isNotEmpty(endTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		return startTime.toEpochSecond(ZoneOffset.of("+8")) - endTime.toEpochSecond(ZoneOffset.of("+8")) <= 0;
	}

	public static boolean isDateLittleEquals(LocalDateTime startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		try {
			LocalDateTime date = DateFormatUtil.parse(endTime);
			return startTime.toEpochSecond(ZoneOffset.of("+8")) - date.toEpochSecond(ZoneOffset.of("+8")) <= 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;

	}

	public static boolean isDateLittleEquals(String startTime, String endTime) {
		if (BeanUtils.isEmpty(startTime)) {
			return true;
		}
		if (BeanUtils.isEmpty(endTime)) {
			return false;
		}
		try {
			LocalDateTime sdate = DateFormatUtil.parse(startTime);
			LocalDateTime edate = DateFormatUtil.parse(endTime);
			return sdate.toEpochSecond(ZoneOffset.of("+8")) - edate.toEpochSecond(ZoneOffset.of("+8")) <= 0;
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;

	}

	public static boolean isDateBelongTo(String time, String boundary) {
		if (BeanUtils.isEmpty(time) || BeanUtils.isEmpty(boundary)) {
			return false;
		}
		try {
			LocalDateTime date = DateFormatUtil.parse(time);
			String[] boundaryArr = boundary.split(",");
			if (boundaryArr.length != 2) {
				return false;
			}
			LocalDateTime sdate = DateFormatUtil.parse(boundaryArr[0]);
			LocalDateTime edate = DateFormatUtil.parse(boundaryArr[1]);
			return date.toEpochSecond(ZoneOffset.of("+8")) >= sdate.toEpochSecond(ZoneOffset.of("+8"))
					&& date.toEpochSecond(ZoneOffset.of("+8")) <= edate.toEpochSecond(ZoneOffset.of("+8"));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return false;
	}

	/***
	 * 判断字符串是否是yyyy-MM-dd HH:mm:ss格式
	 * @param mes 字符串
	 * @return boolean 是否是日期格式
	 */
	public static boolean isRqSjFormat(String mes){
		String format = "([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"
				+ " ([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]";
		Pattern pattern = Pattern.compile(format);
		Matcher matcher = pattern.matcher(mes);
		if (matcher.matches()) {
			pattern = Pattern.compile("(\\d{4})(\\d{2})(\\d{2}).*");
			matcher = pattern.matcher(mes);
			if (matcher.matches()) {
				int y = Integer.valueOf(matcher.group(1));
				int m = Integer.valueOf(matcher.group(2));
				int d = Integer.valueOf(matcher.group(3));
				if (d > 28) {
					Calendar c = Calendar.getInstance();
					c.set(y, m-1, 1);	//每个月的最大天数
					int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
					return (lastDay >= d);
				}
			}
			return true;
		}
		return false;
	}
	
	/***
	  * 判断字符串是否是yyyy-MM-dd格式
	  * @param mes 字符串
	  * @return boolean 是否是日期格式
	  */
	 public static boolean isRqFormat(String mes){
	  String format = "([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])";
	  Pattern pattern = Pattern.compile(format);
	  Matcher matcher = pattern.matcher(mes);
	  if (matcher.matches()) {
	   pattern = Pattern.compile("(\\d{4})(\\d{2})(\\d{2}).*");
	   matcher = pattern.matcher(mes);
	   if (matcher.matches()) {
	    int y = Integer.valueOf(matcher.group(1));
	    int m = Integer.valueOf(matcher.group(2));
	    int d = Integer.valueOf(matcher.group(3));
	    if (d > 28) {
	     Calendar c = Calendar.getInstance();
	     c.set(y, m-1, 1); //每个月的最大天数
	     int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
	     return (lastDay >= d);
	    }
	   }
	   return true;
	  }
	  return false;
	 }

	/**
	 * 获取当天8点时间
	 *
	 * @return
	 */
	public static Date getTodayTime() {
		Calendar todayEnd = Calendar.getInstance();
		todayEnd.set(Calendar.HOUR_OF_DAY, 8);
		todayEnd.set(Calendar.MINUTE, 0);
		todayEnd.set(Calendar.SECOND, 0);
		todayEnd.set(Calendar.MILLISECOND, 000);
		return todayEnd.getTime();
	}

	/**
	 * 获取昨日8点时间
	 *
	 * @return
	 */
	public static Date getYesterdayTime() {
		Calendar time = Calendar.getInstance();
		time.add(Calendar.DATE, -1);
		time.set(Calendar.HOUR_OF_DAY, 8);
		time.set(Calendar.MINUTE, 0);
		time.set(Calendar.SECOND, 0);
		time.set(Calendar.MILLISECOND, 000);
		return time.getTime();
	}


	public static void main(String[] args) {
		boolean rqSjFormat = DateUtil.isRqSjFormat("2020-02-02 11:30:00");
		System.out.println(rqSjFormat);
	}

}
