package org.phosphoresce.commons.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * 共通日付ユーティリティクラス。<br>
 * 
 * @author Kitagawa<br>
 * 
 *<!--
 * 更新日		更新者			更新内容
 * 2005/11/22	Kitagawa		新規作成
 *-->
 */
public final class DateUtil {

	/** 日付書式：yyyyMMdd */
	public static final String FORMAT_YYYYMMDD = "yyyyMMdd";

	/** 日付書式：yyyy/MM/dd */
	public static final String FORMAT_YYYYsMMsDD = "yyyy/MM/dd";

	/** 日付書式：yyyy/MM/dd HH:mm */
	public static final String FORMAT_YYYYsMMsDD_24HHcMM = "yyyy/MM/dd HH:mm";

	/** 日付書式：yyyy/MM/dd HH:mm:ss */
	public static final String FORMAT_YYYYsMMsDD_24HHcMMcSS = "yyyy/MM/dd HH:mm:ss";

	/** 日付書式：yyyy/MM/dd HH:mm:ss.SSS */
	public static final String FORMAT_YYYYsMMsDD_24HHcMMcSSdSSS = "yyyy/MM/dd HH:mm:ss.SSS";

	/** 日付書式：yyyy/MM/dd hh:mm:ss.SSS a */
	public static final String FORMAT_YYYYsMMsDD_12HHcMMcSSdSSS_A = "yyyy/MM/dd hh:mm:ss.SSS a";

	/** 日付書式：y/M/d */
	public static final String FORMAT_YsMsD = "y/M/d";

	/** 日付書式：yyyy/M/d HH:mm */
	public static final String FORMAT_YsMsD_24HHcMM = "y/M/d HH:mm";

	/** 日付書式：yyyy/M/d HH:mm:ss */
	public static final String FORMAT_YsMsD_24HHcMMcSS = "y/M/d HH:mm:ss";

	/** 日付書式：yyyy/M/d HH:mm:ss.SSS */
	public static final String FORMAT_YsMsD_24HHcMMcSSdSSS = "y/M/d HH:mm:ss.SSS";

	/** 日付書式：yyyy/M/d hh:mm:ss.SSS a */
	public static final String FORMAT_YsMsD_12HHcMMcSSdSSS_A = "y/M/d hh:mm:ss.SSS a";

	/** 日付書式：yyyy/M/d H:m */
	public static final String FORMAT_YsMsD_24HcM = "y/M/d H:m";

	/** 日付書式：yyyy/M/d H:m:s */
	public static final String FORMAT_YsMsD_24HcMcS = "y/M/d H:m:s";

	/** 日付書式：yyyy/M/d H:m:s.S */
	public static final String FORMAT_YsMsD_24HcMcSdS = "y/M/d H:m:s.S";

	/** 日付書式：yyyy/M/d h:m:s.S a */
	public static final String FORMAT_YsMsD_12HcMcSdS_A = "y/M/d h:m:s.S a";

	/** 日付書式：yyyyMMddHHmmssSSS */
	public static final String FORMAT_YYYYMMDD24HHMMSSSSS = "yyyyMMddHHmmssSSS";

	/** 日付書式：HH:mm */
	public static final String FORMAT_24HHcMM = "HH:mm";

	/** 日付書式：HH:mm:ss */
	public static final String FORMAT_24HHcMMcSS = "HH:mm:ss";

	/** 日付書式：HH:mm:ss.SSS */
	public static final String FORMAT_24HHcMMcSSdSSS = "HH:mm:ss.SSS";

	/** 日付書式：H:m */
	public static final String FORMAT_24HcM = "H:m";

	/** 日付書式：H:m:s */
	public static final String FORMAT_24HcMcS = "H:m:s";

	/** 日付書式：H:m:s.S */
	public static final String FORMAT_24HcMcSdS = "H:m:s.S";

	/** 日付書式：yyyyMMdd_HHmm */
	public static final String FORMAT_YYYYMMDDu24HHMM = "yyyyMMdd_HHmm";

	/** 日付書式：yyyy */
	public static final String FORMAT_YYYY = "yyyy";

	/** 日付書式：MM */
	public static final String FORMAT_MM = "MM";

	/** 日付書式：dd */
	public static final String FORMAT_DD = "dd";

	/** 日付書式：HH */
	public static final String FORMAT_24HH = "HH";

	/** 日付書式：hh */
	public static final String FORMAT_12HH = "hh";

	/** 日付書式：mm */
	public static final String FORMAT_MI = "mm";

	/** 日付書式：ss */
	public static final String FORMAT_SS = "ss";

	/** 日付書式：SSS */
	public static final String FORMAT_SSS = "SSS";

	/** 日付書式：a */
	public static final String FORMAT_A = "a";

	/** ディフォルト日付書式 */
	public static final String DEFAULT_FORMAT = FORMAT_YYYYsMMsDD;

	/**
	 * コンストラクタ<br>
	 */
	private DateUtil() {
		//
	}

	/**
	 * 指定された日付書式で記述された日付文字列をDateオブジェクトに変換します。<br>
	 * SimpleDateFormatがスローする例外のラップ、コーディングの簡易化を目的としたメソッド。<br>
	 * @param date 日付書式で記述された日付文字列
	 * @param format 日付書式
	 * @return 変換したDateオブジェクト
	 */
	public static Date parse(String date, String format) {
		try {
			return StringUtil.isEmpty(date) ? null : new SimpleDateFormat(format).parse(date);
		} catch (ParseException e) {
			throw new RuntimeException("日付書式、または日付文字列が不正な為、Dateオブジェクトへの変換に失敗しました [" + date + "]");
		}
	}

	/**
	 * 指定された日付書式で記述された日付文字列をDateオブジェクトに変換します。<br>
	 * SimpleDateFormatがスローする例外のラップ、コーディングの簡易化を目的としたメソッド。<br>
	 * @param date 日付書式で記述された日付文字列
	 * @param format 日付書式
	 * @return 変換したDateオブジェクト
	 */
	public static Date parse(String date, String[] format) {
		for (int i = 0; i <= format.length - 1; i++) {
			try {
				return StringUtil.isEmpty(date) ? null : new SimpleDateFormat(format[i]).parse(date);
			} catch (ParseException e) {
				if (i < format.length - 1) {
					continue;
				} else {
					throw new RuntimeException("日付書式、または日付文字列が不正な為、Dateオブジェクトへの変換に失敗しました [" + date + "]");
				}
			}
		}
		return null;
	}

	/**
	 * ディフォルト日付書式で記述された日付文字列をDateオブジェクトに変換します。<br>
	 * SimpleDateFormatがスローする例外のラップ、コーディングの簡易化を目的としたメソッド。<br>
	 * @param date ディフォルト日付書式で記述された日付文字列
	 * @return 変換したDateオブジェクト
	 */
	public static Date parse(String date) {
		return parse(date, DEFAULT_FORMAT);
	}

	/**
	 * 指定された日付書式にあわせた日付文字列として日付情報を取得します。<br>
	 * @param date Dateオブジェクト
	 * @param format 日付書式文字列
	 * @return 日付書式にあわせた日付文字列
	 */
	public static String format(Date date, String format) {
		return date == null ? "" : new SimpleDateFormat(format).format(date);
	}

	/**
	 * ディフォルト日付書式にあわせた日付文字列として日付情報を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return ディフォルト日付書式にあわせた日付文字列
	 */
	public static String format(Date date) {
		return format(date, DEFAULT_FORMAT);
	}

	/**
	 * 指定された日付をUTC書式に変換して取得します。<br>
	 * @param date Dateオブジェクト
	 * @return UTC書式に変換された日付文字列
	 */
	public static String formatUTC(Date date) {
		if (date == null) {
			return "";
		}
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd'T'HHmmssz");
		formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
		return formatter.format(date).replaceAll("UTC", "Z");
	}

	/**
	 * UTC書式日付文字列からDateオブジェクトにパースします。<br>
	 * @param date UTC書式日付文字列
	 * @return Dateオブジェクト
	 */
	public static Date parseUTC(String date) {
		if (StringUtil.isEmpty(date)) {
			return null;
		}
		return parse(date.replaceAll("Z", "UTC"), "yyyyMMdd'T'HHmmssz");
	}

	/**
	 * 指定されたDateオブジェクトの年を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの年
	 */
	public static String getYear(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_YYYY);
	}

	/**
	 * 指定されたDateオブジェクトの月を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの月
	 */
	public static String getMonth(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_MM);
	}

	/**
	 * 指定されたDateオブジェクトの日を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの日
	 */
	public static String getDay(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_DD);
	}

	/**
	 * 指定されたDateオブジェクトの時を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの時
	 */
	public static String getHour(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_24HH);
	}

	/**
	 * 指定されたDateオブジェクトの時(12時間表記)を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの時(12時間表記)
	 */
	public static String getHour12(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_12HH);
	}

	/**
	 * 指定されたDateオブジェクトの分を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの分
	 */
	public static String getMinute(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_MI);
	}

	/**
	 * 指定されたDateオブジェクトの秒を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトの秒
	 */
	public static String getSecond(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_SS);
	}

	/**
	 * 指定されたDateオブジェクトのミリ秒を取得します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトのミリ秒
	 */
	public static String getMilliSecond(Date date) {
		return date == null ? "" : format(new Date(), FORMAT_SSS);
	}

	/**
	 * 指定されたDateオブジェクトが午前の時間であるか判定します。<br>
	 * @param date Dateオブジェクト
	 * @return 指定されたDateオブジェクトが午前の時間である場合はtrueを返却
	 */
	public static boolean isAM(Date date) {
		//return "午前".equals(format(date, FORMAT_A));
		return format(date, FORMAT_24HH).equals(format(date, FORMAT_12HH));
	}

	/**
	 * 現在のDateオブジェクトを取得します。<br>
	 * Dateオブジェクトのインスタンスをそのまま返却するメソッドですが、
	 * 一貫性の為設けてあります。<br>
	 * @return 現在のDateオブジェクト
	 */
	public static Date getNowDate() {
		return new Date();
	}

	/**
	 * 現在の年(yyyy)を取得します。<br>
	 * @return 現在の年(yyyy)
	 */
	public static String getNowYear() {
		return getYear(new Date());
	}

	/**
	 * 現在の月(MM)を取得します。<br>
	 * @return 現在の月(MM)
	 */
	public static String getNowMonth() {
		return getMonth(new Date());
	}

	/**
	 * 現在の日(dd)を取得します。<br>
	 * @return 現在の日(dd)
	 */
	public static String getNowDay() {
		return getDay(new Date());
	}

	/**
	 * 現在の時(HH)を取得します。<br>
	 * @return 現在の時(HH)
	 */
	public static String getNowHour() {
		return getHour(new Date());
	}

	/**
	 * 現在の時(hh)を取得します。<br>
	 * @return 現在の時(hh)
	 */
	public static String getNowHour12() {
		return getHour12(new Date());
	}

	/**
	 * 現在の分(mm)を取得します。<br>
	 * @return 現在の分(mm)
	 */
	public static String getNowMinute() {
		return getMinute(new Date());
	}

	/**
	 * 現在の時間が午前であるか判定します。<br>
	 */
	public static boolean isAMAtNow() {
		return isAM(new Date());
	}

	/**
	 * 文字列が指定された書式からDateオブジェクトと出来る有効な
	 * 文字列であるかどうか判定します。<br>
	 * @param value 判定対象文字列
	 * @param pattern 判定書式
	 * @return 有効な文字列の場合trueを返却
	 */
	public static boolean isValidityDateStringValue(String value, String pattern) {
		if (value == null || pattern == null) {
			return false;
		}

		try {
			SimpleDateFormat format = new SimpleDateFormat(pattern);
			format.parse(value);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * 文字列が指定されたDateFormatオブジェクトからDateオブジェクトと出来る有効な
	 * 文字列であるかどうか判定します。<br>
	 * @param value 判定対象文字列
	 * @param format DateFormatオブジェクト
	 * @return 有効な文字列の場合trueを返却
	 */
	public static boolean isValidityDateStringValue(String value, DateFormat format) {
		if (value == null || format == null) {
			return false;
		}

		try {
			format.parse(value);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	/**
	 * ディフォルトの書式で文字列がDateオブジェクトと出来る有効な
	 * 文字列であるかどうか判定します。<br>
	 * @param value 判定対象文字列
	 * @return 有効な文字列の場合trueを返却
	 */
	public static boolean isValidityDateStringValue(String value) {
		if (value == null) {
			return false;
		}

		try {
			SimpleDateFormat format = new SimpleDateFormat(DEFAULT_FORMAT);
			format.parse(value);
		} catch (Exception e) {
			return false;
		}
		return true;
	}
}
