7.3. 日付操作(JSR-310 Date and Time API)¶
Caution
本バージョンの内容は既に古くなっています。最新のガイドラインはこちらからご参照ください。
7.3.1. Overview¶
java.util.Date , java.util.Calendar に比べて、7.3.2. How to use¶
java.time.LocalDate , java.time.LocalTime , java.time.LocalDateTime を中心に説明を進めるが、主要な日時操作については、各クラスで提供されるメソッドの接頭辞が同一であるため、適時クラス名を置き換えて解釈されたい。| クラス名 | 説明 | 主なファクトリメソッド |
|---|---|---|
| タイムゾーン・時差の情報を持たない日付・時刻の操作を行うクラス | now 現在日時で生成of 任意日時で生成parse 日時文字列から生成from 日時情報を持つ他オブジェクトから生成 |
|
| タイムゾーン・時差を考慮した日付・時刻の操作を行うクラス | 同上 | |
| 和暦の操作を行うクラス | 同上 |
| クラス名 | 説明 | 主なファクトリメソッド |
|---|---|---|
| 日時ベース、時間ベースの期間を扱うクラス | between 日時情報を持つ2つのオブジェクトの差から生成from 時間量を持つ他オブジェクトから生成of 任意期間で生成 |
| クラス名 | 説明 | 主なファクトリメソッド |
|---|---|---|
| 日時のフォーマットに関する操作を行うクラス | ofPattern 指定されたパターンでフォーマッタを生成 |
Note
本ガイドラインで触れなかった内容を含め、詳細は Javadoc を参照されたい。
Note
Date and Time APIのクラスは、immutableである(日時計算等の結果は、新規オブジェクトであり、計算元オブジェクトに変化は起きない)。
7.3.2.1. 日時取得¶
7.3.2.1.1. 現在日時で取得¶
java.time.LocalTime , java.time.LocalDate , java.time.LocalDateTime を使い分けること。以下に例を示す。- 時刻のみ取得したい場合は
java.time.LocalTimeを使用する。
LocalTime localTime = LocalTime.now();
- 日付のみ取得したい場合は
java.time.LocalDateを使用する。
LocalDate localDate = LocalDate.now();
- 日付・時刻を取得したい場合は
java.time.LocalDateTimeを使用する。
LocalDateTime localDateTime = LocalDateTime.now();
7.3.2.1.2. 年月日時分秒を指定して取得¶
- 時刻を指定して
java.time.LocalTimeを取得する。
// 23:30:59
LocalTime localTime = LocalTime.of(23, 30, 59);
- 日付を指定して
java.time.LocalDateを取得する。
// 2015/12/25
LocalDate localDate = LocalDate.of(2015, 12, 25);
- 日付・時刻)を指定して
java.time.LocalDateTimeを取得する。
// 2015/12/25 23:30:59
LocalDateTime localDateTime = LocalDateTime.of(2015, 12, 25, 23, 30, 59);
java.time.temporal.TemporalAdjusters を使うことで様々な日時を取得することができる。// LeapYear(2012/2)
LocalDate localDate1 = LocalDate.of(2012, 2, 1);
// Last day of month(2012/2/29)
LocalDate localDate2 = localDate1.with(TemporalAdjusters.lastDayOfMonth());
// Next monday(2012/2/6)
LocalDate localDate3 = localDate1.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
Note
java.util.Calendar の仕様とは異なり、Monthは 1 始まりである。
7.3.2.1.3. タイムゾーンを指定する場合の日時取得¶
java.time.OffsetTime , java.time.OffsetDateTime , java.time.ZonedDateTime を使い分けること。- 時刻+UTCとの時差を取得したい場合は、
java.time.OffsetTimeを使用する。
// Ex, 12:30:11.567+09:00
OffsetTime offsetTime = OffsetTime.now();
- 日付・時刻+UTCとの時差を取得したい場合は
java.time.OffsetDateTimeを使用する。
// Ex, 2015-12-25T12:30:11.567+09:00
OffsetDateTime offsetDateTime = OffsetDateTime.now();
- 日付・時刻+UTCとの時差・地域を取得したい場合は
java.time.ZonedDateTimeを使用する。
// Ex, 2015-12-25T12:30:11.567+09:00[Asia/Tokyo]
ZonedDateTime zonedDateTime = ZonedDateTime.now();
java.time.ZoneId を引数に設定することで、タイムゾーンを考慮した現在日時が取得できる。java.time.ZoneId の例を示す。ZoneId zoneIdTokyo = ZoneId.of("Asia/Tokyo");
OffsetTime offsetTime = OffsetTime.now(zoneIdTokyo);
java.time.ZoneId は地域名/地名形式で定義する方法や、UTCからの時差で定義する方法がある。ZoneId.of("Asia/Tokyo");
ZoneId.of("UTC+01:00");
java.time.OffsetDateTime , java.time.ZonedDateTime の2クラスは用途が似ているが、具体的には以下のような違いがある。| クラス名 | 説明 |
|---|---|
java.time.OffsetDateTime |
定量値(時差のみ)を持つため、各地域の時間の概念に変化がある場合も、システムに変化が起こらない。 |
java.time.ZonedDateTime |
時差に加えて地域の概念があるため、各地域の時間の概念に変化があった場合、システムに変化が起こる。(政策としてサマータイム導入される場合など) |
7.3.2.2. 期間¶
7.3.2.2.1. 期間の取得¶
java.time.Period 、時間ベースの期間を扱う場合は、 java.time.Duration を使用する。java.time.Duration で表される1日は厳密に24時間であるため、サマータイムの変化が解釈されずに想定通りの結果にならない可能性がある。java.time.Period はサマータイムなどの概念を考慮した1日を表すため、サマータイムを扱うシステムであっても誤差は生じない。LocalDate date1 = LocalDate.of(2010, 01, 15);
LocalDate date2 = LocalDate.of(2011, 03, 18);
LocalTime time1 = LocalTime.of(11, 50, 50);
LocalTime time2 = LocalTime.of(12, 52, 53);
// One year, two months and three days.
Period pd = Period.between(date1, date2);
// One hour, two minutes and three seconds.
Duration dn = Duration.between(time1, time2);
Note
ofメソッドを利用して、期間を指定して生成する方法もある。詳細は Period, DurationのJavadoc を参照されたい。
7.3.2.3. 型変換¶
7.3.2.3.1. Date and Time APIの各クラスの相互運用性¶
java.time.LocalTime , java.time.LocalDate , java.time.LocalDateTime はそれぞれ容易に変換が可能である。以下に例を示す。java.time.LocalTimeからjava.time.LocalDateTimeへの変換。
// Ex. 12:10:30
LocalTime localTime = LocalTime.now();
// 2015-12-25 12:10:30
LocalDateTime localDateTime = localTime.atDate(LocalDate.of(2015, 12, 25));
java.time.LocalDateからjava.time.LocalDateTimeへの変換。
// Ex. 2012-12-25
LocalDate localDate = LocalDate.now();
// 2015-12-25 12:10:30
LocalDateTime localDateTime = localDate.atTime(LocalTime.of(12, 10, 30));
java.time.LocalDateTimeからjava.time.LocalTime,java.time.LocalDateへの変換。
// Ex. 2015-12-25 12:10:30
LocalDateTime localDateTime = LocalDateTime.now();
// 12:10:30
LocalTime localTime = localDateTime.toLocalTime();
// 2012-12-25
LocalDate localDate = localDateTime.toLocalDate();
java.time.OffsetTime , java.time.OffsetDateTime , java.time.ZonedDateTime もそれぞれ容易に変換が可能である。以下に例を示す。java.time.OffsetTimeから、java.time.OffsetDateTimeへの変換。
// Ex, 12:30:11.567+09:00
OffsetTime offsetTime = OffsetTime.now();
// 2015-12-25T12:30:11.567+09:00
OffsetDateTime offsetDateTime = offsetTime.atDate(LocalDate.of(2015, 12, 25));
java.time.OffsetDateTimeからjava.time.ZonedDateTimeへの変換。
// Ex, 2015-12-25T12:30:11.567+09:00
OffsetDateTime offsetDateTime = OffsetDateTime.now();
// 2015-12-25T12:30:11.567+09:00[Asia/Tokyo]
ZonedDateTime zonedDateTime = offsetDateTime.atZoneSameInstant(ZoneId.of("Asia/Tokyo"));
java.time.ZonedDateTimeからjava.time.OffsetDateTime,java.time.OffsetTimeへの変換。
// Ex, 2015-12-25T12:30:11.567+09:00[Asia/Tokyo]
ZonedDateTime zonedDateTime = ZonedDateTime.now();
// 2015-12-25T12:30:11.567+09:00
OffsetDateTime offsetDateTime = zonedDateTime.toOffsetDateTime();
// 12:30:11.567+09:00
OffsetTime offsetTime = zonedDateTime.toOffsetDateTime().toOffsetTime();
java.time.LocalTime を java.time.OffsetTime に変換することも可能である。// Ex, 12:30:11.567
LocalTime localTime = LocalTime.now();
// 12:30:11.567+09:00
OffsetTime offsetTime = localTime.atOffset(ZoneOffset.ofHours(9));
LocalTime から LocalDateTime の変換であれば日付の情報が不足している の要領)を加えることで別のクラスへ変換が可能である。7.3.2.3.2. java.util.Dateとの相互運用性¶
java.time.LocalDate 等のクラスは、java.time.Instant に変換したうえで java.util.Date に変換することが可能である。java.time.LocalDateTimeから、java.util.Dateへの変換。
LocalDateTime localDateTime = LocalDateTime.now();
Instant instant = localDateTime.toInstant(ZoneOffset.ofHours(9));
Date date = Date.from(instant);
java.util.Dateからjava.time.LocalDateTimeへの変換。
Date date = new Date();
Instant instant = date.toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
Note
java.time.LocalTime,java.time.LocalDateはInstant値を持たないため、一度java.time.LocalDateTimeに変換する必要がある。
7.3.2.3.3. java.sql パッケージとの相互運用性¶
java.sql パッケージに改修が入り、 java.time パッケージとの相互変換メソッドが定義された。java.sql.Dateからjava.time.LocalDateへの変換。
java.sql.Date date = new java.sql.Date(System.currentTimeMillis());
LocalDate localDate = date.toLocalDate();
java.time.LocalDateからjava.sql.Dateへの変換。
LocalDate localDate = LocalDate.now();
java.sql.Date date = java.sql.Date.valueOf(localDate);
java.sql.Timeからjava.time.LocalTimeへの変換。
java.sql.Time time = new java.sql.Time(System.currentTimeMillis());
LocalTime localTime = time.toLocalTime();
java.time.LocalTimeからjava.sql.Timeへの変換。
LocalTime localTime = LocalTime.now();
java.sql.Time time = java.sql.Time.valueOf(localTime);
java.sql.Timestampからjava.time.LocalDateTimeへの変換。
java.sql.Timestamp timestamp = new java.sql.Timestamp(System.currentTimeMillis());
LocalDateTime localDateTime = timestamp.toLocalDateTime();
java.time.LocalDateTimeからjava.sql.Timestampへの変換。
LocalDateTime localDateTime = LocalDateTime.now();
java.sql.Timestamp timestamp = java.sql.Timestamp.valueOf(localDateTime);
7.3.2.3.4. org.terasoluna.gfw.common.date パッケージの利用方法¶
org.terasoluna.gfw.common.date.ClassicDateFactory と java.sql.Date を利用することで、 java.time.LocalDate を生成できる。java.time.LocalTime , java.time.LocalDateTime クラスに関しても、 java.time.LocalDate から変換することで生成できる。bean定義ファイル([projectname]-env.xml)
<bean id="dateFactory" class="org.terasoluna.gfw.common.date.DefaultClassicDateFactory" />
Javaクラス
@Inject
ClassicDateFactory dateFactory;
public DateFactorySample getSystemDate() {
java.sql.Date date = dateFactory.newSqlDate();
LocalDate localDate = date.toLocalDate();
// omitted
}
Note
Date and Time APIに対応したDate Factoryは今後追加予定である。
7.3.2.3.5. 文字列へのフォーマット¶
toString メソッドを使用する方法と、java.time.fomat.DateTimeFormatter を使用する方法がある。java.time.fomat.DateTimeFormatter を使用し様々な日時文字列へ変換することが出来る。java.time.fomat.DateTimeFormatter は、事前定義されたISOパターンのフォーマッタを利用する方法と、任意のパターンのフォーマットを定義して利用する方法がある。DateTimeFormatter formatter1 = DateTimeFormatter.BASIC_ISO_DATE;
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("G uuuu/MM/dd E")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);
Locale と ResolverStyle (厳密性)を定義できる。Locale のデフォルト値はシステムによって変化するため、初期化時に設定することが望ましい。ResolverStyle (厳密性)は ofPattern メソッドを使う場合、デフォルトで ResolverStyle.SMART が設定されるが、本ガイドラインでは予期せぬ挙動が起こらないよう、厳密に日付を解釈する ResolverStyle.STRICT の設定を推奨している。(ISOパターンのフォーマッタを利用する場合は ResolverStyle.STRICT が設定されている)yyyy は暦に対する年を表すため、暦によって解釈が異なる(西暦なら2015と解釈されるが、和暦なら0027と解釈される)。DateTimeFormatter formatter1 = DateTimeFormatter.BASIC_ISO_DATE;
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("G uuuu/MM/dd E")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);
LocalDate localDate1 = LocalDate.of(2015, 12, 25);
// "2015-12-25"
System.out.println(localDate1.toString());
// "20151225"
System.out.println(formatter1.format(localDate1));
// "西暦 2015/12/25 金"
System.out.println(formatter2.format(localDate1));
fmt:formatDate タグは、java.util.Date と、 java.util.TimeZone オブジェクトのみを扱うため、Controllerクラス
@Controller
public class HomeController {
@RequestMapping(value = "/", method = {RequestMethod.GET, RequestMethod.POST})
public String home(Model model, Locale locale) {
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu/MM/dd")
.withLocale(locale)
.withResolverStyle(ResolverStyle.STRICT);
LocalDate localDate1 = LocalDate.now();
model.addAttribute("currentDate", localDate1.toString());
model.addAttribute("formattedCurrentDateString", dateFormatter.format(localDate1));
// omitted
}
}
jspファイル
<p>currentDate = ${f:h(currentDate)}.</p>
<p>formattedCurrentDateString = ${f:h(formattedCurrentDateString)}.</p>
出力結果例(html)
<p>currentDate = 2015-12-25.</p>
<p>formattedCurrentDateString = 2015/12/25.</p>
Note
Java SE 11ではJava SE 8と日付の文字列表現が異なる場合がある。 Java SE 8と同様に表現するにはデフォルトで使用されるロケール・データの変更を参照されたい。
7.3.2.3.6. 文字列からのパース¶
java.time.fomat.DateTimeFormatter を用いることで、様々な日付文字列をDate and Time APIのクラスへ変換することが出来る。DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("uuuu/MM/dd")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("HH:mm:ss")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);
LocalDate localDate = LocalDate.parse("2015/12/25", formatter1);
LocalTime localTime = LocalTime.parse("14:09:20", formatter2);
7.3.2.4. 日付操作¶
7.3.2.4.1. 日時の計算¶
plus メソッドと minus メソッドが提供されている。- 時間の計算を行う場合の例。
LocalTime localTime = LocalTime.of(20, 30, 50);
LocalTime plusHoursTime = localTime.plusHours(2);
LocalTime plusMinutesTime = localTime.plusMinutes(10);
LocalTime minusSecondsTime = localTime.minusSeconds(15);
- 日付の計算を行う場合の例。
LocalDate localDate = LocalDate.of(2015, 12, 25);
LocalDate plusYearsDate = localDate.plusYears(10);
LocalDate minusMonthsTime = localDate.minusMonths(1);
LocalDate plusDaysTime = localDate.plusDays(3);
Note
plusメソッドに負数を渡すと、minusメソッドを利用した場合と同様の結果が得られる。minusメソッドも同様。
7.3.2.4.2. 日時の比較¶
- 時間の比較を行う場合の例。
LocalTime morning = LocalTime.of(7, 30, 00);
LocalTime daytime = LocalTime.of(12, 00, 00);
LocalTime evening = LocalTime.of(17, 30, 00);
daytime.isBefore(morning); // false
morning.isAfter(evening); // true
evening.equals(LocalTime.of(17, 30, 00)); // true
daytime.isBefore(daytime); // false
morning.isAfter(morning); // false
- 日付の比較を行う場合の例。
LocalDate may = LocalDate.of(2015, 6, 1);
LocalDate june = LocalDate.of(2015, 7, 1);
LocalDate july = LocalDate.of(2015, 8, 1);
may.isBefore(june); // true
june.isAfter(july); // false
july.equals(may); // false
may.isBefore(may); // false
june.isAfter(june); // false
Interval に当たるクラスは存在しない。7.3.2.4.3. 日時の判定¶
- 妥当な日時文字列かを判定したい場合、
java.time.format.DateTimeParseExceptionの発生有無で判定できる。
String strDateTime = "aabbcc";
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HHmmss")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);;
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuMMdd")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT);;
try {
// DateTimeParseException
LocalTime localTime = LocalTime.parse(strDateTime, timeFormatter);
}
catch (DateTimeParseException e) {
System.out.println("Invalid time string !!");
}
try {
// DateTimeParseException
LocalDate localDate = LocalDate.parse(strDateTime, dateFormatter);
}
catch (DateTimeParseException e) {
System.out.println("Invalid date string !!");
}
- うるう年かを判定したい場合、
java.time.LocalDateのisLeapYearメソッドで判定できる。
LocalDate date1 = LocalDate.of(2012, 1, 1);
LocalDate date2 = LocalDate.of(2015, 1, 1);
date1.isLeapYear(); // true
date2.isLeapYear(); // false
7.3.2.4.4. 年月日時分秒の取得¶
get メソッドを利用する。LocalDate localDate = LocalDate.of(2015, 2, 1);
// 2015
int year = localDate.getYear();
// 2
int month = localDate.getMonthValue();
// 1
int dayOfMonth = localDate.getDayOfMonth();
// 32 ( day of year )
int dayOfYear = localDate.getDayOfYear();
7.3.2.5. 和暦(JapaneseDate)¶
java.time.chrono.JapaneseDate という、和暦を扱うクラスが提供されている。Note
java.time.chrono.JapaneseDateは、グレゴリオ暦が導入された明治6年(西暦1873年)より前は利用できない。
7.3.2.5.1. 和暦の取得¶
java.time.LocalDate と同様に、 now メソッド, of メソッドで取得できる。java.time.chrono.JapaneseEra クラスを使うことで、和暦を指定した取得も行うことが出来る。JapaneseDate japaneseDate1 = JapaneseDate.now();
JapaneseDate japaneseDate2 = JapaneseDate.of(2015, 12, 25);
JapaneseDate japaneseDate3 = JapaneseDate.of(JapaneseEra.HEISEI, 27, 12, 25);
// DateTimeException
JapaneseDate japaneseDate = JapaneseDate.of(1500, 1, 1);
7.3.2.5.2. 文字列へのフォーマット¶
java.time.fomat.DateTimeFormatter を用いることで、和暦日付へ変換することが出来る。利用の際には、 DateTimeFormatter#withChronology メソッドで暦を java.time.chrono.JapaneseChronology に設定する。DateTimeFormatter formatter = DateTimeFormatter.ofPattern("Gppy年ppM月ppd日")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(JapaneseChronology.INSTANCE);
JapaneseDate japaneseDate = JapaneseDate.of(1992, 1, 1);
// "平成 4年 1月 1日"
System.out.println(formatter.format(japaneseDate));
7.3.2.5.3. 文字列からのパース¶
java.time.fomat.DateTimeFormatter を用いることで、和暦文字列から java.time.chrono.JapaneseDate へ変換することが出来る。DateTimeFormatter formatter = DateTimeFormatter.ofPattern("Gy年MM月dd日")
.withLocale(Locale.JAPANESE)
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(JapaneseChronology.INSTANCE);
JapaneseDate japaneseDate1 = JapaneseDate.from(formatter.parse("平成27年12月25日"));
JapaneseDate japaneseDate2 = JapaneseDate.from(formatter.parse("明治6年01月01日"));
7.3.2.5.4. 西暦・和暦の変換¶
java.time.LocalDate からの変換を容易に行える。LocalDate localDate = LocalDate.of(2015, 12, 25);
JapaneseDate jpDate = JapaneseDate.from(localDate);