SpamSajt
SpamSajt

Reputation: 21

Java Convert UTC Date to local Date with Joda

This code is working, but I want to use Joda-Time

public static Date dateFromUTC(Date date){
        return new Date(date.getTime() + Calendar.getInstance().getTimeZone().getOffset(date.getTime()));
    }

I tried this, but it's not working - what's the problem with this?

public static Date dateFromUTC(Date date){
        return new DateTime(date).withZone(DateTimeZone.getDefault()).toDate();
    }

Upvotes: 2

Views: 2128

Answers (3)

Basil Bourque
Basil Bourque

Reputation: 338181

tl;dr

Use java.time classes instead.

Instant.now()        // Capture current moment in UTC. Always in UTC, by definition.

…and…

ZonedDateTime.now()  // Capture current moment as seen through the wall-clock time of the people in the region of the time zone used by default in this JVM.

Details

As others said, you misunderstood the concepts involved in these classes. A java.util.Date represents a moment in UTC, always in UTC, never in some other time zone. So the code seen in the Question is non-sensical. You are working too hard!

java.time

The Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. Many of the concepts are similar between Joda-Time and java.time as both projects are led by the same man, Stephen Colebourne.

When you are ready to migrate, use Instant in place of java.util.Date.

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

instant.toString(): 2018-01-23T12:34:56.123456789Z

Instead of java.util.Calendar, use ZonedDateTime to represent a moment seen through the wall-clock time of a particular region (a time zone).

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;  // Same moment, same point on the timeline, different wall-clock time.

As a shortcut, you can skip the Instant if you want only the zoned time.

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;  // Capture the current moment as seen by people in a certain time zone.

You can get to UTC from there by extracting an Instant object.

Instant instant = zdt.toInstant() ;  // Same moment, same point on the timeline, but viewed with the wall-clock time of UTC.

Actually, there is a time zone assigned deep within a java.util.Date but is irrelevant to our discussion here. Confusing? Yes. One of many reasons to avoid the awful mess that is the old Date/Calendar and related legacy date-time classes.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Upvotes: 3

carlBjqsd
carlBjqsd

Reputation: 130

First of all, read the article linked in the comments: https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/

A java.util.Date doesn't have a timezone. It actually represents a point in time: the number of milliseconds since unix epoch (Jan 1st 1970, at midnight, in UTC).

When you print the Date, though, it uses the JVM default timezone to convert the Date to date/time values, but the Date itself doesn't have a timezone.

That's why converting a Date object to another timezone doesn't make sense.

If you want to know the date (day, month, year) and time (hour, minute, second, millisecond) that corresponds to the Date in a specific timezone, then you can use Joda-Time:

// java.util.Date
Date date = new Date();

// the Date converted to UTC
DateTime utc = new DateTime(date, DateTimeZone.UTC);

// the Date converted to JVM default timezone
DateTime convertedToDefaultTz= new DateTime(date, DateTimeZone.getDefault());

The conversion can also be made using another DateTime:

DateTime convertedToDefaultTz = utc.withZone(DateTimeZone.getDefault());

Joda's DateTime has a timezone attached to it, so now it makes sense to convert to another one. But the Date objects returned by it will always be the same, because all of them represent the same instant (the same point in the timeline):

Date d1 = utc.toDate();
Date d2 = convertedToDefaultTz.toDate();
System.out.println(d1.equals(d2)); // true

All because - again - a Date doesn't have a timezone.

Upvotes: 1

Lev Sivashov
Lev Sivashov

Reputation: 337

Try this:

new DateTime(date, DateTimeZone.UTC)
    .toLocalDateTime() // value without timezone
    .toDateTime() // convert to default timezone
    .toDate();

Your code actually does nothing to the date, because new DateTime(date) creates a DateTime object with default timezone. And then you just convert it back to java.util.Date.

Upvotes: 1

Related Questions