Joda在GMT时区解析ISO8601日期

时间:2012-01-31 09:31:16

标签: java datetime jodatime

我有一个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()方法时。该方法会根据需要将DateTime转换为Date,但我会在当地时间对其进行转换。

有人知道不会施加此限制的转换方法吗?

3 个答案:

答案 0 :(得分:20)

这是一个工作的常规测试用例。显示其他时区的时间显示方式。

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对象的元数据以指示其时区。仍然是相同的时间点,只是显示不同的偏移量。

答案 1 :(得分:0)

java.time

Joda-Time团队告诉我们要迁移到Java 8及更高版本中内置的java.time框架。 java.time框架由JSR 310定义。很多java.time功能都回来了 - ported to Java 6 & 7further adapted for Android

偏移

java.time类包括OffsetDateTime来表示时间轴上的时刻,offset-from-UTC但不是全时区。

在解析或生成字符串时,java.time类默认使用标准的ISO 8601格式。所以不需要定义格式化模式。

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

时区

time zone是用于处理夏令时(DST)等异常的偏移规则。 proper time zone name使用continent/region格式。您可以为OffsetDateTime分配时区(ZoneId)以获得ZonedDateTime

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

答案 2 :(得分:0)

编辑

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()
}