web-dev-qa-db-ja.com

JodaはGMTタイムゾーンでISO8601の日付を解析します

ISO 8601の日付があります。たとえば、_2012-01-19T19:00-05:00_

私のマシンのタイムゾーンは_GMT+1_です

Jodaを使用してこれを解析し、それぞれのGMT日付と時刻に変換しようとしています。

_DateTimeFormatter simpleDateISOFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mmZZ"); 
creationDate = simpleDateISOFormat.withZone(DateTimeZone.UTC)
                                  .parseDateTime(date + "T" + time)
                                  .toDate(); 
_

今、私が期待している結果は_Fri Jan 20 00:00:00 CET 2012_です。

代わりに、次のようになります:_Fri Jan 20 01:00:00 CET 2012_

これは、私がタイムゾーン_GMT + 1_にいるためだと思います。

別のタイムゾーンにあるように偽造した日付を解析する方法はありますか?

編集:基本的に問題は、toDate()メソッドを呼び出すときです。このメソッドは、必要に応じてDateTimeDateに変換しますが、現地時間で変換します。

この制限を課さない変換方法を誰かが知っていますか?

16
Sergio Arrighi

これが実用的なグルーヴィーなテストケースです。他のタイムゾーンの時刻を表示する方法を示します。

import org.joda.time.*
import org.joda.time.format.*

@Grapes([
    @Grab(group='joda-time', module='joda-time', version='1.6.2')
])

class JodaTimeTest extends GroovyTestCase {

    void testTimeZone() {
        DateTimeFormatter parser    = ISODateTimeFormat.dateTimeParser()
        DateTimeFormatter formatter = ISODateTimeFormat.dateTimeNoMillis()

        DateTime dateTimeHere     = parser.parseDateTime("2012-01-19T19:00:00-05:00")

        DateTime dateTimeInLondon = dateTimeHere.withZone(DateTimeZone.forID("Europe/London"))
        DateTime dateTimeInParis  = dateTimeHere.withZone(DateTimeZone.forID("Europe/Paris"))

        assertEquals("2012-01-20T00:00:00Z", formatter.print(dateTimeHere))
        assertEquals("2012-01-20T00:00:00Z", formatter.print(dateTimeInLondon))
        assertEquals("2012-01-20T01:00:00+01:00", formatter.print(dateTimeInParis))
    }
}

注:

  • 私はロンドンのタイムゾーンにいるので、アサーションを調整する必要があります:-)
  • 「withZone」メソッドは、DateTimeオブジェクトのメタデータを変更して、タイムゾーンを示します。それでも同じ時点で、異なるオフセットで表示されます。
22
Mark O'Connor

Java.time

Joda-Timeチームは、Java 8以降に組み込まれている Java.time フレームワークに移行するように指示しました。Java.timeフレームワークは JSR 310 によって定義されます。Java.time機能の多くが戻ってきました- Java 6&= 7 および Android にさらに適合。

オフセット

Java.timeクラスには OffsetDateTime が含まれており、タイムライン上の瞬間を offset-from-UTC で表します。ただし、フルタイムゾーンではありません。

Java.timeクラスは、文字列を解析または生成するときに、デフォルトで標準のISO8601形式を使用します。したがって、フォーマットパターンを定義する必要はありません。

String input = "2012-01-19T19:00-05:00";
OffsetDateTime odt = OffsetDateTime.parse( input );

タイムゾーン

タイムゾーン は、夏時間(DST)などの異常を処理するためのオフセットplusルールです。 適切なタイムゾーン名continent/region形式を使用します。タイムゾーン( ZoneId )をOffsetDateTimeに割り当てて、 ZonedDateTimeを取得できます。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( zoneId );
1
Basil Bourque

[〜#〜]編集[〜#〜]

https://stackoverflow.com/a/23242779/812919

より良い解決策です。


将来の読者のために、yyyyMMddTHHmmssZの形式の文字列を解析しようとしている場合。次のコードで解析する方が簡単です。コードはKotlinにあります。 iCalendar recur rule は、この形式が表示される場所の例です。

// Reads from end to start to accommodate case where year has 4+ digits. 10100 for example.
fun iso8601GetPart(hashMap : HashMap,noOfCharsFromEnd : Int?) : String{
    var str = hashMap.get("DATE_TIME")
    var endIndex = str.length
    if(str.get(str.length-1)=='T' || str.get(str.length-1)=='Z'){
        endIndex--
    }
    if(noOfCharsFromEnd==null){
        return str
    }else{
        hashMap.put("DATE_TIME", str.substring(0, endIndex - noOfCharsFromEnd))
        return str.substring(endIndex-noOfCharsFromEnd,endIndex)
    }
}

fun foo(){

    var hashMap = HashMap<String,String>()
    hashMap.put("DATE_TIME",dateTimeString)

    var secOfMin = iso8601GetPart(hashMap,2).toInt()
    var minOfHour = iso8601GetPart(hashMap,2).toInt()
    var hourOfDay = iso8601GetPart(hashMap,2).toInt()
    var dayOfMonth = iso8601GetPart(hashMap,2).toInt()
    var monthOfYear = iso8601GetPart(hashMap,2).toInt()
    var years = iso8601GetPart(hashMap,null).toInt()
}
0
daka