package com.ym.mec.util.date;

import org.apache.commons.lang3.StringUtils;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.*;

/**
 * 与日期、时间操作有关的工具类。
 * <p>
 * <strong>注意：某些方法会将输入时间转换成格林威治时间，时区默认为东八区。可以通过方法 <code>DateUtil#setTimeZone</code>改变默认时区。 </strong>
 * </p>
 */
public class DateUtil {

	private static final String CHINESE_DATA_FORMAT = "yyyy年MM月dd日 HH:mm:ss";

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

	public static final String DATE_FORMAT_MIN = "yyyy年MM月dd日";

	/**
	 * 默认使用的Locale。默认Locale为 US
	 */
	public static final Locale DEFAULT_LOCALE = Locale.US;
	// ~ 静态属性及初始化 /////////////////////////////////////////////

	/** 默认的时区，一般是使用东八区。即比标准的格林威治时间快8个小时。 */
	public static TimeZone TIME_ZONE = TimeZone.getDefault();

	/**
	 * ISO8601基本日期格式 yyyyMMdd ，如：20021225 代表2002年12月25日。
	 */
	public static final String ISO_DATE_FORMAT = "yyyyMMdd";

	/**
	 * ISO8601扩展日期格式 yyyy-MM-dd ，如：2002-12-25 代表2002年12月25日。
	 */
	public static final String ISO_EXPANDED_DATE_FORMAT = "yyyy-MM-dd";

	/**
	 * ISO8601扩展日期格式 yyyy-MM-dd ，如：2002-12-25 代表2002年12月25日。
	 */
	public static final String ISO_YEAR_MONTH_FORMAT = "yyyy-MM";

	/**
	 * ISO8601基本时间格式 HHmmssSSSzzz ，如：143212333-0500 代表西5区，14点32分12秒333毫秒 24小时制
	 */
	public static final String ISO_TIME_FORMAT = "HHmmssSSSzzz";

	/**
	 * ISO8601基本时间格式 HH:mm:ss,SSSzzz ，如：14:32:12,333-0500 代表西5区，14点32分12秒333毫秒 24小时制
	 */
	public static final String ISO_EXPANDED_TIME_FORMAT = "HH:mm:ss,SSSzzz";

	/**
	 * ISO8601基本日期格式 yyyyMMddTHHmmssSSSzzz ，如：20021225T143212333-0500 代表西5区 2002年12月25日 14点32分12秒333毫秒
	 */
	public static final String ISO_DATE_TIME_FORMAT = "yyyyMMdd'T'HHmmssSSSzzz";

	/**
	 * ISO8601基本日期格式 yyyy-MM-ddTHH:mm:ss,SSSzzz ，如：2002-12-25T14:32:12,333-0500 代表西5区 2002年12月25日 14点32分12秒333毫秒
	 */
	public static final String ISO_EXPANDED_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss,SSSzzz";

	/**
	 * 基本时间格式 HHmmss ，如：143212 代表14点32分12秒 24小时制
	 */
	public static final String TIME_FORMAT = "HHmmss";

	/**
	 * 基本时间格式 HH:mm:ss ，如：14:32:12 代表14点32分12秒 24小时制
	 */
	public static final String EXPANDED_TIME_FORMAT = "HH:mm:ss";

	/**
	 * 日期格式 yyyyMMdd HHmmss ，如：20021225 143212 代表 2002年12月25日 14点32分12秒
	 */
	public static final String DATE_TIME_FORMAT = "yyyyMMdd HHmmss";

	/**
	 * 日期格式 yyyy-MM-dd HH:mm:ss ，如：2002-12-25 14:32:12 代表 2002年12月25日 14点32分12秒
	 */
	public static final String EXPANDED_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

	/**
	 * 西方国家的日期格式 MMM dd, yyyy ，如：February 3, 1982 代表1982年2月3日
	 */
	public static final String ENGLISH_DATE = "MMM dd, yyyy";

	/**
	 * 西方国家的时间格式 MMM dd, yyyy H:mm:ss.SSS ，如：February 3, 1982 12:12:12.005 代表1982年2月3日 12点12分12秒5毫秒
	 */
	public static final String ENGLISH_DATE_TIME = "MMM dd, yyyy H:mm:ss.SSS";

	/**
	 * 美国日期格式 yyyy.MM.dd G 'at' HH:mm:ss z ，如：2001.07.04 AD at 12:08:56 PDT 代表2001年7月4日 12点8分56秒
	 */
	public static final String US_DATE_TIME_1 = "yyyy.MM.dd G 'at' HH:mm:ss z";

	/**
	 * 美国日期格式 yyyyy.MMMMM.dd GGG hh:mm aaa ，如：02001.July.04 AD 12:08 PM 代表2001年7月4日 12点8分
	 */
	public static final String US_DATE_TIME_2 = "yyyyy.MMMMM.dd GGG hh:mm aaa";

	/**
	 * 美国日期格式 EEE, d MMM yyyy HH:mm:ss Z ，如：Wed, 4 Jul 2001 12:08:56 -0700 代表2001年7月4日 12点8分56秒 星期三
	 */
	public static final String US_DATE_TIME_3 = "EEE, d MMM yyyy HH:mm:ss Z";

	// 第1年1月1日 (格里高利历)
	public static final int JAN_1_1_JULIAN_DAY = 1721426;

	// 1970年1月1日 (格里高利历)
	public static final int EPOCH_JULIAN_DAY = 2440588;

	public static final int EPOCH_YEAR = 1970;

	// 一周、一天、一小时、一分钟、一秒，换算成毫秒的全局变量。
	public static final int ONE_SECOND = 1000;

	public static final int ONE_MINUTE = 60 * ONE_SECOND;

	public static final int ONE_HOUR = 60 * ONE_MINUTE;

	public static final long ONE_DAY = 24 * ONE_HOUR;

	public static final long ONE_WEEK = 7 * ONE_DAY;

	public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
	public static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
	public static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
	public static final WeekFields weekFields = WeekFields.of(DayOfWeek.MONDAY, 1);
	public static final ZoneId zoneId = ZoneId.systemDefault();

	public static Map<Object,Integer> normalWeekNumCalendarWeekNumMap=new HashMap<>();
	public static Map<Object,Integer> calendarWeekNumNormalWeekNumMap=new HashMap<>();
	public static Map<Integer,String> weekNumNormalWeekNameMap=new HashMap<>();

	static {
		normalWeekNumCalendarWeekNumMap.put(1,Calendar.MONDAY);
		normalWeekNumCalendarWeekNumMap.put(2,Calendar.TUESDAY);
		normalWeekNumCalendarWeekNumMap.put(3,Calendar.WEDNESDAY);
		normalWeekNumCalendarWeekNumMap.put(4,Calendar.THURSDAY);
		normalWeekNumCalendarWeekNumMap.put(5,Calendar.FRIDAY);
		normalWeekNumCalendarWeekNumMap.put(6,Calendar.SATURDAY);
		normalWeekNumCalendarWeekNumMap.put(7,Calendar.SUNDAY);

		normalWeekNumCalendarWeekNumMap.put("一",Calendar.MONDAY);
		normalWeekNumCalendarWeekNumMap.put("二",Calendar.TUESDAY);
		normalWeekNumCalendarWeekNumMap.put("三",Calendar.WEDNESDAY);
		normalWeekNumCalendarWeekNumMap.put("四",Calendar.THURSDAY);
		normalWeekNumCalendarWeekNumMap.put("五",Calendar.FRIDAY);
		normalWeekNumCalendarWeekNumMap.put("六",Calendar.SATURDAY);
		normalWeekNumCalendarWeekNumMap.put("七",Calendar.SUNDAY);

		normalWeekNumCalendarWeekNumMap.put("周一",Calendar.MONDAY);
		normalWeekNumCalendarWeekNumMap.put("周二",Calendar.TUESDAY);
		normalWeekNumCalendarWeekNumMap.put("周三",Calendar.WEDNESDAY);
		normalWeekNumCalendarWeekNumMap.put("周四",Calendar.THURSDAY);
		normalWeekNumCalendarWeekNumMap.put("周五",Calendar.FRIDAY);
		normalWeekNumCalendarWeekNumMap.put("周六",Calendar.SATURDAY);
		normalWeekNumCalendarWeekNumMap.put("周七",Calendar.SUNDAY);

		normalWeekNumCalendarWeekNumMap.put("星期一",Calendar.MONDAY);
		normalWeekNumCalendarWeekNumMap.put("星期二",Calendar.TUESDAY);
		normalWeekNumCalendarWeekNumMap.put("星期三",Calendar.WEDNESDAY);
		normalWeekNumCalendarWeekNumMap.put("星期四",Calendar.THURSDAY);
		normalWeekNumCalendarWeekNumMap.put("星期五",Calendar.FRIDAY);
		normalWeekNumCalendarWeekNumMap.put("星期六",Calendar.SATURDAY);
		normalWeekNumCalendarWeekNumMap.put("星期七",Calendar.SUNDAY);

		calendarWeekNumNormalWeekNumMap.put(Calendar.MONDAY,1);
		calendarWeekNumNormalWeekNumMap.put(Calendar.TUESDAY,2);
		calendarWeekNumNormalWeekNumMap.put(Calendar.WEDNESDAY,3);
		calendarWeekNumNormalWeekNumMap.put(Calendar.THURSDAY,4);
		calendarWeekNumNormalWeekNumMap.put(Calendar.FRIDAY,5);
		calendarWeekNumNormalWeekNumMap.put(Calendar.SATURDAY,6);
		calendarWeekNumNormalWeekNumMap.put(Calendar.SUNDAY,7);

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

	// ~ 方法 ////////////////////////////////////////////////////////////////

	/**
	 * 设置系统默认的<code>java.util.TimeZone</code>
	 * 
	 * @param timeZone <code>java.util.TimeZone</code>
	 */
	public static void setTimeZone(TimeZone timeZone) {
		TIME_ZONE = timeZone;
	}

	public static Date toDateTime(String isoDateString) {
		return stringToDate(isoDateString, EXPANDED_DATE_TIME_FORMAT);
	}

	public static Date toDate(String isoDateString) {
		return stringToDate(isoDateString, ISO_EXPANDED_DATE_FORMAT);
	}

	public static Date stringToDate(String isoDateString) {
		return stringToDate(isoDateString, EXPANDED_DATE_TIME_FORMAT);
	}

	public static Date stringToDate(String isoDateString, String pattern) {
		if (StringUtils.isBlank(pattern)) {
			return null;
			// throw new IllegalArgumentException("匹配模式不能为空！");
		}

		return stringToDate(isoDateString, new SimpleDateFormat(pattern));
	}

	public static Date stringToDate(String isoDateString, SimpleDateFormat simpleDateFormat) {
		if (StringUtils.isBlank(isoDateString)) {
			// throw new IllegalArgumentException("日期字符串不能为空！");
			return null;
		}
		try {
			return simpleDateFormat.parse(isoDateString);
		} catch (ParseException e) {
			// throw new RuntimeException(e);
		}
		return null;
	}

	public static String getDateTime(Date date) {
		return format(date, EXPANDED_DATE_TIME_FORMAT);
	}

	public static String getDate(Date date) {
		return format(date, ISO_EXPANDED_DATE_FORMAT);
	}

	public static String getDATEFORMAT(Date date) {
		return format(date, ISO_DATE_FORMAT);
	}

	public static String format(Date date, String pattern) {
		return format(date, new SimpleDateFormat(pattern));
	}

	/**
	 * 将<code>java.util.Date</code>按照给定的模式转换成日期字符串。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param formatter 给定的模式
	 * @return 转换后的日期字符串
	 */
	public static String getDate(Date date, SimpleDateFormat formatter) {
		if (date == null || formatter == null) {
			return null;
			// throw new RuntimeException("日期和模式不能为空！");
		}
		formatter.setTimeZone(TIME_ZONE);
		return formatter.format(date);
	}

	/**
	 * 将<code>java.util.Date</code>按照给定的模式转换成日期字符串。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param formatter 给定的模式
	 * @return 转换后的日期字符串
	 */
	public static String format(Date date, SimpleDateFormat formatter) {
		return getDate(date, formatter);
	}

	// 获取年份
	public static String getYear(Date date) {
		return format(date, ISO_EXPANDED_DATE_FORMAT).split("-")[0];
	}

	// 获取月份
	public static String getMonth(Date date) {
		return format(date, ISO_EXPANDED_DATE_FORMAT).split("-")[1];
	}

	// 获取日期
	public static String getDay(Date date) {
		return format(date, ISO_EXPANDED_DATE_FORMAT).split("-")[2];
	}

	// 获取时分秒
	public static String getTime(Date date) {
		return format(date, EXPANDED_DATE_TIME_FORMAT).split(" ")[1];
	}

	/**
	 * 确定给定的年份是否为闰年。
	 * 
	 * <pre>
	 * </pre>
	 * 
	 * @param date <code>java.util.Date</code>
	 * @return True 如果是闰年
	 */
	public static boolean isLeapYear(Date date) {
		if (date == null) {
			throw new RuntimeException("输入日期不能为空！");
		}
		GregorianCalendar cal = new GregorianCalendar();
		cal.setTime(date);

		return cal.isLeapYear(cal.get(Calendar.YEAR));
	}

	public static int getHour(Date date) {
		if (date == null) {
			return -1;
		}

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	public static int geMinute(Date date) {
		if (date == null) {
			return -1;
		}

		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.MINUTE);
	}

	/**
	 * 根据日历的规则，为给定的日历字段添加或减去指定的时间量。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param field 给定的日历字段
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date add(Date date, int field, int amount) {
		if (date == null) {
			throw new RuntimeException("日期不能为空！");
		}
		Calendar cal = GregorianCalendar.getInstance(TIME_ZONE);
		cal.setTime(date);
		cal.add(field, amount);

		return cal.getTime();
	}

	/**
	 * 增加或减少指定数量的年份。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addYears(Date date, int amount) {
		return add(date, Calendar.YEAR, amount);
	}

	/**
	 * 增加或减少指定数量的月份。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addMonths(Date date, int amount) {
		return add(date, Calendar.MONTH, amount);
	}

	/**
	 * 修改周，时间按周的量增加或减少。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addWeeks(Date date, int amount) {
		return add(date, Calendar.WEEK_OF_YEAR, amount);
	}

	/**
	 * 增加或减少指定数量的日数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addDays(Date date, int amount) {
		return add(date, Calendar.DAY_OF_MONTH, amount);
	}

	/**
	 * 增加或减少指定数量的小时数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addHours(Date date, int amount) {
		return add(date, Calendar.HOUR_OF_DAY, amount);
	}

	/**
	 * 增加或减少指定数量的分钟数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addMinutes(Date date, int amount) {
		return add(date, Calendar.MINUTE, amount);
	}

	/**
	 * 增加或减少指定数量的秒钟数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addSeconds(Date date, int amount) {
		return add(date, Calendar.SECOND, amount);
	}

	/**
	 * 增加或减少指定数量的毫秒数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date addMilliseconds(Date date, int amount) {
		return add(date, Calendar.MILLISECOND, amount);
	}

	/**
	 * 在给定的日历字段上添加或减去（上/下）单个时间单元，不更改更大的字段。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param field 给定的日历字段
	 * @param up 添加或减去（上/下）
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date roll(Date date, int field, boolean up) {
		Calendar cal = GregorianCalendar.getInstance(TIME_ZONE);
		cal.setTime(date);
		cal.roll(field, up);

		return cal.getTime();
	}

	/**
	 * 向指定日历字段添加指定（有符号的）时间量，不更改更大的字段。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param field 给定的日历字段
	 * @param amount 数量
	 * @return 运算后的 <code>java.util.Date</code>
	 */
	public static Date roll(Date date, int field, int amount) {
		Calendar cal = GregorianCalendar.getInstance(TIME_ZONE);
		cal.setTime(date);
		cal.roll(field, amount);

		return cal.getTime();
	}

	/**
	 * 将毫秒时间戳转换成格里高利历的日数。日数是只从格里高利历第1年1月1日算起的日数。
	 * 
	 * @param millis 给定的毫秒时间戳
	 * @return 格里高利历的日数
	 */
	public static int millisToJulianDay(long millis) {
		return EPOCH_JULIAN_DAY - JAN_1_1_JULIAN_DAY + (int) (millis / ONE_DAY);
	}

	/**
	 * 将<code>java.util.Date</code>转换成格里高利历的日数。 日数是只从格里高利历第1年1月1日算起的日数。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @return 格里高利历的日数
	 */
	public static int dateToJulianDay(Date date) {
		return millisToJulianDay(date.getTime());
	}

	/**
	 * 计算两个日期之间相差的秒钟数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的秒钟数
	 */
	public static int secondsBetween(Date early, Date late) {
		return (int) ((late.getTime() / ONE_SECOND) - (early.getTime() / ONE_SECOND));
	}

	/**
	 * 计算两个日期之间相差的分钟数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的分钟数
	 */
	public static int minutesBetween(Date early, Date late) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(early);
		c2.setTime(late);

		return (int) ((late.getTime() / ONE_MINUTE) - (early.getTime() / ONE_MINUTE));
	}

	/**
	 * 计算两个日期之间相差的小时数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的小时数
	 */
	public static int hoursBetween(Date early, Date late) {
		return (int) ((late.getTime() / ONE_HOUR) - (early.getTime() / ONE_HOUR));
	}

	/**
	 * 计算两个日期之间相差的天数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的天数
	 */
	public static int daysBetween(Date early, Date late) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(early);
		c2.setTime(late);
		return dateToJulianDay(c2.getTime()) - dateToJulianDay(c1.getTime());
	}

	/**
	 * 计算两个日期之间相差的月数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的月数
	 */
	public static int monthsBetween(Date early, Date late) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(early);
		c2.setTime(late);
		return ((c2.get(Calendar.YEAR) * 12) + c2.get(Calendar.MONTH)) - ((c1.get(Calendar.YEAR) * 12) + c1.get(Calendar.MONTH));
	}

	/**
	 * 计算两个日期之间相差的年数。如果第一个日期在第二个日期之前，则返回正，反之返回负。
	 * 
	 * @param early 第一个日期
	 * @param late 第二个日期
	 * @return 两个日期之间相差的年数
	 */
	public static int yearsBetween(Date early, Date late) {
		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();
		c1.setTime(early);
		c2.setTime(late);
		return c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
	}

	/**
	 * 将格里高利历日数转换成 <code>java.sql.Date</code>
	 * 
	 * @param julian 格里高利历日数
	 * @return <code>java.sql.Date</code>
	 */
	public static java.sql.Date julianDayToSqlDate(long julian) {
		return new java.sql.Date(julianDayToMillis(julian));
	}

	/**
	 * 将格里高利历日数转换成 <code>java.util.Date</code>
	 * 
	 * @param julian 格里高利历日数
	 * @return <code>java.util.Date</code>
	 */
	public static Date julianDayToDate(long julian) {
		return new Date(julianDayToMillis(julian));
	}

	/**
	 * 将格里高利历日数转换成毫秒时间戳。
	 * 
	 * @param julian 格里高利历日数
	 * @return 毫秒时间戳
	 */
	public static long julianDayToMillis(long julian) {
		return (julian - EPOCH_JULIAN_DAY + JAN_1_1_JULIAN_DAY) * ONE_DAY;
	}

	/**
	 * 将日历转换成儒略历日期。算法参见： <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
	 * (Gregorian Calendar)</a>, 由 Bill Jeffrys 提供。
	 * 
	 * @param c 日历实例
	 * @return 儒略历日期
	 */
	public static float toJulian(Calendar c) {
		int Y = c.get(Calendar.YEAR);
		int M = c.get(Calendar.MONTH);
		int D = c.get(Calendar.DATE);
		int A = Y / 100;
		int B = A / 4;
		int C = 2 - A + B;
		float E = (int) (365.25f * (Y + 4716));
		float F = (int) (30.6001f * (M + 1));
		float JD = (C + D + E + F) - 1524.5f;

		return JD;
	}

	/**
	 * 将日期转换成儒略历日期。算法参见： <a href="http://quasar.as.utexas.edu/BillInfo/JulianDatesG.html">Julian Day Calculations
	 * (Gregorian Calendar)</a>, 由 Bill Jeffrys 提供。
	 * 
	 * @param date 日期
	 * @return 儒略历日期
	 */
	public static float toJulian(Date date) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);

		return toJulian(c);
	}

	protected static float normalizedJulian(float JD) {
		float f = Math.round(JD + 0.5f) - 0.5f;

		return f;
	}

	/**
	 * 给定此 <code>java.util.Date</code> 的时间值，返回指定日历字段可能拥有的最大值。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param field 日历字段
	 * @return 对于此 <code>java.util.Date</code> 的时间值而言，给定日历字段的最大值
	 */
	public static Date getActualMaximum(Date date, int field) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(field, c.getActualMaximum(field));

		return c.getTime();
	}

	/**
	 * 给定此 <code>java.util.Date</code> 的时间值，返回指定日历字段可能拥有的最小值。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @param field 日历字段
	 * @return 对于此 <code>java.util.Date</code> 的时间值而言，给定日历字段的最小值
	 */
	public static Date getActualMinimum(Date date, int field) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(field, c.getActualMinimum(field));

		return c.getTime();
	}

	/**
	 * 截取日期，只保留年、月、日部分。
	 * 
	 * @param date <code>java.util.Date</code>
	 * @return 截取后的<code>java.util.Date</code>
	 */
	public static Date trunc(Date date) {
		if (date != null) {
			Calendar c1 = Calendar.getInstance();
			c1.setTime(date);
			Calendar c2 = (Calendar) c1.clone();
			c1.clear();
			c1.set(Calendar.YEAR, c2.get(Calendar.YEAR));
			c1.set(Calendar.MONTH, c2.get(Calendar.MONTH));
			c1.set(Calendar.DAY_OF_MONTH, c2.get(Calendar.DAY_OF_MONTH));
			return c1.getTime();
		}
		return null;
	}

	/**
	 * 返回当天的最后一秒
	 * 
	 * @param date <code>java.util.Date</code>
	 * @return 截取后的<code>java.util.Date</code>
	 */
	public static Date dayEnd(Date date) {
		Calendar c1 = Calendar.getInstance();
		c1.setTime(date);
		Calendar c2 = (Calendar) c1.clone();
		c1.clear();
		c1.set(Calendar.YEAR, c2.get(Calendar.YEAR));
		c1.set(Calendar.MONTH, c2.get(Calendar.MONTH));
		c1.set(Calendar.DAY_OF_MONTH, c2.get(Calendar.DAY_OF_MONTH));
		// 23:59:59
		c1.set(Calendar.HOUR_OF_DAY, 23);
		c1.set(Calendar.MINUTE, 59);
		c1.set(Calendar.SECOND, 59);
		return c1.getTime();
	}

	/**
	 * 判断两个日期是否是同一天，精确到天。
	 * 
	 * @param date1 <code>java.util.Date</code>
	 * @param date2 <code>java.util.Date</code>
	 * @return true 如果两个日期是同一天
	 */
	public static boolean isSameDay(Date date1, Date date2) {
		if (date1 == null || date2 == null) {
			throw new RuntimeException("日期不能为空！");
		}
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date1);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(date2);
		return isSameDay(cal1, cal2);
	}

	/**
	 * 判断两个日期是否是同一天，精确到天。
	 * 
	 * @param cal1 <code>java.util.Calendar</code>
	 * @param cal2 <code>java.util.Calendar</code>
	 * @return true 如果两个日期是同一天
	 */
	public static boolean isSameDay(Calendar cal1, Calendar cal2) {
		if (cal1 == null || cal2 == null) {
			throw new RuntimeException("日期不能为空！");
		}
		return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2
				.get(Calendar.DAY_OF_YEAR));
	}

	/**
	 * 判断两个时间是否完全相等，精确到毫秒。
	 * 
	 * @param date1 <code>java.util.Date</code>
	 * @param date2 <code>java.util.Date</code>
	 * @return true 如果两个时间完全相等
	 */
	public static boolean isSameLocalTime(Date date1, Date date2) {
		if (date1 == null || date2 == null) {
			throw new RuntimeException("日期不能为空！");
		}
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(date1);
		Calendar cal2 = Calendar.getInstance();
		cal2.setTime(date2);
		return isSameLocalTime(cal1, cal2);
	}

	/**
	 * 判断两个时间是否完全相等，精确到毫秒。
	 * 
	 * @param cal1 <code>java.util.Calendar</code>
	 * @param cal2 <code>java.util.Calendar</code>
	 * @return true 如果两个时间完全相等
	 */
	public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) {
		if (cal1 == null || cal2 == null) {
			throw new RuntimeException("日期不能为空！");
		}
		return (cal1.get(Calendar.MILLISECOND) == cal2.get(Calendar.MILLISECOND) && cal1.get(Calendar.SECOND) == cal2.get(Calendar.SECOND)
				&& cal1.get(Calendar.MINUTE) == cal2.get(Calendar.MINUTE) && cal1.get(Calendar.HOUR) == cal2.get(Calendar.HOUR)
				&& cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)
				&& cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.getClass() == cal2.getClass());
	}

	public static String formatHuman(Date date) {
		if (date != null) {
			Long seconds = (System.currentTimeMillis() - date.getTime()) / 1000;

			if (seconds <= 0) {
				return "刚刚";
			}

			if (seconds < 60) {
				return seconds + "秒前";
			}

			Long min = seconds / 60;
			if (min < 60) {
				return min + "分钟前";
			}

			Long hour = seconds / 3600;
			if (hour < 12) {
				return hour + "小时前";
			}

			return format(date, "yyyy-MM-dd HH:mm:ss");
		} else {
			return "";
		}

	}

	public static String formatHumanShort(Date date) {

		Long seconds = (System.currentTimeMillis() - date.getTime()) / 1000;

		if (seconds <= 0) {
			return "刚刚";
		}

		if (seconds < 60) {
			return seconds + "秒前";
		}

		Long min = seconds / 60;
		if (min < 60) {
			return min + "分钟前";
		}

		Long hour = seconds / 3600;
		if (hour < 12) {
			return hour + "小时前";
		}

		return format(date, "yyyy-MM-dd");
	}

	/**
	 * 解析毫秒时间格式
	 * 
	 * @param millis
	 * @return
	 */
	public static Date parseMillis(Long millis) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(millis);
		return calendar.getTime();
	}

	/**
	 * 返回date所在月的第一天
	 * 
	 * @return
	 */
	public static Date getFirstDayOfMonth(Date date) {
		String str = DateUtil.getYear(date) + "-" + DateUtil.getMonth(date) + "-01";
		return DateUtil.stringToDate(str, DateUtil.ISO_EXPANDED_DATE_FORMAT);
	}

	/**
	 * 返回date所在月的最后一天
	 *
	 * @return
	 */
	public static Date getLastDayOfMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		return calendar.getTime();
	}

	// 取最近的时间
	public static Date getMaxDate(Date lastDate, Date newDate) {
		if (lastDate != null && newDate != null) {
			if (newDate.after(lastDate)) {
				return newDate;
			} else {
				return lastDate;
			}
		} else if (lastDate != null) {
			return lastDate;
		} else {
			return newDate;
		}
	}

	// 取最老的时间
	public static Date getMinDate(Date lastDate, Date newDate) {
		if (lastDate != null && newDate != null) {
			if (newDate.before(lastDate)) {
				return newDate;
			} else {
				return lastDate;
			}
		} else if (lastDate != null) {
			return lastDate;
		} else {
			return newDate;
		}
	}

	/**
	 * 将字符串转换为指定格式的日期
	 * 
	 * @param dateStr
	 * @param pattern
	 * @return
	 */
	public static Date strToDate(String dateStr, String pattern) {
		Date date = null;
		try {
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern, DEFAULT_LOCALE);
			date = simpleDateFormat.parse(dateStr);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date; // null if parse faile
	}

	/**
	 * 时间转字符串
	 * @param date
	 * @return
	 */
	public static String dateToString(Date date) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		return df.format(date);
	}

	/**
	 * 时间转字符串
	 * @param date
	 * @return
	 */
	public static String dateToString(Date date, SimpleDateFormat df) {
		return df.format(date);
	}

	/**
	 * 时间转字符串
	 * @param date
	 * @return
	 */
	public static String dateToString(Date date, String format) {
		SimpleDateFormat df = new SimpleDateFormat(format);
		return df.format(date);
	}

	/**
	 * @describe 获取时间段内对应星期数的集合
	 * @author Joburgess
	 * @date 2019/10/25
	 * @param startTime 开始时间
	 * @param endTime 结束时间
	 * @param weekNum 周几
	 * @return java.util.List<java.util.Date>
	 */
	public static List<Date> getWeekDays(Date startTime, Date endTime, int weekNum) {
		Calendar calendar = Calendar.getInstance();
		List<Date> dates = new ArrayList<>();
		for (Date x = startTime; x.compareTo(endTime) <= 0;) {
			calendar.setTime(x);
			calendar.add(Calendar.DATE, 1);
			x = calendar.getTime();
			if (calendar.get(Calendar.DAY_OF_WEEK) == weekNum) {
				dates.add(x);
			}
		}
		return dates;
	}

	/**
	 * @describe 获取指定时间再当天最后一秒的时间
	 * @author Joburgess
	 * @date 2020/1/16
	 * @param date: 时间
	 * @return java.util.Date
	 */
	public static Date getLastSecondWithDay(Date date){
		Calendar calendar=Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY,23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		return calendar.getTime();
	}

	/**
	 * @describe 获取指定时间在当天最后的时间
	 * @author Joburgess
	 * @date 2020/1/16
	 * @param date: 时间
	 * @return java.util.Date
	 */
	public static Date getLastTimeWithDay(Date date){
		Calendar calendar=Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY,23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		calendar.set(Calendar.MILLISECOND,999);
		return calendar.getTime();
	}

	/**
	 * @describe 根据日期获取所在周的周一
	 * @author Joburgess
	 * @date 2019/10/25
	 * @param date: 日期
	 * @return java.util.Date
	 */
	public static Date getWeekMondayWithDate(Date date) {
		Calendar cal = Calendar.getInstance();
		try {
			date = new SimpleDateFormat(DEFAULT_PATTERN).parse(new SimpleDateFormat(DEFAULT_PATTERN).format(date));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		cal.setTime(date);
		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();
	}

	/**
	 * @describe 根据指定日期获取所在周的指定星期数的日期
	 * @author Joburgess
	 * @date 2020/2/6
	 * @param date: 日期
	 * @param weekNum: 星期几
	 * @return java.util.Date
	 */
	public static Date getWeekDayWithDate(Date date,int weekNum){
		Calendar cal = Calendar.getInstance();
		cal.setFirstDayOfWeek(Calendar.MONDAY);
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_WEEK,weekNum);
		return cal.getTime();
	}

	/**
	 * @describe 根据日期获取所在周获取下周一的时间
	 * @author Joburgess
	 * @date 2019/10/25
	 * @param date:
	 * @return java.util.Date
	 */
	public static Date getNextWeekMonday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(getWeekMondayWithDate(date));
		cal.add(Calendar.DATE, 7);
		return cal.getTime();
	}

	/**
	 * @describe 根据日期获取所在周获取下周日的时间
	 * @author Joburgess
	 * @date 2019/10/25
	 * @param date:
	 * @return java.util.Date
	 */
	public static Date getNextWeekSunday(Date date) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(getWeekMondayWithDate(date));
		cal.add(Calendar.DATE, 13);
		return cal.getTime();
	}

	/**
	 * @describe 根据日期获取下周几的时间
	 * @author Joburgess
	 * @date 2019/10/25
	 * @param date:
	 * @return java.util.Date
	 */
	public static Date getNextWeekDay(Date date,int intervalDays) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(getWeekMondayWithDate(date));
		cal.add(Calendar.DATE, intervalDays);
		return cal.getTime();
	}

	/**
	 * @describe 在指定时间上加上指定天数，忽略时分秒
	 * @author Joburgess
	 * @date 2019/10/30
	 * @param date: 日期
	 * @param days: 天数
	 * @return java.util.Date
	 */
	public static Date addDays1(Date date, int days) {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DATE, days);
		try {
			return new SimpleDateFormat(DateUtil.DEFAULT_PATTERN).parse(new SimpleDateFormat(DateUtil.DEFAULT_PATTERN).format(cal.getTime()));
		} catch (ParseException e) {
			return cal.getTime();
		}
	}

	/**
	 * 时间转换为中文格式
	 * @param date
	 * @return
	 */
	public static String date2ChineseDate(Date date) {
		return new SimpleDateFormat(CHINESE_DATA_FORMAT).format(date);
	}

	/**
	 * @describe 判断多个时间区段是否存在重叠
	 * @author Joburgess
	 * @date 2019/10/27
	 * @param dateZones:
	 * @return boolean
	 */
	public static boolean checkDateZoneOverlap(List<DateZone> dateZones) {
		dateZones.sort(Comparator.comparing(DateZone::getStartTime));
		if (dateZones.size() <= 1) {
			return false;
		} else {
			for (int i = 0; i < dateZones.size() - 1; i++) {
				if (dateZones.get(i + 1).getStartTime().before(dateZones.get(i).getEndTime())) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @describe 时间区段辅助类
	 * @author Joburgess
	 * @date 2019/10/27
	 * @return
	 */
	public static class DateZone {
		private Date startTime;
		private Date endTime;

		public DateZone() {
		}

		public DateZone(Date startTime, Date endTime) {
			this.startTime = startTime;
			this.endTime = endTime;
		}

		public Date getStartTime() {
			return startTime;
		}

		public void setStartTime(Date startTime) {
			this.startTime = startTime;
		}

		public Date getEndTime() {
			return endTime;
		}

		public void setEndTime(Date endTime) {
			this.endTime = endTime;
		}
	}

	/**
	 * @describe 时间转换为星期数
	 * @author Joburgess
	 * @date 2019/10/28
	 * @param date: 日期
	 * @return java.lang.String
	 */
	public static String date2Week(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int i = calendar.get(Calendar.DAY_OF_WEEK);
		switch (i) {
		case 1:
			return "星期日";
		case 2:
			return "星期一";
		case 3:
			return "星期二";
		case 4:
			return "星期三";
		case 5:
			return "星期四";
		case 6:
			return "星期五";
		case 7:
			return "星期六";
		default:
			return "";
		}
	}

	/**
	 * 获取当前时间到0点的毫秒数
	 * @return
	 */
	public static long getTomorrowZeroSeconds() {
		long current = System.currentTimeMillis();// 当前时间毫秒数
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		long tomorrowzero = calendar.getTimeInMillis();
		long tomorrowzeroSeconds = (tomorrowzero - current) / 1000;
		return tomorrowzeroSeconds;
	}

	public static String timeStamp2Date(String seconds,String format) {
		if(seconds == null || seconds.isEmpty() || seconds.equals("null")){
			return "";
		}
		if(format == null || format.isEmpty()){
			format = "yyyy-MM-dd HH:mm:ss";
		}
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(new Date(Long.valueOf(seconds+"000")));
	}

	public static void main(String[] args) throws ParseException {
		// DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//		 System.out.println(daysBetween(df.parse("2017-07-20 10:07:42"), df.parse(df.format(new Date()))));
		System.out.println(getWeekMondayWithDate(new Date()));
		System.out.println(getNextWeekMonday(new Date()));
		System.out.println(getNextWeekSunday(new Date()));
		System.out.println(dayEnd(new Date()));
		System.out.println(format(getLastDayOfMonth(new Date()),CHINESE_DATA_FORMAT));
		System.out.println(monthsBetween(df1.parse("2020-01-18 12:00:00"),df1.parse("2020-04-19 12:00:00")));
		System.out.println(getNextWeekMonday(new Date()));
	}
}
