A java.util.Date
object has no format nor any timezone information. It just keeps a long
value that represents the number of milliseconds since unix epoch (1970-01-01T00:00Z
).
When you format a Date
using SimpleDateFormat
, the formatter uses the system's default timezone to convert this milliseconds value to human readable values (day/month/year/hour/minute/second).
If you're getting 2017-08-02 21:04:04
it means that the default timezone in the JVM where the code is running is EST (technically speaking, EST
is not actually a timezone, more on that below). If you want the output to be converted to UTC, you must set it in the formatter:
Date date = // Date corresponding to 2017-08-03 01:04:04 UTC (or 2017-08-02 21:04:04 EDT)
// date format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// set UTC
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(dateFormat.format(date)); // 2017-08-03
// time format
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// set UTC
timeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(timeFormat.format(date)); // 01:04:04
The output will be:
2017-08-03
01:04:04
To get the values for EST, just change the timezone:
// date format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// set to EST
dateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(dateFormat.format(date));
// time format
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
// set to EST
timeFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(timeFormat.format(date));
The output will be:
2017-08-02
21:04:04
Note that I used America/New_York
because EST
produces incorrect results. The ideal is to always use IANA timezones names (always in the format Region/City
, like America/New_York
or Europe/Berlin
).
Avoid using the 3-letter abbreviations (like EST
or PST
) because they are ambiguous and not standard.
There are lots of different timezones that use EST
as a "short name", so you can change America/New_York
to a timezone that suits best to your system. You can get a list of available timezones by calling TimeZone.getAvailableIDs()
.
To check the default timezone, you can use TimeZone.getDefault().getID()
and check if it's UTC
or GMT
(so you know which format to use - although it's recommended to internally work with UTC and only convert to a timezone when displaying the values to users, for example).
Depending on the default timezone is not ideal, because it can be changed at any time, even at runtime, or due to a misconfiguration made by someone else (I've faced situations like this before and it's not a good thing). But as it seems you don't have a choice, just check the value returned by getID()
and decide what to do based on that.
Java new Date and Time API
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.
First you convert the GregorianCalendar
to an Instant
:
// convert calendar
Instant inst = Instant.ofEpochMilli(data1.getDate.toGregorianCalendar().getTimeInMillis());
In Java 8, GregorianCalendar
has a method to do the conversion directly:
Instant inst = data1.getDate.toGregorianCalendar().toInstant();
Then you can convert the instant to a timezone:
// convert to UTC
ZonedDateTime zdt = inst.atZone(ZoneOffset.UTC);
// or convert to a timezone
ZonedDateTime zdt = inst.atZone(ZoneId.of("America/New_York"));
Then you can use a DateTimeFormatter
to format it:
DateTimeFormatter dateFmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter timeFmt = DateTimeFormatter.ofPattern("HH:mm:ss");
System.out.println(dateFmt.format(zdt));
System.out.println(timeFmt.format(zdt));
This will produce the same output as above.
You can also check the JVM default timezone using ZoneId.systemDefault().getId()
and checking if it's UTC
or GMT
.