7.3. 日付操作(JSR-310 Date and Time API)¶
7.3.1. Overview¶
java.util.Date
, java.util.Calendar
に比べて、Note
JSR-310 Date and Time APIはJava8から導入されたため、 Java8未満の環境は、Joda Timeの利用を推奨している。 Joda Timeの利用方法は、 日付操作(Joda Time) を参照されたい。
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>
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);