web-dev-qa-db-ja.com

JavaでUTC日​​付文字列を変換し、TとZを削除する方法

Java 1.7。

変換しようとしています:

2018-05-23T23:18:31.000Z 

2018-05-23 23:18:31

DateUtilsクラス:

public class DateUtils {

    public static String convertToNewFormat(String dateStr) throws ParseException {
        TimeZone utc = TimeZone.getTimeZone("UTC");
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
        sdf.setTimeZone(utc);
        Date convertedDate = sdf.parse(dateStr);
        return convertedDate.toString();
    }
}

それを使用しようとするとき:

String convertedDate = DateUtils.convertToNewFormat("2018-05-23T23:18:31.000Z");
System.out.println(convertedDate);

次の例外を取得します。

Exception in thread "main" Java.text.ParseException: Unparseable date: "2018-05-23T23:22:16.000Z"
   at Java.text.DateFormat.parse(DateFormat.Java:366)
   at com.myapp.utils.DateUtils.convertToNewFormat(DateUtils.Java:7)

何が間違っているのでしょうか?

より簡単な方法はありますか(Apache Commons libなど)?

4
PacificNW_Lover

これを試して。解析には1つのパターンを使用し、フォーマットには別のパターンを使用する必要があります。

public static String convertToNewFormat(String dateStr) throws ParseException {
    TimeZone utc = TimeZone.getTimeZone("UTC");
    SimpleDateFormat sourceFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    SimpleDateFormat destFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    sourceFormat.setTimeZone(utc);
    Date convertedDate = sourceFormat.parse(dateStr);
    return destFormat.format(convertedDate);
}
5
jkumaranc

tl; dr

Instant.parse( "2018-05-23T23:18:31.000Z" )                // Parse this String in standard ISO 8601 format as a `Instant`, a point on the timeline in UTC. The `Z` means UTC.
.atOffset( ZoneOffset.UTC )                                // Change from `Instant` to the more flexible `OffsetDateTime`.
.format(                                                   // Generate a String representing the value of this `OffsetDateTime` object.
    DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss" )   // Specify a formatting pattern as desired.
)                                                          // Returns a `String` object.

2018-05-23 23:18:31

ISO 8601

入力文字列は、標準の ISO 8601 形式です。

Java.timeクラスは、文字列の解析/生成時にデフォルトでこれらの標準形式を使用します。

Tは、年月日部分を時分秒から分離します。 ZZuluと発音され、 [〜#〜] utc [〜#〜] を意味します。

Java.time

Java.timeクラスによって何年も前に取って代わられた厄介な古い日時クラスを使用しています。 Apache DateUtilsも不要になりました。その機能はJava.timeにもあります。

入力文字列をInstantオブジェクトとして解析します。 Instant クラスは、 [〜#〜] utc [〜#〜] でタイムライン上の瞬間を表し、 ナノ秒 (小数の最大9桁)の分解能で)。

String input = "2018-05-23T23:18:31.000Z" ;
Instant instant = Instant.parse( input ) ;

別の形式で文字列を生成するには、より柔軟なオブジェクトが必要です。 Instantクラスは、基本的なビルディングブロックであることを意図しています。 Lets convert it to aOffsetDateTime`、UTC自体を指定されたUTCからのオフセットとして使用。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; 

目的の出力に一致するようにフォーマットパターンを定義します。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd HH:mm:ss" ) ;
String output = odt.format( f ) ;

ヒント:DateTimeFormatter::ofLocalized…メソッドを使用して、フォーマットパターンをハードコーディングするのではなく、Localeごとに文字列生成を自動的にローカライズすることを検討してください。


Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い レガシー 日時クラスに取って代わります。

Joda-Time プロジェクトが メンテナンスモード になり、 Java.time クラスへの移行を推奨しています。

詳細については、 Oracleチュートリアル を参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様は JSR 31 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠した JDBCドライバー を使用してください。文字列も、Java.sql.*クラスも必要ありません。

Java.timeクラスはどこで入手できますか?

  • Java SE 8Java SE 9Java SE 1 以降
    • ビルトイン。
    • バンドル実装を備えた標準のJava AP​​Iの一部。
    • Java 9では、いくつかのマイナーな機能と修正が追加されています。
  • Java SE 6 および Java SE 7
    • Java.time機能の多くは、 ThreeTen-Backport のJava 6&7にバックポートされています。
  • Android
    • それ以降のバージョンのAndroidには、Java.timeクラスの実装がバンドルされています。
    • 以前のAndroid(<26)の場合、 ThreeTenABP プロジェクトは ThreeTen-Backport (上記)。 How to use ThreeTenABP… を参照してください。

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明する場です。 IntervalYearWeekYearQuartermore などの便利なクラスがここにあります。

7
Basil Bourque

Java 1.7制限のない他の人:

Java 1.8なので、パッケージのLocalDateTimeZonedDateTimeを使用してこれを行うことができます_Java.time_

_public static void main(String[] args) {
    String sourceDateTime           = "2018-05-23T23:18:31.000Z";
    DateTimeFormatter sourceFormat  = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    DateTimeFormatter targetFormat  = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    LocalDateTime dateTime          = LocalDateTime.parse(sourceDateTime, sourceFormat);
    String formatedDateTime         = dateTime.atZone(ZoneId.of("UTC")).format(targetFormat);
    System.out.println(formatedDateTime);
}
_

編集:(コメントを参照)

Oracleからの引用Java LocalDateTime のドキュメント):

LocalDateTimeは、日時を表す不変の日時オブジェクトで、多くの場合、年、月、日、時、分、秒と表示されます。日、週、週などのその他の日付と時刻フィールドにもアクセスできます。時間はナノ秒の精度で表されます。たとえば、値「2007年10月2日13:45.30.123456789」はLocalDateTimeに格納できます。

このクラスは、タイムゾーンを格納または表しません。代わりに、誕生日に使用される日付の説明と、壁掛け時計に表示される現地時間を組み合わせたものです。オフセットやタイムゾーンなどの追加情報がないと、タイムライン上のインスタントを表すことはできません。

oPは入力文字列を日付時刻(年月日日時分秒)に解析するように要求し、ドキュメントには

LocalDateTime ...は日時を表し、多くの場合、年、月、日、時、分、秒と表示されます。

ここでは重要な情報が失われることはありません。そしてdateTime.atZone(ZoneId.of("UTC"))ZonedDateTimeを返すので、ユーザーがタイムゾーンなどで作業する必要がある場合は、この時点でZimeZoneが再び処理されます。

そのため、回答で提示する「唯一無二の」ソリューションをユーザーに使用させようとしないでください。

3
Rami.Q

KotlinでThreeTenABPを使用すると、

fun getIsoString(year: Int, month: Int, day: Int): String {
    val localTime = ZonedDateTime.of(year, month, day, 0, 0, 0, 0, ZoneId.of("Z"))

    val utcTime = localTime.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC)

    val isoString = utcTime.toInstant().toString() // 1940-15-12T00:00:00Z

    val formattedIsoString = val formattedIsoString =
        Instant.parse(isoString)
            .atOffset(ZoneOffset.UTC)
            .format(DateTimeFormatter
                .ofPattern("uuuu-MM-dd'T'HH:mm:ss")) // 'T' in quotes so that it is retained.

    return formattedIsoString
}

// print it
print(getIsoString(1940, 15, 12)) // 1940-15-12T00:00:00
0
Jose

YYYYは年の部分と一致しません。 Java 7では、yyyyが必要です。

Tの場合、'T'を使用して一致させます

また、ミリ秒部分の派閥がありません:.SSS

これを試して:

String dateStr="2018-05-23T23:18:31.000Z";
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss.SSS'Z'");
sdf.setTimeZone(utc);
Date convertedDate = sdf.parse(dateStr);
convertedDate.toString();