I have a function where I need to grab the current date, set to another time zone, and return that converted/formatted date as a Date
object. I have code that works, however, the Date
object does not set to the newly converted 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 have reviewed and tried, this should work correctly. One of the issues is that I need to return the Date
object so it works with the current code.
The output looks like:
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 to the Mountain Time Zone, but then sets it back to the Calendar
time.
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;
}
A java.util.Date
object has no timezone information . It has only a long
value, which is the number of milliseconds from 1970-01-01T00:00:00Z
(also known as "unix epoch" or just "epoch" ). This value is absolutely independent of timezone (you can say "it's in UTC" as well).
When you call Logger.info("finalDate:: " + finalDate);
, it calls the toString()
method of java.util.Date
, and this method uses the system's default timezone behind the scenes, giving the impression that the date object itself has a timezone - but it doesn't .
Check the values of finalDate.getTime()
and currentdate.getTimeInMillis()
, you'll see they are almost the same - "almost" because the SimpleDateFormat
doesn't have the fraction of seconds , so you're losing the milliseconds precision ( format
method creates a String
without the milliseconds, and the parse
method sets it to zero when the field is not present). If I change the formatter to this, though:
// using ".SSS" to don't lose milliseconds when formatting
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
The output is:
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
And both finalDate.getTime()
and currentdate.getTimeInMillis()
will have exactly the same values (Note that Date.toString()
doesn't print the milliseconds, so you can't know what's their value - only by comparing getTime()
values you know if they are the same).
Conclusion: just change your formatter to use the milliseconds ( .SSS
) and parsing/formatting will work. The fact that it shows the dates in another timezone is an implementation detail ( toString()
method uses system's default timezone), but the milliseconds value is correct.
If you want to get 11h at UTC, you must 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, finalDate
's time will have the value of 11h at UTC:
finalDate:: Mon Jul 03 11:34:34 UTC 2017
The old classes ( Date
, Calendar
and SimpleDateFormat
) have lots of problems and design issues , and they're being replaced by the new APIs.
If you're using Java 8 , consider using the new java.time API . It's easier, less bugged and less error-prone than the old APIs .
If you're using Java <= 7 , you can use the ThreeTen Backport , a great backport for Java 8's new date/time classes. And for Android , there's the ThreeTenABP (more on how to use it here ).
The code below works for both. The only difference is the package names (in Java 8 is java.time
and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp
), but the classes and methods names are the same.
To do what you need, you can use a ZonedDateTime
(a date and time + a timezone) and convert to another timezone 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 a different format, use a 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 the org.threeten.bp.DateTimeUtils
class:
// 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")));
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.