View Javadoc
1   package com.github.mygreen.cellformatter.term;
2   
3   import java.util.Calendar;
4   import java.util.Date;
5   import java.util.Locale;
6   import java.util.concurrent.TimeUnit;
7   
8   import org.slf4j.Logger;
9   import org.slf4j.LoggerFactory;
10  
11  import com.github.mygreen.cellformatter.lang.Era;
12  import com.github.mygreen.cellformatter.lang.EraPeriod;
13  import com.github.mygreen.cellformatter.lang.EraResolver;
14  import com.github.mygreen.cellformatter.lang.ExcelDateUtils;
15  import com.github.mygreen.cellformatter.lang.MSLocale;
16  import com.github.mygreen.cellformatter.lang.MessageResolver;
17  import com.github.mygreen.cellformatter.lang.Utils;
18  
19  
20  /**
21   * 日時の書式の項
22   *
23   * @version 0.5
24   * @author T.TSUCHIE
25   *
26   */
27  public abstract class DateTerm implements Term<Calendar> {
28  
29      protected static final Logger logger = LoggerFactory.getLogger(DateTerm.class);
30  
31      protected static final MessageResolvergeResolver.html#MessageResolver">MessageResolver messageResolver = new MessageResolver("com.github.mygreen.cellformatter.label");
32  
33      protected static final EraResolverng/EraResolver.html#EraResolver">EraResolver eraResolver = new EraResolver();
34  
35      @Override
36      public String format(Calendar value, MSLocale formatLocale, Locale runtimeLocale) {
37          // このメソッドは実質呼ばれない。
38          return format(value, formatLocale, runtimeLocale, false);
39      }
40  
41      /**
42       * 値をフォーマットする。
43       * @param value フォーマット対象の値。
44       * @param formatLocale 書式中に指定されたロケール。
45       * @param runtimeLocale 実行時にしていされたロケール。
46       * @param isStartDate1904 日時が1904年始まりかどうか。
47       * @return フォーマットされた文字列。nullは返さない。
48       */
49      public abstract String format(Calendar value, MSLocale formatLocale, Locale runtimeLocale, boolean isStartDate1904);
50  
51      /**
52       * 経過時間を計算するときの基準日を取得する。
53       * ・1900/2/28までは、-1日ずれる。Excelは1900年は1月0日(=1899年12月31日)から始まるため、1日多い。
54       * ・1900/3/1以降は、-2日ずれず。Excel は、閏日ではない1900年2月29日(=1900年3月1日)が存在するため1日多い。
55       * @param date
56       * @param isStartDate1904
57       * @return
58       */
59      private static long getElapsedZeroTime(final Date date, final boolean isStartDate1904) {
60  
61          if(isStartDate1904) {
62              return ExcelDateUtils.getExcelZeroDateTime(isStartDate1904);
63          } else {
64              if(ExcelDateUtils.MILLISECONDS_19000301 <= date.getTime()) {
65                  // 1900-03-01以降
66                  return ExcelDateUtils.MILLISECONDS_19000101 - TimeUnit.DAYS.toMillis(2);
67              } else {
68                  return ExcelDateUtils.MILLISECONDS_19000101 - TimeUnit.DAYS.toMillis(1);
69              }
70          }
71  
72      }
73  
74      /**
75       * [h] - 24時を超える経過時間の処理
76       */
77      public static DateTerm elapsedHour(final String format) {
78          return new ElapsedHourTerm(format);
79      }
80  
81  
82      /**
83       * [m] - 60分を超える経過時間の処理
84       */
85      public static DateTerm elapsedMinute(final String format) {
86          return new ElapsedMinuteTerm(format);
87      }
88  
89      /**
90       * [s] - 60秒を超える経過時間の処理
91       */
92      public static DateTerm elapsedSecond(final String format) {
93          return new ElapsedSecondTerm(format);
94      }
95  
96      /**
97       * y - 年の場合の処理
98       */
99      public static DateTerm year(final String format) {
100         return new YearTerm(format);
101     }
102 
103     /**
104      * g - 元号の名称の場合の処理
105      */
106     public static DateTerm eraName(final String format) {
107         return new EraNameTerm(format);
108     }
109 
110     /**
111      * e - 元号の年の場合の処理
112      */
113     public static DateTerm eraYear(final String format) {
114         return new EraYearTerm(format);
115     }
116 
117     /**
118      * r - 元号の名称と年の場合の処理
119      */
120     public static DateTerm eraNameYear(final String format) {
121         return new EraNameYearTerm(format);
122     }
123 
124     /**
125      * m - 月の場合の処理
126      */
127     public static DateTerm month(final String format) {
128         return new MonthTerm(format);
129     }
130 
131     /**
132      * d - 日の場合の処理
133      */
134     public static DateTerm day(final String format) {
135         return new DayTerm(format);
136     }
137 
138     /**
139      * a - 曜日の名称場合の処理
140      */
141     public static DateTerm weekName(final String format) {
142         return new WeekName(format);
143     }
144 
145     /**
146      * n - 曜日の名称場合の処理(OpenOffice用)
147      */
148     public static DateTerm weekNameForOO(final String format) {
149         return new WeekNameForOO(format);
150     }
151 
152     /**
153      * ww - 年の週番号(OpenOffice用)
154      */
155     public static DateTerm weekNumber(final String format) {
156         return new WeekNumberTerm(format);
157     }
158 
159     /**
160      * h - 時間の場合の処理
161      * @param format
162      * @param half 12時間表示かどうか
163      */
164     public static DateTerm hour(final String format, final boolean half) {
165         return new HourTerm(format, half);
166     }
167 
168     /**
169      * m - 分の場合の処理
170      */
171     public static DateTerm minute(final String format) {
172         return new MinuteTerm(format);
173     }
174 
175     /**
176      * s - 秒の場合の処理
177      */
178     public static DateTerm second(final String format) {
179         return new SecondTerm(format);
180     }
181 
182     /**
183      * q - 四半期の場合の処理(OpenOffice用)
184      */
185     public static DateTerm quater(final String format) {
186         return new QuaterTerm(format);
187     }
188 
189     /**
190      * AM/PM - 午前/午後の場合の処理
191      */
192     public static DateTerm amPm(final String format) {
193         return new AmPmTerm(format);
194     }
195 
196     /**
197      * [h] - 24時を超える経過時間の処理
198      */
199     public static class ElapsedHourTerm extends DateTerm {
200 
201         /** ミリ秒を時間に直すための基底 */
202         private static final long BASE = 1000*60*60;
203 
204         private final String format;
205 
206         public ElapsedHourTerm(final String format) {
207             this.format = format;
208         }
209 
210         @Override
211         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
212 
213             final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
214             if(logger.isInfoEnabled()) {
215                 logger.info("ElapsedHour:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
216             }
217 
218             final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
219             final int formatLength = format.length();
220             return Utils.supplyZero(String.valueOf(time), formatLength);
221         }
222 
223         public String getFormat() {
224             return format;
225         }
226 
227     }
228 
229     /**
230      * [m] - 60分を超える経過時間の処理
231      */
232     public static class ElapsedMinuteTerm extends DateTerm {
233 
234         /** ミリ秒を分に直すための基底 */
235         private static final long BASE = 1000*60;
236 
237         private final String format;
238 
239         public ElapsedMinuteTerm(final String format) {
240             this.format = format;
241         }
242 
243         @Override
244         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
245 
246             final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
247             if(logger.isInfoEnabled()) {
248                 logger.info("ElapsedMinute:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
249             }
250 
251             final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
252             final int formatLength = format.length();
253             return Utils.supplyZero(String.valueOf(time), formatLength);
254         }
255 
256         public String getFormat() {
257             return format;
258         }
259 
260     }
261 
262     /**
263      * [s] - 60秒を超える経過時間の処理
264      */
265     public static class ElapsedSecondTerm extends DateTerm {
266 
267         /** ミリ秒を秒に直すための基底 */
268         private static final long BASE = 1000;
269 
270         private final String format;
271 
272         public ElapsedSecondTerm(final String format) {
273             this.format = format;
274         }
275 
276         @Override
277         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
278 
279             final long zeroTime = getElapsedZeroTime(cal.getTime(), isStartDate1904);
280             if(logger.isInfoEnabled()) {
281                 logger.info("ElapsedSecond:calendar={}, zeroTime={}.", ExcelDateUtils.formatDate(cal.getTime()), ExcelDateUtils.formatDate(new Date(zeroTime)));
282             }
283 
284             final long time = (long) ((cal.getTime().getTime() - zeroTime) / BASE);
285             final int formatLength = format.length();
286             return Utils.supplyZero(String.valueOf(time), formatLength);
287         }
288 
289         public String getFormat() {
290             return format;
291         }
292 
293     }
294 
295     /**
296      * y - 年の場合
297      */
298     public static class YearTerm extends DateTerm {
299 
300         private final String format;
301 
302         public YearTerm(final String format) {
303             this.format = format;
304         }
305 
306         @Override
307         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
308 
309             final String value = String.valueOf(cal.get(Calendar.YEAR));
310             final int formatLength = format.length();
311 
312             // 2桁、4桁補正する
313             if(formatLength <= 2) {
314                 return Utils.supplyZero(value, 2).substring(2);
315             } else {
316                 return Utils.supplyZero(value, 4);
317             }
318         }
319 
320         public String getFormat() {
321             return format;
322         }
323 
324     }
325 
326     /**
327      * g - 元号の名称の場合
328      */
329     public static class EraNameTerm extends DateTerm {
330 
331         private final String format;
332 
333         public EraNameTerm(final String format) {
334             this.format = format;
335         }
336 
337         @Override
338         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
339 
340             final Date date = cal.getTime();
341 
342             final Era era;
343             if(formatLocale != null) {
344                 era = eraResolver.getEra(formatLocale);
345             } else {
346                 era = eraResolver.getEra(runtimeLocale);
347             }
348 
349             if(era.isUnkndown()) {
350                 return "";
351             }
352 
353             final EraPeriod period = era.getTargetPeriod(date);
354             if(period.isUnknown()) {
355                 return "";
356             }
357 
358             final int formatLength = format.length();
359             if(formatLength == 1) {
360                 return period.getAbbrevRomanName();
361 
362             } else if(formatLength == 2) {
363                 return period.getAbbrevName();
364 
365             } else {
366                 return period.getName();
367             }
368         }
369 
370         public String getFormat() {
371             return format;
372         }
373 
374     }
375 
376     /**
377      * e - 元号の年の場合
378      */
379     public static class EraYearTerm extends DateTerm {
380 
381         private final String format;
382 
383         public EraYearTerm(final String format) {
384             this.format = format;
385         }
386 
387         @Override
388         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
389 
390             final int formatLength = format.length();
391             final Date date = cal.getTime();
392 
393             final Era era;
394             if(formatLocale != null) {
395                 era = eraResolver.getEra(formatLocale);
396             } else {
397                 era = eraResolver.getEra(runtimeLocale);
398             }
399 
400             if(era.isUnkndown()) {
401                 // 該当する時代の定義がない場合
402                 String value = String.valueOf(cal.get(Calendar.YEAR));
403                 return Utils.supplyZero(value, formatLength);
404             }
405 
406             final EraPeriod period = era.getTargetPeriod(date);
407             if(period.isUnknown()) {
408                 // 期間が不明な場合
409                 String value = String.valueOf(cal.get(Calendar.YEAR));
410                 return Utils.supplyZero(value, formatLength);
411 
412             }
413 
414             final String value = String.valueOf(period.getEraYear(cal));
415             return Utils.supplyZero(value, formatLength);
416 
417         }
418 
419         public String getFormat() {
420             return format;
421         }
422 
423     }
424 
425     /**
426      * r - 元号の名称と年の場合
427      */
428     public static class EraNameYearTerm extends DateTerm {
429 
430         private final String format;
431 
432         public EraNameYearTerm(final String format) {
433             this.format = format;
434         }
435 
436         @Override
437         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
438 
439             final int formatLength = format.length();
440             final Date date = cal.getTime();
441 
442             final Era era;
443             if(formatLocale != null) {
444                 era = eraResolver.getEra(formatLocale);
445             } else {
446                 era = eraResolver.getEra(runtimeLocale);
447             }
448 
449             if(era.isUnkndown()) {
450                 // 該当する時代の定義がない場合
451                 String value = String.valueOf(cal.get(Calendar.YEAR));
452                 return Utils.supplyZero(value, formatLength);
453             }
454 
455             final EraPeriod period = era.getTargetPeriod(date);
456             if(period.isUnknown()) {
457                 // 期間が不明な場合
458                 String value = String.valueOf(cal.get(Calendar.YEAR));
459                 return Utils.supplyZero(value, formatLength);
460 
461             }
462 
463             StringBuilder sb = new StringBuilder();
464 
465             // 元号の組み立て(2桁以上の時に元号を追加)
466             if(formatLength >= 2) {
467                 sb.append(period.getName());
468             }
469 
470             // 年の組み立て
471             final String strYear = String.valueOf(period.getEraYear(cal));
472             sb.append(Utils.supplyZero(strYear, 2));
473 
474             return sb.toString();
475         }
476 
477         public String getFormat() {
478             return format;
479         }
480 
481     }
482 
483     /**
484      * m - 月の場合
485      */
486     public static class MonthTerm extends DateTerm {
487 
488         private final String format;
489 
490         public MonthTerm(final String format) {
491             this.format = format;
492         }
493 
494         @Override
495         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
496 
497             final int value = cal.get(Calendar.MONTH) + 1;
498             final int formatLength = format.length();
499 
500             if(formatLength == 1) {
501                 return String.valueOf(value);
502 
503             } else if(formatLength == 2) {
504                 return Utils.supplyZero(String.valueOf(value), 2);
505 
506             } else if(formatLength == 3) {
507                 // 月名の先頭3文字
508                 final String key = String.format("month.%d.abbrev", value);
509                 return DateTerm.messageResolver.getMessage(formatLocale, key);
510 
511             } else if(formatLength == 4) {
512                 // 月名
513                 final String key = String.format("month.%d.name", value);
514                 return DateTerm.messageResolver.getMessage(formatLocale, key);
515 
516             } else if(formatLength == 5) {
517                 // 月名の先頭1文字
518                 final String key = String.format("month.%d.leading", value);
519                 return DateTerm.messageResolver.getMessage(formatLocale, key);
520 
521             } else {
522                 return Utils.supplyZero(String.valueOf(value), 2);
523             }
524         }
525 
526         public String getFormat() {
527             return format;
528         }
529 
530     }
531 
532     /**
533      * 曜日のインデックスを取得する。
534      * ・日曜始まりで、0から始まる。
535      * @param cal
536      * @return
537      */
538     private static int getWeekIndex(final Calendar cal) {
539         final int val = cal.get(Calendar.DAY_OF_WEEK);
540         switch(val) {
541             case Calendar.SUNDAY:
542                 return 0;
543             case Calendar.MONDAY:
544                 return 1;
545             case Calendar.TUESDAY:
546                 return 2;
547             case Calendar.WEDNESDAY:
548                 return 3;
549             case Calendar.THURSDAY:
550                 return 4;
551             case Calendar.FRIDAY:
552                 return 5;
553             case Calendar.SATURDAY:
554                 return 6;
555         }
556 
557         return 0;
558     }
559 
560     /**
561      * d - 日の場合
562      * ・dが3~4桁の場合は、英字の曜日。
563      */
564     public static class DayTerm extends DateTerm {
565 
566         private final String format;
567 
568         public DayTerm(final String format) {
569             this.format = format;
570         }
571 
572         @Override
573         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
574 
575             final int value = cal.get(Calendar.DAY_OF_MONTH);
576             final int formatLength = format.length();
577 
578             if(formatLength == 1) {
579                 return String.valueOf(value);
580 
581             } else if(formatLength == 2) {
582                 return Utils.supplyZero(String.valueOf(value), 2);
583 
584             } else if(formatLength == 3) {
585                 // 曜日の省略名
586                 final int index = getWeekIndex(cal);
587                 final String key = String.format("week.%d.abbrev", index);
588                 return messageResolver.getMessage(formatLocale, key);
589 
590             } else if(formatLength >= 4) {
591                 // 曜日の正式名
592                 final int index = getWeekIndex(cal);
593                 final String key = String.format("week.%d.name", index);
594                 return messageResolver.getMessage(formatLocale, key);
595 
596             } else {
597                return Utils.supplyZero(String.valueOf(value), 2);
598             }
599 
600         }
601 
602         public String getFormat() {
603             return format;
604         }
605 
606     }
607 
608     /**
609      * a- 日本語名称の曜日の場合
610      *
611      */
612     public static class WeekName extends DateTerm {
613 
614         private final String format;
615 
616         public WeekName(final String format) {
617             this.format = format;
618         }
619 
620         @Override
621         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
622 
623             final int index = getWeekIndex(cal);
624             final int formatLength = format.length();
625 
626             if(formatLength <= 3) {
627                 final String key = String.format("week.%d.abbrev", index);
628                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
629             } else {
630                 final String key = String.format("week.%d.name", index);
631                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
632             }
633         }
634 
635         public String getFormat() {
636             return format;
637         }
638 
639     }
640 
641     /**
642      * n- OpenOffice用の日本語名称の曜日の場合
643      *
644      */
645     public static class WeekNameForOO extends DateTerm {
646 
647         private final String format;
648 
649         public WeekNameForOO(final String format) {
650             this.format = format;
651         }
652 
653         @Override
654         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
655 
656             final int index = getWeekIndex(cal);
657             final int formatLength = format.length();
658 
659             if(formatLength <= 2) {
660                 final String key = String.format("week.%d.abbrev", index);
661                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
662             } else {
663                 final String key = String.format("week.%d.name", index);
664                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
665             }
666         }
667 
668         public String getFormat() {
669             return format;
670         }
671 
672     }
673 
674     /**
675      * ww - 年の週番号を取得する。
676      *
677      */
678     public static class WeekNumberTerm extends DateTerm {
679 
680         private final String format;
681 
682         public WeekNumberTerm(final String format) {
683             this.format = format;
684         }
685 
686         @Override
687         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
688 
689             final int val = cal.get(Calendar.WEEK_OF_YEAR);
690             return String.valueOf(val);
691 
692         }
693 
694         public String getFormat() {
695             return format;
696         }
697 
698     }
699 
700     /**
701      * h - 時間の場合
702      */
703     public static class HourTerm extends DateTerm {
704 
705         private final String format;
706 
707         /**
708          * 12時間表示かどうか。
709          */
710         private final boolean half;
711 
712         public HourTerm(final String format, final boolean half) {
713             this.format = format;
714             this.half = half;
715         }
716 
717         @Override
718         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
719 
720             final String value;
721             if(isHalf()) {
722                 value = String.valueOf(cal.get(Calendar.HOUR));
723             } else {
724                 value = String.valueOf(cal.get(Calendar.HOUR_OF_DAY));
725             }
726 
727             final int formatLength = format.length();
728             return Utils.supplyZero(value, formatLength);
729 
730         }
731 
732         public boolean isHalf() {
733             return half;
734         }
735 
736         public String getFormat() {
737             return format;
738         }
739 
740     }
741 
742     /**
743      * m - 分の場合
744      */
745     public static class MinuteTerm extends DateTerm {
746 
747         private final String format;
748 
749         public MinuteTerm(final String format) {
750             this.format = format;
751         }
752 
753         @Override
754         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
755 
756             final String value = String.valueOf(cal.get(Calendar.MINUTE));
757             final int formatLength = format.length();
758             return Utils.supplyZero(value, formatLength);
759 
760         }
761 
762         public String getFormat() {
763             return format;
764         }
765 
766     }
767 
768     /**
769      * s - 秒の場合
770      */
771     public static class SecondTerm extends DateTerm {
772 
773         private final String format;
774 
775         public SecondTerm(final String format) {
776             this.format = format;
777         }
778 
779         @Override
780         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
781 
782             final String value = String.valueOf(cal.get(Calendar.SECOND));
783             final int formatLength = format.length();
784             return Utils.supplyZero(value, formatLength);
785 
786         }
787 
788         public String getFormat() {
789             return format;
790         }
791 
792     }
793 
794     /**
795      * AM/PM - 午前/午後の場合
796      */
797     public static class AmPmTerm extends DateTerm {
798 
799         private final String format;
800 
801         private final String am;
802 
803         private final String pm;
804 
805         public AmPmTerm(final String format) {
806             this.format = format;
807 
808             String[] split = format.split("/");
809             if(split.length >= 2) {
810                 this.am = split[0];
811                 this.pm = split[1];
812             } else {
813                 this.am = "AM";
814                 this.pm = "PM";
815             }
816         }
817 
818         @Override
819         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
820 
821             final int val = cal.get(Calendar.AM_PM);
822             if(val == Calendar.AM) {
823                 return messageResolver.getMessage(formatLocale, "day.am.name", am);
824 
825             } else {
826                 return messageResolver.getMessage(formatLocale, "day.pm.name", pm);
827 
828             }
829 
830         }
831 
832         public String getFormat() {
833             return format;
834         }
835 
836         public String getAm() {
837             return am;
838         }
839 
840         public String getPm() {
841             return pm;
842         }
843 
844     }
845 
846     /**
847      * q - 四半期の場合
848      */
849     public static class QuaterTerm extends DateTerm {
850 
851         private final String format;
852 
853         public QuaterTerm(final String format) {
854             this.format = format;
855         }
856 
857         @Override
858         public String format(final Calendar cal, final MSLocale formatLocale, final Locale runtimeLocale, final boolean isStartDate1904) {
859 
860             final int index = (cal.get(Calendar.MONTH) / 3) + 1;
861 
862             // Excelではなく実行環境のロケールによっても変わるため注意
863             if(format.length() == 1) {
864                 final String key = String.format("quaterTerm.%d.abbrev", index);
865                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
866 
867             } else {
868                 final String key = String.format("quaterTerm.%d.name", index);
869                 return messageResolver.getMessage(formatLocale, runtimeLocale, key);
870             }
871 
872         }
873 
874     }
875 }