Setting and formatting a timezone using a Calendar object in Java and then returning a Date object

I have a function where I need to take the current date, set it to a different timezone, and return that converted / formatted date as an object Date

. I have some code that works, however the object Date

does not set a new date, it returns the current date.

Here is the code:

public static Date getCurrentLocalDateTime() {

    Calendar currentdate = Calendar.getInstance();
    DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    TimeZone obj = TimeZone.getTimeZone("America/Denver");
    formatter.setTimeZone(obj);

    Logger.info("Local:: " + currentdate.getTime());

    String formattedDate = formatter.format(currentdate.getTime());

    Logger.info("America/Denver:: "+ formattedDate);

    Date finalDate = null;
    try {
        finalDate = formatter.parse(formattedDate);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    Logger.info("finalDate:: " + finalDate);

    return finalDate;
}

      

From the examples I've looked at and tried it out, this should work correctly. One problem is that I need to return an object Date

in order for it to work with the current code.

The result looks like this:

2017-07-03 17:08:24,499 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                Local:: Mon Jul 03 17:08:24 UTC 2017
2017-07-03 17:08:24,501 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                America/Denver:: 2017-07-03 11:08:24
2017-07-03 17:08:24,502 [INFO] from application in application-akka.actor.default-dispatcher-3 -
                finalDate:: Mon Jul 03 17:08:24 UTC 2017

      

As you can see, it formats the date correctly in the Mountain time zone, but then sets it back to Calendar

.


EDIT --- Code solution:

public static Date getCurrentLocalDateTime() {
    Calendar currentdate = Calendar.getInstance();
    ZonedDateTime converted = currentdate.toInstant().atZone(ZoneId.of("America/Denver"))
            .withZoneSameLocal(ZoneOffset.UTC);
    Date finalDate = Date.from(converted.toInstant());
    return finalDate;
}

      

+3


source to share


1 answer


A java.util.Date

object has no time zone information . It only has a value long

that represents the number of milliseconds from 1970-01-01T00:00:00Z

(also known as "unix epoch" or simply "epoch"). This value is completely independent of the time zone (you can also say "it's in UTC").

When you call Logger.info("finalDate:: " + finalDate);

, it invokes a method toString()

java.util.Date

and that method uses the default timezone, giving the impression that the date object itself has a timezone - but it doesn't .

Check the values finalDate.getTime()

and currentdate.getTimeInMillis()

you will see that they are almost the same - "almost" because it SimpleDateFormat

does not have a fraction of a second , so you lose milliseconds precision (the format

method creates String

no milliseconds, and the method parse

sets it to zero when this field is absent). If I change the formatter to this then:

// using ".SSS" to don't lose milliseconds when formatting
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

      

Output:

Local :: Mon Jul 03 17:34:34 UTC 2017
America / Denver :: 2017-07-03 11: 34: 34.508
finalDate :: Mon Jul 03 17:34:34 UTC 2017

Both finalDate.getTime()

and currentdate.getTimeInMillis()

will have exactly the same values ​​(note that it Date.toString()

does not print milliseconds, so you cannot know what their value is - just by comparing the values getTime()

you know if they are the same).

Conclusion: just change your formatter to use milliseconds ( .SSS

) and the parsing / formatting will work. The fact that it shows dates in a different time zone is an implementation detail (the method toString()

uses the system default time zone), but the millisecond value is correct.

If you want to get 11 hours in UTC, you have to create another formatter and set its timezone to UTC:

DateFormat parser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
parser.setTimeZone(TimeZone.getTimeZone("UTC"));
finalDate = parser.parse(formattedDate);

      

Then the finalDate

time will be 11h in UTC:

finalDate :: Mon Jul 03 11:34:34 UTC 2017


New Java Date / Time API

The old classes ( Date

, Calendar

and SimpleDateFormat

) have many design problems and problems , and they are being replaced with new APIs.

If you're using Java 8 , consider the new java.time API . Lighter, less error prone and less error prone than older APIs .



If you're using Java <= 7 , you can use the ThreeTen Backport , a great backport for Java 8's new date and time classes. And for Android there is ThreeTenABP (more on how to use it here ).

Below is the code below. The only difference is the package names (in Java 8 - java.time

, and in ThreeTen Backport (or Android ThreeTenABP) - org.threeten.bp

), but the class and method names are the same.

To do what you need you can use ZonedDateTime

(date and time + time zone) and convert to a different time zone while keeping the same date / time values:

// current date/time in Denver
ZonedDateTime denverNow = ZonedDateTime.now(ZoneId.of("America/Denver"));
// convert to UTC, but keeping the same date/time values (like 11:34)
ZonedDateTime converted = denverNow.withZoneSameLocal(ZoneOffset.UTC);
System.out.println(converted); // 2017-07-03T11:34:34.508Z

      

The output will be:

2017-07-03T11: 34: 34.508Z

If you want to use a different format use DateTimeFormatter

:

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // pattern for day/hour
    .appendPattern("EEE MMM dd HH:mm:ss ")
    // UTC offset
    .appendOffset("+HHMM", "UTC")
    // year
    .appendPattern(" yyyy")
    // create formatter
    .toFormatter(Locale.ENGLISH);
System.out.println(fmt.format(converted));

      

The output will be:

Mon Jul 03 11:34:34 UTC 2017


If you still need to use java.util.Date

, you can easily convert from / to the new API.

In Java> = 8:

// convert your Calendar object to ZonedDateTime
converted = currentdate.toInstant()
               .atZone(ZoneId.of("America/Denver"))
               .withZoneSameLocal(ZoneOffset.UTC);
// converted is equals to 2017-07-03T11:34:34.508Z

// from ZonedDateTime to Date and Calendar (date will be 11:34 UTC)
Date d = Date.from(converted.toInstant());
Calendar cal = Calendar.getInstance();
cal.setTime(d);

// to get a Date that corresponds to 11:34 in Denver
Date d = Date.from(converted.withZoneSameLocal(ZoneId.of("America/Denver")).toInstant());
Calendar cal = Calendar.getInstance();
cal.setTime(d);

      

In Java <= 7 (ThreeTen Backport) you can use a class org.threeten.bp.DateTimeUtils

:

// convert Calendar to ZonedDateTime 
converted = DateTimeUtils.toInstant(currentdate)
                .atZone(ZoneId.of("America/Denver"))
                .withZoneSameLocal(ZoneOffset.UTC);
// converted is equals to 2017-07-03T11:34:34.508Z

// convert ZonedDateTime to Date (date will be 11:34 UTC)
Date d = DateTimeUtils.toDate(converted.toInstant());
Calendar c = DateTimeUtils.toGregorianCalendar(converted);

// to get a Date that corresponds to 11:34 in Denver
Date d = DateTimeUtils.toDate(converted.withZoneSameLocal(ZoneId.of("America/Denver")).toInstant());
Calendar c = DateTimeUtils.toGregorianCalendar(converted.withZoneSameLocal(ZoneId.of("America/Denver")));

      

+1


source







All Articles