package com.ylcm.sys.common;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

public class DateUtil {

	// 格式 HH 必须大写，否则按照12小时制
	private static String shortPattern = "yyyy-MM-dd";
	private static String longPattern = "yyyy-MM-dd HH:mm:ss";
	private static Logger logger = Logger.getLogger(DateUtil.class);
	private static SimpleDateFormat longDateFormat = new SimpleDateFormat(
			longPattern);
	private static SimpleDateFormat shortDateFormat = new SimpleDateFormat(
			shortPattern);

	/**
	 * 日期转换str->date
	 * @param dateStr
	 *            default:yyyy-MM-dd
	 * @param pattern
	 * @return
	 */
	public static Date str2Date(String dateStr, String pattern) {
		Date date = null;
		SimpleDateFormat format = null;
		if (pattern == null || ("").equals(pattern)) {
			format = shortDateFormat;
		} else {
			format = new SimpleDateFormat(pattern, Locale.US);
		}
		try {
			synchronized (format) {
				// SimpleDateFormat is not thread safe
				date = format.parse(dateStr);
			}
		} catch (ParseException e) {
			logger.error(e.getMessage());
		}
		return date;
	}

	/**
	 * 日期转换
	 * ts->str
	 * @param ts
	 * @return yyyy-MM-dd HH:mm:ss
	 */
	public static String timestamp2Str(Timestamp ts) {
		if (ts != null) {
			synchronized (longDateFormat) {
				return longDateFormat.format(ts);
			}
		}
		return null;
	}
	
	public static String timestamp2Str(Timestamp ts, String pattern) {
		if (ts != null) {
			SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
			return dateFormat.format(ts);
		}
		return null;
	}

	/**
	 * 日期转换
	 * date->str
	 * @param date
	 * @param pattern
	 * @return
	 */
	public static String date2Str(Date date, String pattern) {
		if(date != null){
			SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
			return dateFormat.format(date);
		} else {
			return "";
		}
	}
	
	public static String date2Str(LocalDate date, String pattern) {
		if(date != null){
			return date.format(DateTimeFormatter.ISO_DATE);
		} else {
			return "";
		}
	}

	public static LocalDate str2Date(String dateStr){
		return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
	}
	
	public static String time2Str(LocalTime date, String pattern) {
		if(date != null){
			return date.format(DateTimeFormatter.ISO_TIME);
		} else {
			return "";
		}
	}

	/**
	 * 根据出生日期算几岁
	 * @param birthDay
	 * @return
	 * @throws Exception
	 */
	public static int getAge(Date birthDay) throws Exception {
		Calendar cal = Calendar.getInstance();

		if (cal.before(birthDay)) {
			throw new IllegalArgumentException(
					"The birthDay is before Now.It's unbelievable!");
		}

		int yearNow = cal.get(Calendar.YEAR);
		int monthNow = cal.get(Calendar.MONTH);
		int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
		cal.setTime(birthDay);

		int yearBirth = cal.get(Calendar.YEAR);
		int monthBirth = cal.get(Calendar.MONTH);
		int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

		int age = yearNow - yearBirth;

		if (monthNow <= monthBirth) {
			if (monthNow == monthBirth) {
				// monthNow==monthBirth
				if (dayOfMonthNow < dayOfMonthBirth) {
					age--;
				} else {
					// do nothing
				}
			} else {
				// monthNow>monthBirth
				age--;
			}
		} else {
			// monthNow<monthBirth
			// donothing
		}

		return age;
	}
	
	public static String getTimestampYmdhms() {

		Calendar cal = Calendar.getInstance();

		String year = Integer.toString(cal.get(Calendar.YEAR));
		String month = Integer.toString(cal.get(Calendar.MONTH) + 1);
		String day = Integer.toString(cal.get(Calendar.DATE));
		String hour = Integer.toString(cal.get(Calendar.HOUR_OF_DAY));
		String minute = Integer.toString(cal.get(Calendar.MINUTE));
		String second = Integer.toString(cal.get(Calendar.SECOND));
		String m = Integer.toString(cal.get(Calendar.MILLISECOND));

		StringBuffer ret = new StringBuffer();
		ret.append(year).append("-");
		ret.append(month.length() == 1 ? "0" + month : month).append("-");
		ret.append(day.length() == 1 ? "0" + day : day).append(" ");
		ret.append(hour.length() == 1 ? "0" + hour : hour).append(":");
		ret.append(minute.length() == 1 ? "0" + minute : minute).append(":");
		ret.append(second.length() == 1 ? "0" + second : second);
		ret.append(":" + m);
		return ret.toString();
	}

	public static String toYMDHMS(String argYmdHMS) {

		if (argYmdHMS == null || argYmdHMS.length() == 0) {
			return null;
		}
		String strTmpDate = argYmdHMS.replaceAll("-", "");
		strTmpDate = strTmpDate.replaceAll("/", "");
		strTmpDate = strTmpDate.replaceAll(":", "");
		strTmpDate = strTmpDate.replaceAll(" ", "");
		return strTmpDate;
	}

	/**
	 * 得到类似微博的时间格式
	 * @param date
	 * @return
	 */
	public static String getShortTime(Date date) {
		String shortstring = null;

		if (date == null)
			return shortstring;

		long now = Calendar.getInstance().getTimeInMillis();
		long deltime = (now - date.getTime()) / 1000;
		if (deltime > 2 * 24 * 60 * 60) {
			shortstring = date2Str(date, "MM月dd日 HH:mm");
		} else if (deltime > 24 * 60 * 60) {
			shortstring = "昨天 " + date2Str(date, "HH:mm");
		} else if (deltime > 60 * 60) {
			shortstring = (int) (deltime / (60 * 60)) + "小时前";
		} else if (deltime > 60) {
			shortstring = (int) (deltime / (60)) + "分钟前";
		} else if (deltime > 1) {
			shortstring = deltime + "秒前";
		} else {
			shortstring = "刚刚";
		}
		return shortstring;
	}
	
	/**
	 * 得到类似微博的时间格式 比较早的时间不加几点几分
	 * @param date
	 * @return
	 */
	public static String getShortTime1(Date date) {
		String shortstring = null;

		if (date == null)
			return shortstring;

		long now = Calendar.getInstance().getTimeInMillis();
		long deltime = (now - date.getTime()) / 1000;
		if (deltime > 2 * 24 * 60 * 60) {
			shortstring = date2Str(date, "MM月dd日");
		} else if (deltime > 24 * 60 * 60) {
			shortstring = "昨天 " + date2Str(date, "HH:mm");
		} else if (deltime > 60 * 60) {
			shortstring = (int) (deltime / (60 * 60)) + "小时前";
		} else if (deltime > 60) {
			shortstring = (int) (deltime / (60)) + "分钟前";
		} else if (deltime > 1) {
			shortstring = deltime + "秒前";
		} else {
			shortstring = "刚刚";
		}
		return shortstring;
	}
	
	/**
	 * 获取当前日期的第一天
	 * @param date 当前日期
	 * @return 当前日期的第一天
	 */
	public static Date getFirstDayByDate(Date date){
		if(date == null){
			return null;
		}
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		return cal.getTime();
	}
	
	/**
	 * 日期提前或者推迟N天
	 * @param date 日期
	 * @param amount 计量数
	 * @return 处理后的日期
	 */
	public static Date addDate(Date date, int amount){
		
		if(date == null){
			return null;
		}
		
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DAY_OF_MONTH, amount);
		return cal.getTime();
	}

	/**
	 * 求2个日期之间的差值 a-b
	 * @param aDate
	 * @param bDate
	 * @return
	 */
	public static long subDates(Date aDate, Date bDate){
		long sub = 0;
		
		if (aDate != null && bDate != null) {
			sub = aDate.getTime() - bDate.getTime();
		}
		
		return sub;
	}

	public static Date string2sdate(String input) throws ParseException {
		Date result = null;

		if (!StringUtils.isBlank(input)) {
			Calendar c = Calendar.getInstance();
			c.setTime(longDateFormat.parse(input));
			c.set(Calendar.HOUR, 0);
			c.set(Calendar.MINUTE, 0);
			c.set(Calendar.SECOND, 0);
			result = c.getTime();
		}

		return result;
	}

	public static Date string2edate(String input) throws ParseException {
		Date result = null;

		if (!StringUtils.isBlank(input)) {
			Calendar c = Calendar.getInstance();
			c.setTime(longDateFormat.parse(input));
			c.set(Calendar.HOUR, 23);
			c.set(Calendar.MINUTE, 59);
			c.set(Calendar.SECOND, 59);
			result = c.getTime();
		}

		return result;
	}
	
	/**
	 * 获得时间段内的随机日期
	 * @param beginDateString
	 * @param endDateString
	 * @return
	 */
	public static String getRandomDate(String beginDateString,
			String endDateString) {

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

			Date beginDate = sdf.parse(beginDateString);
			Date endDate = sdf.parse(endDateString);

			long timeRange = (endDate.getTime() - beginDate.getTime());

			long millisecondAdd = (long) (Math.random() * timeRange);

			Date randomDate = new java.sql.Date(beginDate.getTime()
					+ millisecondAdd);

			return randomDate.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 闰年判断
	 * @param year
	 * @return
	 */
	public static boolean isLeapYear(int year) {

		GregorianCalendar calendar = new GregorianCalendar();

		return calendar.isLeapYear(year);

	}
	
	/**
	 * 
	 * @param date  default format(yyyy-MM-dd HH:mm:ss)
	 * @return
	 */
	public static String toString(Date date) {
		if (date != null) {
			synchronized (longDateFormat) {
				return longDateFormat.format(date);
			}
		}
		return null;
	}

	public static String toString(Date date, String pattern) {
		if(date != null){
			SimpleDateFormat shortDateFormat = new SimpleDateFormat(pattern);
			return shortDateFormat.format(date);
		} else {
			return "";
		}
	}
	
	
	/**
	 * 周6
	 * @param today
	 * @return
	 */
	public static Date getThisWeekSatDay(Date today){
		Calendar c = new GregorianCalendar(); 
		c.setFirstDayOfWeek(Calendar.MONDAY); 
		c.setTime(today); 
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 5); 
		Date staDate = c.getTime(); 
		return staDate;
	}
	
	/**
	 * 周7
	 * @param today
	 * @return
	 */
	public static Date getThisWeekSunDay(Date today){
		Calendar c = new GregorianCalendar(); 
		c.setFirstDayOfWeek(Calendar.MONDAY); 
		c.setTime(today); 
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6); 
		Date sunDate = c.getTime(); 
		return sunDate;
	}
	
	/**
	 * 周六
	 * @param today
	 * @param x 从0开始
	 * @return
	 */
	public static Date getThisWeekDay(Date today, int x){
		Calendar c = new GregorianCalendar(); 
		c.setFirstDayOfWeek(Calendar.MONDAY); 
		c.setTime(today); 
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + x); 
		Date sunDate = c.getTime(); 
		return sunDate;
	}
	
	/**
	 * 今天 格式yyyy-MM-dd
	 * @return
	 */
	public static Date getTodayZeroTime(){
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		return calendar.getTime();
	}
	
	/**
	 * 得到星期几信息
	 * @param date
	 * @return
	 */
	public static String getWeek(Date date) {
		String[] weeks = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (week_index < 0) {
			week_index = 0;
		}
		return weeks[week_index];
	}
	
	public static List<String> getSpecialDay(String type){
		List<String> specialDay = new ArrayList<String>();
		
		Calendar calendar =Calendar.getInstance(); //当前日期
        
        Calendar cend =Calendar.getInstance(); 
        
        cend.add(Calendar.MONTH, 3);

        //向后
		for (; calendar.before(cend); calendar.add(Calendar.DAY_OF_YEAR, 7)) {
			Calendar now = (Calendar) calendar.clone();
			if ("周六".equals(type)) {
				specialDay.add(date2Str(getThisWeekSatDay(now.getTime()), "yyyy-MM-dd"));
			}else if("周日".equals(type)){
				specialDay.add(date2Str(getThisWeekSunDay(now.getTime()), "yyyy-MM-dd"));
			}else if("周末".equals(type)){
				specialDay.add(date2Str(getThisWeekSatDay(now.getTime()), "yyyy-MM-dd"));
				specialDay.add(date2Str(getThisWeekSunDay(now.getTime()), "yyyy-MM-dd"));
			}else if("工作日".equals(type)){
				specialDay.add(date2Str(getThisWeekDay(now.getTime(), 0), "yyyy-MM-dd"));
				specialDay.add(date2Str(getThisWeekDay(now.getTime(), 1), "yyyy-MM-dd"));
				specialDay.add(date2Str(getThisWeekDay(now.getTime(), 2), "yyyy-MM-dd"));
				specialDay.add(date2Str(getThisWeekDay(now.getTime(), 3), "yyyy-MM-dd"));
				specialDay.add(date2Str(getThisWeekDay(now.getTime(), 4), "yyyy-MM-dd"));
			}
		}
        
        return specialDay;
	}
	
	/**
	 * 月份比较
	 * @param date1
	 * @param date2
	 * @return date2 - date1
	 */
	public static int getMonthSpace(Date date1, Date date2){

		int result = 0;

		Calendar c1 = Calendar.getInstance();
		Calendar c2 = Calendar.getInstance();

		c1.setTime(date1);
		c2.setTime(date2);

		result = c2.get(Calendar.MONDAY) - c1.get(Calendar.MONTH);

		return result;

	}
	
	public static void main(String[] args) {
		Date date = new Date();
		String dateString = "Sun Nov 04 11:04:27 +0800 2012";
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"EEE MMM dd HH:mm:ss Z yyyy", Locale.US);
		try {
			System.out.println(dateFormat.parse(dateString));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		System.out.println("The first day is : " + getFirstDayByDate(date));
		
		System.out.println("The final day is : " + addDate(date, -30));
		
		System.out.println("The final day is : " + addDate(date, 30));
		
		System.out.println("This weekend day is : " + DateUtil.toString(getThisWeekSunDay(date), "yyyy-MM-dd"));
		System.out.println("This weekend day is : " + DateUtil.toString(getThisWeekSatDay(date), "yyyy-MM-dd"));

		Date nowDate = new Date();
		
		nowDate = DateUtil.getTodayZeroTime();
		System.out.println(DateUtil.toString(nowDate, "yyyy-MM-dd"));
	}
	
	/**
	 * 判断是否为日期
	 * @param date
	 * @return
	 */
	public boolean isDate(String date)
    {
        /**
         * 判断日期格式和范围
         */
        String rexp = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
         
        Pattern pat = Pattern.compile(rexp);  
         
        Matcher mat = pat.matcher(date);  
         
        boolean dateType = mat.matches();

        return dateType;
    }
	
	/**
	 * 判断是否为日期
	 * @param date
	 * @param pattern
	 * @return
	 */
	public static boolean isDate(String date, String pattern){
		try {
			SimpleDateFormat format=new SimpleDateFormat(pattern);
			format.parse(date);
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
    /**
     * 日期串格式化
     *
     * @param startDate yyyy-MM-dd
     * @return LocalDate
     */
    public static LocalDate getLocaDateByString(String startDate) {
        return LocalDate.parse(startDate, DateTimeFormatter.ISO_LOCAL_DATE);
    }
    
    public static LocalTime getLocaTimeByString(String startDate) {
        return LocalTime.parse(startDate, DateTimeFormatter.ISO_TIME);
    }
    
    public static String getStringByLocalDate(LocalDate startDate) {
        try {
        	return startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }catch (Exception e) {
        	return "";
		}
    }
    
    public static String getStringByLocalTime(LocalTime startDate) {
    	try {
        	return startDate.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
        }catch (Exception e) {
        	return "";
		}
    }
}
