DateTerm.java
package com.github.mygreen.cellformatter.term;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.mygreen.cellformatter.lang.Era;
import com.github.mygreen.cellformatter.lang.EraPeriod;
import com.github.mygreen.cellformatter.lang.EraResolver;
import com.github.mygreen.cellformatter.lang.ExcelDateUtils;
import com.github.mygreen.cellformatter.lang.MSLocale;
import com.github.mygreen.cellformatter.lang.MessageResolver;
import com.github.mygreen.cellformatter.lang.Utils;
/**
* 日時の書式の項
*
* @version 0.5
* @author T.TSUCHIE
*
*/
public abstract class DateTerm implements Term<Calendar> {
protected static final Logger logger = LoggerFactory.getLogger(DateTerm.class);
protected static final MessageResolver messageResolver = new MessageResolver("com.github.mygreen.cellformatter.label");
protected static final EraResolver eraResolver = new EraResolver();
@Override
public String format(Calendar value, MSLocale formatLocale, Locale runtimeLocale) {
// このメソッドは実質呼ばれない。
return format(value, formatLocale, runtimeLocale, false);
}
/**
* 値をフォーマットする。
* @param value フォーマット対象の値。
* @param formatLocale 書式中に指定されたロケール。
* @param runtimeLocale 実行時にしていされたロケール。
* @param isStartDate1904 日時が1904年始まりかどうか。
* @return フォーマットされた文字列。nullは返さない。
*/
public abstract String format(Calendar value, MSLocale formatLocale, Locale runtimeLocale, boolean isStartDate1904);
/**
* 経過時間を計算するときの基準日を取得する。
* ・1900/2/28までは、-1日ずれる。Excelは1900年は1月0日(=1899年12月31日)から始まるため、1日多い。
* ・1900/3/1以降は、-2日ずれず。Excel は、閏日ではない1900年2月29日(=1900年3月1日)が存在するため1日多い。
* @param date
* @param isStartDate1904
* @return
*/
private static long getElapsedZeroTime(final Date date, final boolean isStartDate1904) {
if(isStartDate1904) {
return ExcelDateUtils.getExcelZeroDateTime(isStartDate1904);
} else {
if(ExcelDateUtils.MILLISECONDS_19000301 <= date.getTime()) {
// 1900-03-01以降
return ExcelDateUtils.MILLISECONDS_19000101 - TimeUnit.DAYS.toMillis(2);
} else {
return ExcelDateUtils.MILLISECONDS_19000101 - TimeUnit.DAYS.toMillis(1);
}
}
}
/**
* [h] - 24時を超える経過時間の処理
*/
public static DateTerm elapsedHour(final String format) {
return new ElapsedHourTerm(format);
}
/**
* [m] - 60分を超える経過時間の処理
*/
public static DateTerm elapsedMinute(final String format) {
return new ElapsedMinuteTerm(format);
}
/**
* [s] - 60秒を超える経過時間の処理
*/
public static DateTerm elapsedSecond(final String format) {
return new ElapsedSecondTerm(format);
}
/**
* y - 年の場合の処理
*/
public static DateTerm year(final String format) {
return new YearTerm(format);
}
/**
* g - 元号の名称の場合の処理
*/
public static DateTerm eraName(final String format) {
return new EraNameTerm(format);
}
/**
* e - 元号の年の場合の処理
*/
public static DateTerm eraYear(final String format) {
return new EraYearTerm(format);
}
/**
* r - 元号の名称と年の場合の処理
*/
public static DateTerm eraNameYear(final String format) {
return new EraNameYearTerm(format);
}
/**
* m - 月の場合の処理
*/
public static DateTerm month(final String format) {
return new MonthTerm(format);
}
/**
* d - 日の場合の処理
*/
public static DateTerm day(final String format) {
return new DayTerm(format);
}
/**
* a - 曜日の名称場合の処理
*/
public static DateTerm weekName(final String format) {
return new WeekName(format);
}
/**
* n - 曜日の名称場合の処理(OpenOffice用)
*/
public static DateTerm weekNameForOO(final String format) {
return new WeekNameForOO(format);
}
/**
* ww - 年の週番号(OpenOffice用)
*/
public static DateTerm weekNumber(final String format) {
return new WeekNumberTerm(format);
}
/**
* h - 時間の場合の処理
* @param format
* @param half 12時間表示かどうか
*/
public static DateTerm hour(final String format, final boolean half) {
return new HourTerm(format, half);
}
/**
* m - 分の場合の処理
*/
public static DateTerm minute(final String format) {
return new MinuteTerm(format);
}
/**
* s - 秒の場合の処理
*/
public static DateTerm second(final String format) {
return new SecondTerm(format);
}
/**
* q - 四半期の場合の処理(OpenOffice用)
*/
public static DateTerm quater(final String format) {
return new QuaterTerm(format);
}
/**
* AM/PM - 午前/午後の場合の処理
*/
public static DateTerm amPm(final String format) {
return new AmPmTerm(format);
}
/**
* [h] - 24時を超える経過時間の処理
*/
public static class ElapsedHourTerm extends DateTerm {
/** ミリ秒を時間に直すための基底 */
private static final long BASE = 1000*60*60;
private final String format;
public ElapsedHourTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
if(logger.isInfoEnabled()) {
logger.info("ElapsedHour:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
}
final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
final int formatLength = format.length();
return Utils.supplyZero(String.valueOf(time), formatLength);
}
public String getFormat() {
return format;
}
}
/**
* [m] - 60分を超える経過時間の処理
*/
public static class ElapsedMinuteTerm extends DateTerm {
/** ミリ秒を分に直すための基底 */
private static final long BASE = 1000*60;
private final String format;
public ElapsedMinuteTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
if(logger.isInfoEnabled()) {
logger.info("ElapsedMinute:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
}
final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
final int formatLength = format.length();
return Utils.supplyZero(String.valueOf(time), formatLength);
}
public String getFormat() {
return format;
}
}
/**
* [s] - 60秒を超える経過時間の処理
*/
public static class ElapsedSecondTerm extends DateTerm {
/** ミリ秒を秒に直すための基底 */
private static final long BASE = 1000;
private final String format;
public ElapsedSecondTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
if(logger.isInfoEnabled()) {
logger.info("ElapsedSecond:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
}
final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
final int formatLength = format.length();
return Utils.supplyZero(String.valueOf(time), formatLength);
}
public String getFormat() {
return format;
}
}
/**
* y - 年の場合
*/
public static class YearTerm extends DateTerm {
private final String format;
public YearTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final String value = String.valueOf(cal.get(Calendar.YEAR));
final int formatLength = format.length();
// 2桁、4桁補正する
if(formatLength <= 2) {
return Utils.supplyZero(value, 2).substring(2);
} else {
return Utils.supplyZero(value, 4);
}
}
public String getFormat() {
return format;
}
}
/**
* g - 元号の名称の場合
*/
public static class EraNameTerm extends DateTerm {
private final String format;
public EraNameTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final Date date = cal.getTime();
final Era era;
if(formatLocale != null) {
era = eraResolver.getEra(formatLocale);
} else {
era = eraResolver.getEra(runtimeLocale);
}
if(era.isUnkndown()) {
return "";
}
final EraPeriod period = era.getTargetPeriod(date);
if(period.isUnknown()) {
return "";
}
final int formatLength = format.length();
if(formatLength == 1) {
return period.getAbbrevRomanName();
} else if(formatLength == 2) {
return period.getAbbrevName();
} else {
return period.getName();
}
}
public String getFormat() {
return format;
}
}
/**
* e - 元号の年の場合
*/
public static class EraYearTerm extends DateTerm {
private final String format;
public EraYearTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int formatLength = format.length();
final Date date = cal.getTime();
final Era era;
if(formatLocale != null) {
era = eraResolver.getEra(formatLocale);
} else {
era = eraResolver.getEra(runtimeLocale);
}
if(era.isUnkndown()) {
// 該当する時代の定義がない場合
String value = String.valueOf(cal.get(Calendar.YEAR));
return Utils.supplyZero(value, formatLength);
}
final EraPeriod period = era.getTargetPeriod(date);
if(period.isUnknown()) {
// 期間が不明な場合
String value = String.valueOf(cal.get(Calendar.YEAR));
return Utils.supplyZero(value, formatLength);
}
final String value = String.valueOf(period.getEraYear(cal));
return Utils.supplyZero(value, formatLength);
}
public String getFormat() {
return format;
}
}
/**
* r - 元号の名称と年の場合
*/
public static class EraNameYearTerm extends DateTerm {
private final String format;
public EraNameYearTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int formatLength = format.length();
final Date date = cal.getTime();
final Era era;
if(formatLocale != null) {
era = eraResolver.getEra(formatLocale);
} else {
era = eraResolver.getEra(runtimeLocale);
}
if(era.isUnkndown()) {
// 該当する時代の定義がない場合
String value = String.valueOf(cal.get(Calendar.YEAR));
return Utils.supplyZero(value, formatLength);
}
final EraPeriod period = era.getTargetPeriod(date);
if(period.isUnknown()) {
// 期間が不明な場合
String value = String.valueOf(cal.get(Calendar.YEAR));
return Utils.supplyZero(value, formatLength);
}
StringBuilder sb = new StringBuilder();
// 元号の組み立て(2桁以上の時に元号を追加)
if(formatLength >= 2) {
sb.append(period.getName());
}
// 年の組み立て
final String strYear = String.valueOf(period.getEraYear(cal));
sb.append(Utils.supplyZero(strYear, 2));
return sb.toString();
}
public String getFormat() {
return format;
}
}
/**
* m - 月の場合
*/
public static class MonthTerm extends DateTerm {
private final String format;
public MonthTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int value = cal.get(Calendar.MONTH) + 1;
final int formatLength = format.length();
if(formatLength == 1) {
return String.valueOf(value);
} else if(formatLength == 2) {
return Utils.supplyZero(String.valueOf(value), 2);
} else if(formatLength == 3) {
// 月名の先頭3文字
final String key = String.format("month.%d.abbrev", value);
return DateTerm.messageResolver.getMessage(formatLocale, key);
} else if(formatLength == 4) {
// 月名
final String key = String.format("month.%d.name", value);
return DateTerm.messageResolver.getMessage(formatLocale, key);
} else if(formatLength == 5) {
// 月名の先頭1文字
final String key = String.format("month.%d.leading", value);
return DateTerm.messageResolver.getMessage(formatLocale, key);
} else {
return Utils.supplyZero(String.valueOf(value), 2);
}
}
public String getFormat() {
return format;
}
}
/**
* 曜日のインデックスを取得する。
* ・日曜始まりで、0から始まる。
* @param cal
* @return
*/
private static int getWeekIndex(final Calendar cal) {
final int val = cal.get(Calendar.DAY_OF_WEEK);
switch(val) {
case Calendar.SUNDAY:
return 0;
case Calendar.MONDAY:
return 1;
case Calendar.TUESDAY:
return 2;
case Calendar.WEDNESDAY:
return 3;
case Calendar.THURSDAY:
return 4;
case Calendar.FRIDAY:
return 5;
case Calendar.SATURDAY:
return 6;
}
return 0;
}
/**
* d - 日の場合
* ・dが3~4桁の場合は、英字の曜日。
*/
public static class DayTerm extends DateTerm {
private final String format;
public DayTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int value = cal.get(Calendar.DAY_OF_MONTH);
final int formatLength = format.length();
if(formatLength == 1) {
return String.valueOf(value);
} else if(formatLength == 2) {
return Utils.supplyZero(String.valueOf(value), 2);
} else if(formatLength == 3) {
// 曜日の省略名
final int index = getWeekIndex(cal);
final String key = String.format("week.%d.abbrev", index);
return messageResolver.getMessage(formatLocale, key);
} else if(formatLength >= 4) {
// 曜日の正式名
final int index = getWeekIndex(cal);
final String key = String.format("week.%d.name", index);
return messageResolver.getMessage(formatLocale, key);
} else {
return Utils.supplyZero(String.valueOf(value), 2);
}
}
public String getFormat() {
return format;
}
}
/**
* a- 日本語名称の曜日の場合
*
*/
public static class WeekName extends DateTerm {
private final String format;
public WeekName(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int index = getWeekIndex(cal);
final int formatLength = format.length();
if(formatLength <= 3) {
final String key = String.format("week.%d.abbrev", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
} else {
final String key = String.format("week.%d.name", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
}
}
public String getFormat() {
return format;
}
}
/**
* n- OpenOffice用の日本語名称の曜日の場合
*
*/
public static class WeekNameForOO extends DateTerm {
private final String format;
public WeekNameForOO(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int index = getWeekIndex(cal);
final int formatLength = format.length();
if(formatLength <= 2) {
final String key = String.format("week.%d.abbrev", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
} else {
final String key = String.format("week.%d.name", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
}
}
public String getFormat() {
return format;
}
}
/**
* ww - 年の週番号を取得する。
*
*/
public static class WeekNumberTerm extends DateTerm {
private final String format;
public WeekNumberTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int val = cal.get(Calendar.WEEK_OF_YEAR);
return String.valueOf(val);
}
public String getFormat() {
return format;
}
}
/**
* h - 時間の場合
*/
public static class HourTerm extends DateTerm {
private final String format;
/**
* 12時間表示かどうか。
*/
private final boolean half;
public HourTerm(final String format, final boolean half) {
this.format = format;
this.half = half;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final String value;
if(isHalf()) {
value = String.valueOf(cal.get(Calendar.HOUR));
} else {
value = String.valueOf(cal.get(Calendar.HOUR_OF_DAY));
}
final int formatLength = format.length();
return Utils.supplyZero(value, formatLength);
}
public boolean isHalf() {
return half;
}
public String getFormat() {
return format;
}
}
/**
* m - 分の場合
*/
public static class MinuteTerm extends DateTerm {
private final String format;
public MinuteTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final String value = String.valueOf(cal.get(Calendar.MINUTE));
final int formatLength = format.length();
return Utils.supplyZero(value, formatLength);
}
public String getFormat() {
return format;
}
}
/**
* s - 秒の場合
*/
public static class SecondTerm extends DateTerm {
private final String format;
public SecondTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final String value = String.valueOf(cal.get(Calendar.SECOND));
final int formatLength = format.length();
return Utils.supplyZero(value, formatLength);
}
public String getFormat() {
return format;
}
}
/**
* AM/PM - 午前/午後の場合
*/
public static class AmPmTerm extends DateTerm {
private final String format;
private final String am;
private final String pm;
public AmPmTerm(final String format) {
this.format = format;
String[] split = format.split("/");
if(split.length >= 2) {
this.am = split[0];
this.pm = split[1];
} else {
this.am = "AM";
this.pm = "PM";
}
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int val = cal.get(Calendar.AM_PM);
if(val == Calendar.AM) {
return messageResolver.getMessage(formatLocale, "day.am.name", am);
} else {
return messageResolver.getMessage(formatLocale, "day.pm.name", pm);
}
}
public String getFormat() {
return format;
}
public String getAm() {
return am;
}
public String getPm() {
return pm;
}
}
/**
* q - 四半期の場合
*/
public static class QuaterTerm extends DateTerm {
private final String format;
public QuaterTerm(final String format) {
this.format = format;
}
@Override
public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
final int index = (cal.get(Calendar.MONTH) / 3) + 1;
// Excelではなく実行環境のロケールによっても変わるため注意
if(format.length() == 1) {
final String key = String.format("quaterTerm.%d.abbrev", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
} else {
final String key = String.format("quaterTerm.%d.name", index);
return messageResolver.getMessage(formatLocale, runtimeLocale, key);
}
}
}
}