user1116714
user1116714

Reputation: 365

Convert OffsetDateTime to LocalDateTime with correct offset in java 8

When I try to convert OffsetDateTime to LocalDateTime from java.time, I expect the resulting LocalDateTime to be updated with the local time zone. So, If I have an OffsetDateTime of 2011-12-03T10:00:00Z, and my local timezone is UTC+2, I expect the LocalDateTime to be 2011-12-03T12:00:00, but I get instead 2011-12-03T10:00:00. I'm converting it with the method toLocalDateTime() that OffsetDateTime has. It seems that it only truncates the date, removing the offset part, without adjusting the time.

So I'm trying to figure out a way to get a LocalDateTime that represents the local date time taking into account the zone offset. Following the example, I would like to get 2011-12-03T12:00:00

Upvotes: 16

Views: 36404

Answers (6)

cutiko
cutiko

Reputation: 10507

The answer marked as correct put me in the right direction to make it a little bit more production oriented. Also, I need this for Kotlin, so considering it is retro-compatible, here it goes.

For me, what worked was using withOffsetSameInstant. This method requires the offset, and I think the key is to obtain it from the system to provide the user with the visualization in its own time.

The offset can be obtained like this:

val offset = OffsetDateTime.now().offset

And then we proceed to parse the date-time text to OffsetDateTime:

val dateTime = "2023-01-20T01:00:00+00:00"

val offsetDateTime =  OffsetDateTime.parse(dateTime).withOffsetSameInstant(offset)

Then we can obtain the local date-time like this:

val localDateTime = offsetDateTime.toLocalDateTime()
println(localDateTime)

Let's say that my offset is minus 3 (-03:00). Then that should print:

2023-01-19T22:00

This, for me, seems ok because it was day 20th at 1:00 am, so with minus 3, it should be the day 19th.

A small clarification regarding using a formatter. For the format above, you don't need to provide a DateTimeFormatter because the method parse with a single argument; assumes it is ISO, and the format above is ISO (DateTimeFormatter.ISO_OFFSET_DATE_TIME).

This is how you can create a formatter in case you need it:

val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX")

Upvotes: 0

Semyon Evgrafov
Semyon Evgrafov

Reputation: 106

I think the most concise solution is

LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC)

Upvotes: -1

Arvind Kumar Avinash
Arvind Kumar Avinash

Reputation: 79055

OffsetDateTime#withOffsetSameInstant

If you need to convert an object of OffsetDateTime to an OffsetDateTime object with a different ZoneOffset, you can do so by using OffsetDateTime#withOffsetSameInstant.

Demo:

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.parse("2011-12-03T10:00:00Z");

        OffsetDateTime odtWithOffsetTwoHours = odt.withOffsetSameInstant(ZoneOffset.of("+02:00"));
        System.out.println(odtWithOffsetTwoHours);

        LocalDateTime ldt = odtWithOffsetTwoHours.toLocalDateTime();
        System.out.println(ldt);
    }
}

Output:

2011-12-03T12:00+02:00
2011-12-03T12:00

ONLINE DEMO

I suggest you keep using OffsetDateTime because LocalDateTime, as the name suggests, throws away the useful timezone information. Nevertheless, LocalDateTime is useful in some scenarios as mentioned on this page.

If you are dealing with JDBC, check this answer and this answer.

Learn more about the modern Date-Time API from Trail: Date Time.

Upvotes: 5

Adam Millerchip
Adam Millerchip

Reputation: 23091

I think what you are looking for is OffsetDateTime.atZoneSameInstant:

OffsetDateTime.parse("2011-12-03T10:00:00Z")
    .atZoneSameInstant(ZoneId.systemDefault())
    .toLocalDateTime()

Upvotes: 9

David Lilljegren
David Lilljegren

Reputation: 1939

LocalDateTime would give you the time of a wall clock of your OffsetDateTime. That's 10:00

You need to first convert to a ZonedDatedTime in your time zone

Like this

OffsetDateTime off = OffsetDateTime.of(2011,12,3,10,00,0,0, ZoneOffset.UTC);
ZonedDateTime zoned = off.atZoneSameInstant(ZoneId.of("Europe/Athens"));
LocalDateTime athensWallTime = zoned.toLocalDateTime();
System.out.println(athensWallTime);

Upvotes: 22

stic-lab
stic-lab

Reputation: 553

Here is some code you can try :

public static void main(String[] args) {
        OffsetDateTime offsetDT1 = OffsetDateTime.now();
        System.out.println("OffsetDateTime1: " + offsetDT1);
 
        OffsetDateTime offsetDT2 = OffsetDateTime.now(Clock.systemUTC());
        System.out.println("OffsetDateTime2: " + offsetDT2);
        
        OffsetDateTime offsetDT3 = OffsetDateTime.now(ZoneId.of("Asia/Jakarta"));
        System.out.println("OffsetDateTime3: " + offsetDT3);
        
        OffsetDateTime offsetDT4 = OffsetDateTime.of(1980, 4, 9, 20, 15, 45, 345875000, ZoneOffset.of("+07:00"));
        System.out.println("OffsetDateTime4: " + offsetDT4);
        
        OffsetDateTime offsetDT5 = OffsetDateTime.of(LocalDate.now(), LocalTime.of(15, 50, 25), ZoneOffset.of("+07:00"));
        System.out.println("OffsetDateTime5: " + offsetDT5);
        
        OffsetDateTime offsetDT6 = OffsetDateTime.of(LocalDateTime.now(), ZoneOffset.of("+07:00"));
        System.out.println("OffsetDateTime6: " + offsetDT6);
        
        OffsetDateTime offsetDT7 = OffsetDateTime.ofInstant(Instant.now(), ZoneId.systemDefault());
        System.out.println("OffsetDateTime7: " + offsetDT7);
        
        OffsetDateTime offsetDT8 = OffsetDateTime.parse("2019-08-31T15:20:30+08:00");
        System.out.println("OffsetDateTime8: " + offsetDT8);
        
        OffsetDateTime offsetDT9 = OffsetDateTime.parse("1980-04-09T08:20:45+07:00", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
        System.out.println("OffsetDateTime9: " + offsetDT9);

Output

OffsetDateTime1: 2019-08-31T23:49:05.629+08:00
OffsetDateTime2: 2019-08-31T15:49:05.630Z
OffsetDateTime3: 2019-08-31T22:49:05.630+07:00
OffsetDateTime4: 1980-04-09T20:15:45.345875+07:00
OffsetDateTime5: 2019-08-31T15:50:25+07:00   
OffsetDateTime6: 2019-08-31T23:49:05.631+07:00
OffsetDateTime7: 2019-08-31T23:49:05.631+08:00
OffsetDateTime8: 2019-08-31T15:20:30+08:00
OffsetDateTime9: 1980-04-09T08:20:45+07:00

You can take a look on this website for more explaination or browse javadoc wbsite.

Upvotes: -2

Related Questions