HTML5 datetime
入力フィールドから値として返された日付を解析しようとしています。 Operaで例を確認してください。返される日付は次のようになります:2011-05-03T11:58:01Z
。
これをJava日付またはカレンダーオブジェクトに解析します。
理想的には、ソリューションには次のものが必要です。
GoogleがGoogle HTTPクライアントライブラリにRfc3339パーサーを実装していることがわかりました
テスト済み。これは、さまざまなサブ秒の時間フラグメントを解析するのに適しています。
import Java.time.ZoneId;
import Java.time.format.DateTimeFormatter;
import Java.util.Date;
import com.google.api.client.util.DateTime;
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
.withZone(ZoneId.of("UTC"));
@Test
public void test1e9Parse() {
String timeStr = "2018-04-03T11:32:26.553955473Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
@Test
public void test1e3Parse() {
String timeStr = "2018-04-03T11:32:26.553Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.553Z");
}
@Test
public void testEpochSecondsParse() {
String timeStr = "2018-04-03T11:32:26Z";
DateTime dateTime = DateTime.parseRfc3339(timeStr);
long millis = dateTime.getValue();
String result = formatter.format(new Date(millis).toInstant());
assert result.equals("2018-04-03T11:32:26.000Z");
}
Instant.parse( "2011-05-03T11:58:01Z" )
実際、 RFC 3339 は、実際の標準、 ISO 8601 の自己宣言した「プロファイル」にすぎません。
RFCは、意図的にISO 8601に違反してゼロ時間(-00:00
)の負のオフセットを許可し、意味が「オフセット不明」であることを意味するという点で異なります。そのセマンティクスは、私には非常に悪い考えのようです。私は、より賢明なISO 8601ルールを守ることをお勧めします。 ISO 8601では、オフセットがまったくないということは、オフセットが不明であることを意味します。これは明らかな意味ですが、RFCルールは厄介です。
最新のJava.timeクラスは、文字列の解析/生成時にデフォルトでISO 8601形式を使用します。
入力文字列は、UTCでの瞬間を表します。末尾のZ
はZulu
の略で、UTCを意味します。
Instant
(Date
ではない)最新のクラスInstant
は、UTCにおける瞬間を表します。このクラスは Java.util.Date
を置き換え、ミリ秒ではなくナノ秒のより細かい分解能を使用します。
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
ZonedDateTime
(Calendar
ではない)特定の地域(タイムゾーン)の人々が使用する実時間を通じて同じ瞬間を確認するには、ZoneId
を適用してZonedDateTime
を取得します。このクラスZonedDateTime
は、 Java.util.Calendar
クラスを置き換えます。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
可能な場合は、従来の日時クラスを使用しないことを強くお勧めします。ただし、Java.timeにまだ更新されていない古いコードと相互運用する必要がある場合は、前後に変換できます。 oldクラスに追加された新しいメソッドを呼び出します。
Instant
はJava.util.Date
を置き換えます。
Java.util.Date myJUDate = Java.util.Date.from( instant ) ; // From modern to legacy.
Instant instant = myJUDate.toInstant() ; // From legacy to modern.
ZonedDateTime
はGregorianCalendar
を置き換えます。
Java.util.GregorianCalendar myGregCal = Java.util.GregorianCalendar.from( zdt ) ; // From modern to legacy.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
Java.util.Calendar
が実際にGregorianCalendar
である場合は、キャストします。
Java.util.GregorianCalendar myGregCal = ( Java.util.GregorianCalendar ) myCal ; // Cast to the concrete class.
ZonedDateTime zdt = myGregCal.toZonedDateTime() ; // From legacy to modern.
質問の特定の問題について…
Java.timeクラスはJava 8、9、10、およびそれ以降に組み込まれています。実装は後のAndroidにも含まれています。 Java以前のAndroid、この回答の次のセクションを参照してください。
さまざまなJava.timeクラスは、私が知っているすべてのISO 8601形式を処理します。標準の後の版から不可解に姿を消したいくつかのフォーマットも処理します。
その他の形式については、parse
、toString
などのさまざまなクラスのLocalDate
およびOffsetDateTime
メソッドを参照してください。また、このトピックに関するmanyの例とディスカッションがあるため、スタックオーバーフローを検索してください。
入力文字列を検証するには、 DateTimeParseException
をトラップします。
try {
Instant instant = Instant.parse( "2011-05-03T11:58:01Z" ) ;
} catch ( DateTimeParseException e ) {
… handle invalid input
}
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは厄介な古い レガシーに取って代わりますJava.util.Date
、 Calendar
、& SimpleDateFormat
などの日時クラス.
Joda-Time プロジェクトは現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。
詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 310 です。
Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠した JDBCドライバー を使用します。文字列も、Java.sql.*
クラスも必要ありません。
Java.timeクラスはどこで入手できますか?
ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明する場です。 Interval
、 YearWeek
、 YearQuarter
、 more などの便利なクラスがここにあります。
したがって、原則として、これはさまざまな SimpleDateFormat パターンを使用して行われます。
RFC 3339の 個別宣言のパターンのリスト :
yyyy
MM
dd
HH
mm
ss
.SSS
_(ただし、S
はミリ秒を意味します。これらの数字が3桁より多い場合や少ない場合に何が起こるかは明確ではありません。)+02:00
_はサポートされていないようです-代わりに、_+0200
_、_GMT+02:00
_の形式と、z
およびZ
。)'Z'
_(他のタイムゾーンはサポートされていません)-これを使用する前にformat.setTimezone(TimeZone.getTimeZone("UTC"))
を使用する必要があります。)HH:mm:ss
_または_HH:mm:ss.SSS
_。HH:mm:ss'Z'
_または_HH:mm:ss.SSS'Z'
_。yyyy-MM-dd
_yyyy-MM-dd'T'HH:mm:ss'Z'
_または_yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
_ご覧のとおり、これではすべてを解析できないようです。 _RFC3339DateFormat
_を最初から実装することをお勧めします(簡単にするために正規表現を使用するか、効率を上げるために手動で解析する)。
ここ は、そのための簡単な方法です。それはあなたのニーズに合うかもしれません。
おそらく最もエレガントな方法ではないかもしれませんが、確かに私が最近作った方法で動作しています:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
cal.setTime(sdf.parse(dateInString.replace("Z", "").replace("T", "-")));
あなたが持っているフォーマットで2011-05-03T11:58:01Z、以下のコードで実行できます。しかし、最近ChromeおよびOperaでhtml5の日時を試してみたところ、2011-05-03T11:58Z->以下のコードでは処理できないss部分がありません。
new Timestamp(javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(date).toGregorianCalendar().getTimeInMillis());
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").parse(datetimeInFRC3339format)