/*
 * PROJECT NAME: openplatform
 * CREATED TIME: 15-4-30 下午4:16
 *       AUTHOR: lizhiming
 *    COPYRIGHT: Copyright(c) 2015~2020 All Rights Reserved.
 *
 */
package com.fdage.util;


import lombok.extern.slf4j.Slf4j;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日期工具类
 *
 * @author lizhiming
 */
@Slf4j
public final class DateUtil {

	/**
     * 时间格式
     */
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";

    public static final String YYYY_MM_DD_DATE_FORMAT = "yyyy-MM-dd";

    public static final String YYYYMMDD_DATA_FORMAT = "yyyyMMdd";

    public static final String HHMMSS_DATA_FORMAT = "HHmmss";

    public static final String YYYYMMDDHHMMSSSSS_DATA_FORMAT = "yyyyMMddHHmmssSSS";

    public static final String YYYYMMDDHHMMSS_DATA_FORMAT = "yyyyMMddHHmmss";
    
    public static final String YYMMDDHHMMSS_DATA_FORMAT = "yyMMddHHmmss";
    
    public static final String YYMMDDHHMM_DATA_FORMAT = "yyyyMMddHHmm";
    
	
	/**
	 * 过去的Date对象，TIMESTAMP值可以从1970的某时的开始一直到2037年
	 */
	public static final Date PASSED_DATE = DateUtil.string2Date("2000-01-01 00:00:00",
			DEFAULT_DATE_FORMAT);;
	/**
	 * 永久的Date对象，TIMESTAMP值可以从1970的某时的开始一直到2037年
	 */
	public static final Date FOREVER_DATE = DateUtil.string2Date("9999-12-31 23:59:59",
			DEFAULT_DATE_FORMAT);

	private DateUtil() {
	}

	/**
	 * 把时间转成北京时间的时间戳
	 *
	 * @param input
	 * @return
	 */
	public static long convert2CST(String input) {
		SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		dff.setTimeZone(TimeZone.getTimeZone("GMT+08"));

		long result = -1;
		try {
			Date cstDate = dff.parse(input);
			result = cstDate.getTime();
		} catch (Exception e) {
			log.error("convert2CST meet exception.", e);
		}

		return result;
	}

	/**
	 * 把时间戳转成北京时间的字符串表示
	 *
	 * @param input
	 * @return
	 */
	public static String convert2CST(long input) {
		SimpleDateFormat dff = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		dff.setTimeZone(TimeZone.getTimeZone("GMT+08"));

		try {
			return dff.format(new Date(input));
		} catch (Exception e) {
			log.error("convert2CST meet exception.", e);
		}

		return "";
	}


	/**
	 * 判断两个日期是否是同一天
	 *
	 * @param dateA
	 *            日期1
	 * @param dateB
	 *            日期2
	 * @return true:false
	 */
	public static boolean isSameDay(Date dateA, Date dateB) {
		Calendar calDateA = Calendar.getInstance();
		calDateA.setTime(dateA);

		Calendar calDateB = Calendar.getInstance();
		calDateB.setTime(dateB);

		return calDateA.get(Calendar.YEAR) == calDateB.get(Calendar.YEAR)
				&& calDateA.get(Calendar.MONTH) == calDateB.get(Calendar.MONTH)
				&& calDateA.get(Calendar.DAY_OF_MONTH) == calDateB.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 将Java日期转成以秒为单位，去除毫秒信息
	 * java中Date类中的getTime()是获取时间戳的，java中生成的时间戳精确到毫秒级别，而unix中精确到秒级别，
	 * 所以通过java生成的时间戳需要除以1000
	 *
	 * @param date
	 * @return
	 */
	public static Date truncMesc(Date date) {
		String strDate = DateUtil.date2String(date, DEFAULT_DATE_FORMAT);

		Date result = null;
		try {
			SimpleDateFormat dateFmt = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
			result = dateFmt.parse(strDate);
		} catch (Exception e) {
			log.error("truncMesc meet exception", e);
		}

		return result;
	}

	/**
	 * 判断当前时间是否在指定的有效期内
	 *
	 * @param beginDate
	 *            开始时间
	 * @param endDate
	 *            结束时间
	 * @return true : false
	 */
	public static boolean isInPeriod(Date beginDate, Date endDate) {
		Date now = new Date();

		if (beginDate == null || endDate == null) {
			log.error("isInPeriod meet null argument.");
			throw new IllegalArgumentException("isInPeriod meet null argument.");
		}

		if (beginDate.before(endDate) == false) {
			log.error("isInPeriod meet invalid date argument.");
			throw new IllegalArgumentException("isInPeriod meet invalid date argument.");
		}

		if (now.after(beginDate) && now.before(endDate)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 判断目标时间是否比当前时间早
	 *
	 * @param targetDate
	 *            需比较的时间
	 * @return
	 */
	public static boolean isBeforeNow(Date targetDate) {
		if (targetDate == null) {
			log.error("isBeforeNow meet null argument.");
			throw new IllegalArgumentException("isBeforeNow meet null argument.");
		}

		Date now = new Date();

		return (now.after(targetDate)) ? true : false;
	}

	/**
	 * @param beginDate
	 *            开始时期
	 * @param days
	 *            偏离天数，> 0 往后推算； < 0 往前推算
	 * @return
	 */
	public static Date daysCalculate(Date beginDate, int days) {
		return timesCalculate(beginDate, days, GregorianCalendar.DATE);
	}

	/**
	 * @param beginDate
	 *            开始时期
	 * @return
	 */
	public static Date hoursCalculate(Date beginDate, int hours) {
		return timesCalculate(beginDate, hours, GregorianCalendar.HOUR);
	}

	public static Date timesCalculate(Date beginDate, int times, int type) {
		/*
		 * GregorianCalendar类的add(int field,int amount)方法表示年月日加减.
		 * field参数表示年,月,周,日等. amount参数表示要加减的数量.
		 */
		GregorianCalendar gc = new GregorianCalendar();
		gc.setTime(beginDate);
		gc.add(type, times);
		return gc.getTime();
	}

	/**
	 * 将日期对象按照格式转成字符串
	 *
	 * @param date
	 *            日期对象
	 * @param format
	 *            日期格式
	 * @return 字符串
	 */
	public static String date2String(Date date, String format) {
		if (date == null) {
			log.error("date2String meet null argument.");
			throw new IllegalArgumentException("argument is null.");
		}

		if (format == null) {
			format = DEFAULT_DATE_FORMAT;
		}

		String result = null;
		try {
			DateFormat fmt = new SimpleDateFormat(format);
			result = fmt.format(date);
		} catch (Exception e) {
			log.error("date2String meet exception. " + e.getLocalizedMessage());
		}
		return result;
	}

	/**
	 * 将字符串转成日期对象
	 *
	 * @param date
	 *            日期字符串
	 * @param format
	 *            日期格式
	 * @return 日期对象
	 */
	public static Date string2Date(String date, String format) {
		if (date == null) {
			log.error("string2Date meet null argument.");
			throw new IllegalArgumentException("argument is null.");
		}

		if (format == null) {
			format = DEFAULT_DATE_FORMAT;
		}

		Date result = null;
		try {
			DateFormat fmt = new SimpleDateFormat(format);
			result = fmt.parse(date);
		} catch (Exception e) {
			log.error("string2Date meet exception. " + e.getLocalizedMessage());
		}

		return result;
	}

	/**
	 * java时间戳转换到php时间戳
	 *
	 * @param time
	 * @return
	 */
	public static long javaTimestamp(long time) {
		if (time <= 0) {
			log.error("javaTimestamp meet null argument.");
			throw new IllegalArgumentException("argument is null.");
		}
		// mysql 时间戳只有10位，只精确到秒，而Java时间戳精确到毫秒，故要做处理
		String dateline = String.valueOf(time);
		dateline = dateline.substring(0, 10);
		return Long.parseLong(dateline);
	}

	public static long javaTimestamp(Date now) {
		return javaTimestamp(now.getTime());
	}

	/**
	 * 计算两个日期之间相差的天数
	 *
	 * @param smdate
	 *            较小的时间
	 * @param bdate
	 *            较大的时间
	 * @return 相差天数
	 * @throws ParseException
	 */
	public static int daysBetween(Date smdate, Date bdate) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			smdate = sdf.parse(sdf.format(smdate));
			bdate = sdf.parse(sdf.format(bdate));
		} catch (ParseException e) {
			log.error("ParseException:", e);
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(smdate);
		long time1 = cal.getTimeInMillis();
		cal.setTime(bdate);
		long time2 = cal.getTimeInMillis();
		long between_days = (time2 - time1) / (1000 * 3600 * 24);

		return Integer.parseInt(String.valueOf(between_days));
	}

	/**
	 * 把日期推后一天
	 * @return 相差天数
	 * @throws ParseException
	 */
	public static Date dayDelay(String dateTime) {
		Date date = string2Date(dateTime, "yyyy-MM-dd");
		Calendar calendar = new GregorianCalendar();
		calendar.setTime(date);
		calendar.add(calendar.DATE, 1);// 把日期往后增加一天.整数往后推,负数往前移动
		date = calendar.getTime(); // 这个时间就是日期往后推一天的结果

		return date;
	}

	/**
	 * 获取某年某月的最后一天日期
	 */
	public static Date getLastDayOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
		cal.set(Calendar.DAY_OF_MONTH, lastDay);
		return cal.getTime();
	}

	/**
	 * 获取某年某月的第一天 日期
	 */
	public static Date getFisrtDayOfMonth(int year, int month) {
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
		cal.set(Calendar.DAY_OF_MONTH, firstDay);
		return cal.getTime();
	}

	/**
	 * 根据开始时间和结束时间返回时间段内的时间集合
	 *
	 * @param beginDate
	 * @param endDate
	 * int calendarType 差距的时间 如获取间隔为一天 输入Calendar.DAY_OF_MONTH
	 * @return List
	 */
	public static List<Date> getDatesBetweenTwoDate(Date beginDate, Date endDate,int calendarType) {
		List<Date> lDate = new ArrayList<Date>();
		lDate.add(beginDate);// 把开始时间加入集合
		Calendar cal = Calendar.getInstance();
		// 使用给定的 Date 设置此 Calendar 的时间
		cal.setTime(beginDate);
		boolean bContinue = true;
		while (bContinue) {
			// 根据日历的规则，为给定的日历字段添加或减去指定的时间量
			cal.add(calendarType, 1);
			// 测试此日期是否在指定日期之后
			if (endDate.after(cal.getTime())) {
				lDate.add(cal.getTime());
			} else {
				break;
			}
		}
		lDate.add(endDate);// 把结束时间加入集合
		return lDate;
	}
}
