Search code examples
kotlintimezonesimpledateformat

Kotlin SimpleDateFormat parse wrong timezone


My mobile timezone was GMT+7, I have a code to convert a specific date time(GMT+0) to a specific timezone(GMT+3):

var strDate = "2020-07-10 04:00:00+0000"
var result: Date?
var dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ")
dateFormatter.timeZone = TimeZone.getTimeZone("Asia/Jerusalem")
result = dateFormatter.parse(strDate)

The problem is result always return "Fri Jul 10 11:00:00 GMT+07:00 2020"
But I expected it will return date object "Fri Jul 10 07:00:00 GMT+03:00 2020", any idea what's wrong with my code?


Solution

  • It's recommended to use java.time and stop using java.util.Date, java.util.Calendar along with java.text.SimpleDateFormat because of problems like this one.

    In your code, the target time zone is obviously not applied to the date but it isn't obvious why it isn't.

    A different problem might be pattern you are using because your example String does not contain any unit of time smaller than seconds but the pattern tries to consider .SSS (which made the code fail in the Kotlin Playground).

    Switch to java.time and handle this with modern classes, such as OffsetDateTime for parsing this String (it doesn't contain information about a specific time zone, just an offset of zero hours) and ZonedDateTime as the target object (this considers a real time zone which may have different offsets depending things like Daylight Saving Time).

    You could do it like this:

    import java.time.ZoneId
    import java.time.ZonedDateTime
    import java.time.OffsetDateTime
    import java.time.format.DateTimeFormatter
    
    fun main() {
        // this example is in UTC (+0000 --> no offset / offset of 0 hours)
        var strDate = "2020-07-10 04:00:00+0000"
        // create a formatter that can parse Strings of this pattern
        // ([] represents optional units to be parsed)
        var dateFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss[.SSS]Z")
        // and parse the String to an OffsetDateTime using this formatter
        var resultOfParsing = OffsetDateTime.parse(strDate, dateFormatter)
        // then print the parsed result
        println(resultOfParsing)
        
        // create the target time zone
        var timeZone = ZoneId.of("Asia/Jerusalem")
        // then use the target zone for a zone shift
        var jerusalemTime: ZonedDateTime = resultOfParsing.atZoneSameInstant(timeZone)
        // and print the result
        println(jerusalemTime)
        // you could use your formatter defined above for a differently formatted output, too
        println(jerusalemTime.format(dateFormatter))
    }
    

    which outputs (including all intermediate results):

    2020-07-10T04:00Z
    2020-07-10T07:00+03:00[Asia/Jerusalem]
    2020-07-10 07:00:00.000+0300