Java 8では、日付と時刻を処理するための新しい Java.time APIが追加されました( JSR 310 )。
私は文字列として日付と時刻を持っています(例:"2014-04-08 12:30"
)。与えられた文字列から LocalDateTime
のインスタンスを取得するにはどうすればいいですか?
LocalDateTime
オブジェクトの処理を終えた後:LocalDateTime
インスタンスを上記の形式と同じ形式の文字列に変換する方法を教えてください。
解析日時
文字列からLocalDateTime
オブジェクトを作成するには、static LocalDateTime.parse()
メソッドを使います。パラメータとして文字列と DateTimeFormatter
を取ります。 DateTimeFormatter
は日付/時刻パターンを指定するために使用されます。
String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);
フォーマット日時
LocalDateTime
オブジェクトからフォーマットされた文字列を作成するには、format()
メソッドを使います。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"
DateTimeFormatter
で定数として定義されている、よく使われる日付/時刻フォーマットがいくつかあることに注意してください。例:DateTimeFormatter.ISO_DATE_TIME
を使用して上記のLocalDateTime
インスタンスをフォーマットすると、ストリング"1986-04-08T12:30:00"
が得られます。
parse()
メソッドとformat()
メソッドは、すべての日付/時刻関連オブジェクトに使用できます(例:LocalDate
またはZonedDateTime
)
String
が ISO-8601 format )の場合は、パターンを指定せずにString
にLocalDate.parse()
またはLocalDateTime.parse()
を使用することもできます。
例えば、
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);
String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);
出力 、
Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30
他の日付パターンを処理する必要がある場合にのみDateTimeFormatter
を使用します。例えば、dd MMM uuuuは、月の日(2桁)、3文字の月(1月、2月、3月、...)、および4桁の年:
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);
出力
04 Aug 2015 parses to 2015-08-04
DateTimeFormatter
オブジェクトは双方向です。入力を解析して出力をフォーマットすることができます。
String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));
出力
2015-08-04 formats as 04 Aug 2015
(complete DateFormatterのフォーマットと解析のためのパターンのリスト を参照)
Symbol Meaning Presentation Examples
------ ------- ------------ -------
G era text AD; Anno Domini; A
u year year 2004; 04
y year-of-era year 2004; 04
D day-of-year number 189
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
Q/q quarter-of-year number/text 3; 03; Q3; 3rd quarter
Y week-based-year year 1996; 96
w week-of-week-based-year number 27
W week-of-month number 4
E day-of-week text Tue; Tuesday; T
e/c localized day-of-week number/text 2; 02; Tue; Tuesday; T
F week-of-month number 3
a am-pm-of-day text PM
h clock-hour-of-am-pm (1-12) number 12
K hour-of-am-pm (0-11) number 0
k clock-hour-of-am-pm (1-24) number 0
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
A milli-of-day number 1234
n nano-of-second number 987654321
N nano-of-day number 1234000000
V time-zone ID zone-id America/Los_Angeles; Z; -08:30
z time-zone name zone-name Pacific Standard Time; PST
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
X zone-offset 'Z' for zero offset-X Z; -08; -0830; -08:30; -083015; -08:30:15;
x zone-offset offset-x +0000; -08; -0830; -08:30; -083015; -08:30:15;
Z zone-offset offset-Z +0000; -0800; -08:00;
p pad next pad modifier 1
' escape for text delimiter
'' single quote literal '
[ optional section start
] optional section end
# reserved for future use
{ reserved for future use
} reserved for future use
上記の両方の答えは、文字列パターンに関する質問を非常によく説明しています。ただし、 ISO 8601 を使用している場合に備えて、LocalDateTimeはすでに用意されているので、DateTimeFormatter
を適用する必要はありません。
LocalDateTimeをタイムゾーンISO8601文字列に変換する
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); //you might use a different zone
String iso8601 = zdt.toString();
ISO 8601文字列からLocalDateTimeへの変換
String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();
日付と時刻を含む文字列を特定の時点(Javaでは " Instant
"と呼びます)に解析することは非常に複雑です。 Javaは、これに何度か取り組んでいます。最新のJava.time
とJava.time.chrono
は、ほとんどすべてのニーズをカバーしています( Time Dilation :)を除く)。
ただし、その複雑さは多くの混乱をもたらします。
日付解析を理解するための鍵は次のとおりです。
LocalDateTime
、ZonedDateTime
et al。とても複雑タイムゾーン があります。タイムゾーンとは、基本的に、地球の表面の「ストライプ」* [1]であり、その当局は、いつどのオフセットを持っているかという同じルールに従います。これには夏時間の規則が含まれます。
タイムゾーンは、主に誰が誰を征服するかに基づいて、さまざまな地域の時間とともに変化します。また、1つのタイムゾーンのルール 経時変化 も同様です。
時間オフセットがあります。タイムゾーンは、たとえばタイムゾーンである可能性があるため、タイムゾーンとは異なります。 「プラハ」ですが、夏時間と冬時間のオフセットがあります。
タイムゾーン付きのタイムスタンプを取得する場合、オフセットは、その年のどの部分に応じて異なる場合があります。うるう時間中、タイムスタンプは2つの異なる時間を意味する場合があるため、追加情報なしで、確実に変換できません。
注: timestamp は、「日付と時刻、またはオプションでタイムゾーンと時刻オフセットを含む文字列」を意味します。
複数のタイムゾーンが特定の期間に同じタイムオフセットを共有する場合があります。たとえば、夏時間オフセットが有効でない場合、GMT/UTCタイムゾーンは「ロンドン」タイムゾーンと同じです。
それをもう少し複雑にするために(しかし、それはあなたのユースケースにとってあまり重要ではありません):
2040-12-31 24:00:00
は有効な日時になる可能性があります。)これには、システムが日付変換を正しく行うために使用するメタデータの定期的な更新が必要です。例えば。 Linuxでは、これらの新しいデータを含むJavaパッケージの定期的な更新を取得します。更新は、過去と将来のタイムスタンプの両方で以前の動作を常に保持するとは限りません。したがって、異なるバージョンのソフトウェアで実行している場合、 を比較して、あるタイムゾーンの変更に関する2つのタイムスタンプを解析すると、異なる結果が得られる場合があります これは、影響を受けるタイムゾーンと他のタイムゾーンの比較にも適用されます。
これによりソフトウェアにバグが発生する場合は、 UNIX timestamp などの複雑なルールのないタイムスタンプの使用を検討してください。
7のため、将来の日付について、正確に日付を変換することはできません。そのため、たとえば、8524-02-17 12:00:00
の現在の解析は、将来の解析から数秒遅れることがあります。
Java.util.Date
しかありませんでしたが、年、月、日、時刻だけがあると仮定すると、少し素朴なアプローチがありました。これはすぐに十分ではありませんでした。Java.sql.Date
が導入されましたが、独自の制限がありました。Calendar
APIが導入されました。Java.time
での対処方法タイムスタンプ文字列を使用する場合、含まれる情報を知る必要があります。 これが重要なポイントです。これが正しくない場合、「インスタントを作成できません」または「ゾーンオフセットが見つかりません」または「不明なゾーンID」など.
日付と時刻が含まれていますか?
時間オフセットはありますか?
時間オフセットは+hh:mm
部分です。 +00:00
は、「Zulu時間」としてZ
、協定世界時としてUTC
、またはグリニッジ標準時としてGMT
に置き換えられる場合があります。これらはタイムゾーンも設定します。
これらのタイムスタンプには、 OffsetDateTime
を使用します。
タイムゾーンはありますか?
これらのタイムスタンプには、 ZonedDateTime
を使用します。
ゾーンは、
タイムゾーンのリストは、ICAANが支援する "TZデータベース" によってコンパイルされます。
ZoneId
のjavadocによると、ゾーンIDは、何らかの方法でZ
およびoffsetとして指定することもできます。これが実際のゾーンにどのようにマッピングされるかわかりません。 TZのみを持つタイムスタンプが、うるう時のタイムオフセットの変化に該当する場合、それはあいまいであり、解釈はResolverStyle
の対象となります。以下を参照してください。
どちらにもない場合、欠落しているコンテキストが想定または無視されます。そして、消費者が決定する必要があります。したがって、LocalDateTime
として解析し、欠落している情報を追加してOffsetDateTime
に変換する必要があります。
Duration
を参照)場合、またはわからないが実際には関係ない場合(ローカルバスのスケジュールなど)。部分時間情報
LocalDate
、LocalTime
、OffsetTime
、MonthDay
、Year
、またはYearMonth
を取り出すことができます。完全な情報がある場合は、 Java.time.Instant
を取得できます。これは、OffsetDateTime
とZonedDateTime
の間の変換にも内部的に使用されます。
DateTimeFormatter
には詳細なドキュメントがあり、タイムスタンプ文字列の解析と文字列へのフォーマットの両方が可能です。
pre-created DateTimeFormatter
s は、すべての標準タイムスタンプ形式をカバーする必要があります。たとえば、ISO_INSTANT
は2011-12-03T10:15:30.123457Z
を解析できます。
特別な形式がある場合は、 独自のDateTimeFormatter (パーサーでもあります)を作成できます。
private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
.toFormatter();
DateTimeFormatter
のソースコードを見て、DateTimeFormatterBuilder
を使用してビルドする方法に触発されることをお勧めします。また、パーサーがLENIENT、SMARTまたはSTRICTのいずれであるかを制御するResolverStyle
も、フォーマットとあいまいな情報に注目してください。
現在、よくある間違いは、TemporalAccessor
の複雑さです。これは、開発者がSimpleDateFormatter.parse(String)
を扱うためにどのように使用されたかに由来します。そう、DateTimeFormatter.parse("...")
はTemporalAccessor
を提供します。
// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");
しかし、前のセクションからの知識を備えていれば、必要なタイプに便利に解析できます。
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);
実際にDateTimeFormatter
も必要ありません。解析するタイプには、parse(String)
メソッドがあります。
OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");
TemporalAccessor
に関しては、文字列にどのような情報があるかについて漠然とした考えがあり、実行時に決定したい場合に使用できます。
私はあなたの魂に理解の光を当てることを望みます:)
注:Java.time
からJava 6および7へのバックポートがあります: ThreeTen-Backport 。 Androidの場合、 ThreeTenABP になります。
[1]ストライプではないだけでなく、奇妙な極端な部分もあります。たとえば、 いくつかの隣接する太平洋の島々 には、+ 14:00と-11:00のタイムゾーンがあります。つまり、ある島では5月1日午後3時、別の島ではそれほど遠くない、まだ4月30日PM(正しくカウントした場合:))