タイムゾーン
質問と他の回答は、タイムゾーンの重要な問題を無視しています。その入力文字列には、タイム ゾーンまたはoffset-from-UTCがありません。そのため、その文字列は、JVM の現在のデフォルト タイム ゾーンの日時を表していると想定して解析されます。(a) その仮定が間違っている可能性があること、および (b) そのデフォルトが実行時であってもいつでも変更される可能性があるため、危険なビジネス。
ロケール
質問とその他の回答では、別の重要な問題が無視されていますLocale
。Locale は、解析 (および生成) 中に入力文字列から曜日名と月名を翻訳するために使用される人間の言語を決定します。
指定しない場合、JVM の現在のデフォルト ロケールが翻訳に使用されます。タイム ゾーンと同様に、JVM のデフォルト ロケールは、実行時であってもいつでも変更できます。
希望する/予想されるロケールを指定することをお勧めします。
java.time
質問とその他の回答では、設計が不十分で面倒であることが証明されている古い日時クラスを使用しています。Java 8 以降にはjava.timeフレームワークが組み込まれており、そのクラスは古いクラスに取って代わります。
新しい文字列を生成しながら文字列を解析する方法は、2 つの方法に分割する必要があります。1 つのメソッドは、日時オブジェクトを取得するために解析する必要があります。2 番目は日時オブジェクトを取り、目的の文字列出力を生成する必要があります。その後、それぞれを別々に使用できます。そして、このアプローチにより、文字列を日時値と考える必要がなくなります。文字列は、日時値のテキスト表現です。ビジネス ロジックは、文字列ではなく、これらの日時の値をオブジェクトとして操作することに重点を置く必要があります。
解析中
private ZonedDateTime parseLengthyString ( String input , ZoneId zoneId , Locale locale ) {
// FIXME: Check for nulls.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" );
formatter = formatter.withZone ( zoneId );
formatter = formatter.withLocale ( locale );
ZonedDateTime zdt = null;
try {
zdt = ZonedDateTime.parse ( input , formatter );
} catch ( DateTimeParseException e ) {
// FIXME: handle exeption.
System.out.println ( "ERROR - e: " + e );
}
return zdt; // FIXME: Check for null.
}
生成中
上記ZonedDateTime
のメソッドから を取得すると、指定された Locale を使用して曜日名と月名を変換することで、その日時値のテキスト表現を生成できます。
日時が今日か昨日かを判断するには、時刻のない日付部分のみを考慮します。そのためにLocalDate
、java.time のクラスを使用できます。
private String generateLengthyString ( ZonedDateTime zdt , Locale locale ) {
// FIXME: Check for nulls.
// Compare the date-only value of incoming date-time to date-only of today and yesterday.
LocalDate localDateIncoming = zdt.toLocalDate ();
Instant instant = Instant.now ();
ZonedDateTime now = ZonedDateTime.now ( zdt.getZone () ); // Get current date-time in same zone as incoming ZonedDateTime.
LocalDate localDateToday = now.toLocalDate ();
LocalDate localDateYesterday = localDateToday.minusDays ( 1 );
DateTimeFormatter formatter = null;
if ( localDateIncoming.isEqual ( localDateToday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Today' hh:mma" , locale ); // FIXME: Localize "Today".
} else if ( localDateIncoming.isEqual ( localDateYesterday ) ) {
formatter = DateTimeFormatter.ofPattern ( "'Yesterday' hh:mma" , locale ); // FIXME: Localize "Yesterday".
} else {
formatter = DateTimeFormatter.ofPattern ( "EEE hh:mma MMM d, uuuu" , locale );
}
String output = zdt.format ( formatter );
return output; // FIXME: Check for null.
}
例
これらの 2 つの方法を実行します。
America/New_York
質問で指定されていない時間帯を任意に選択します。
String input = "Sat 11:23AM Feb 6, 2016";
ZoneId zoneId = ZoneId.of ( "America/New_York" );
Locale locale = Locale.US;
ZonedDateTime zdt = this.parseLengthyString ( input , zoneId , locale );
String output = this.generateLengthyString ( zdt , locale );
ところで、フォーマットをハードコーディングする代わりに、ロケールの文化的規範に従って出力文字列を自動的にフォーマットするように java.time に依頼することができます。
String outputPerLocale = zdt.format ( DateTimeFormatter.ofLocalizedDateTime ( FormatStyle.MEDIUM ) );
コンソールにダンプします。
System.out.println ( "input: " + input + " | zdt: " + zdt + " | Instant: " + zdt.toInstant () + " | output: " | output + " + outputPerLocale: " + outputPerLocale );
入力: 2016 年 2 月 6 日 11:23AM | zdt: 2016-02-06T11:23-05:00[アメリカ/ニューヨーク] | インスタント: 2016-02-06T16:23:00Z | 出力: 今日の午前 11 時 23 分 | outputPerLocale: 2016 年 2 月 6 日 11:23:00 AM
ちなみに、読みやすくするためにAM
orの前に SPACE を入れることをお勧めします。PM