Reputation: 1668
How do I convert a Java Calendar
object from local time to UTC? This what I have tried:
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTime(localDateTime.getTime());
SimpleDateFormat outputFmt = new SimpleDateFormat("MMM dd, yyy h:mm a zz");
String dateAsString = outputFmt.format(calendar.getTime());
System.out.println(dateAsString)
Time is always displayed in MT not GMT. I want to store the calendar in UTC in a database (I'm not concerned with formatting or displaying the time).
Upvotes: 1
Views: 7208
Reputation: 208
Here's I prepared my own Calender Object and set the time zone to UTC and then get the Date Object. Once you get the date object you can get the time in millis which is millisecs since epoch.
private static Date internalDate(int year, int month, int day, int hour, int minute, int second) {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month - 1);
calendar.set(Calendar.DAY_OF_MONTH, day);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, second);
// get the Date Object and now your time is in UTC and you can easily convert it to
// local or UTC by getting the milli seconds which is date.gerTime();
return calendar.getTime();
}
Upvotes: 0
Reputation: 86389
Don’t convert your date-time to string for storing into an SQL database. Use a date-time object.
I am assuming that you are storing into a database column of datatype datetime
or timestamp
without time zone and the column is to contain UTC values (a recommended practice). In this case, further assuming that you are using at least Java 8 and at least JDBC 4.2, store a LocalDateTime
in UTC into the database.
ZonedDateTime dateTime = ZonedDateTime.of(
2018, 7, 1, 9, 0, 0, 0, ZoneId.of("America/Denver"));
LocalDateTime dateTimeInUtc = dateTime.withZoneSameInstant(ZoneOffset.UTC)
.toLocalDateTime();
System.out.println("UTC: " + dateTimeInUtc);
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(date_time) values (?)");
ps.setObject(1, dateTimeInUtc);
ps.executeUpdate();
The code example takes July 1 at 9 AM in Denver and converts it and prints:
UTC: 2018-07-01T15:00
It then stores the printed UTC time to the database. Note the use of the setObject
method.
The Calendar
class that you used is long outdated and was always poorly designed. If you got a Calendar
object from a legacy API that you cannot change or don’t want to change just now, convert it first to an Instant
and then do further conversion from there:
Calendar localDateTime = // …;
LocalDateTime dateTimeInUtc = localDateTime.toInstant()
.atOffset(ZoneOffset.UTC)
.toLocalDateTime();
EDIT: It depends on the datatype you use in your database and the requirements of your JDBC driver. As I said, I was assuming that you know that the values in the database are in UTC and that the datatype you use is without time zone, so the database doesn’t know. If this is the case, there is no point in using a Java type with time zone or offset information since this will be lost anyway when you store it.
Some will say that in that case you are already using the wrong type in the database and will recommend that you use a timestamp with timezone
column so also the database knows that the times are in UTC. In this case you should of course include offset information in the value you store. The PostgreSQL JDBC driver, for example, requires an OffsetDateTime
in this case, which is logical (because what it stores, is a UTC offset, not a real time zone).
Depending on the capabilities of your DBMS there may be yet other options. I have included yet a couple of links at the bottom, and you can serach for more.
Your conversion to Calendar
worked correctly and gave you the same point in time in UTC. The trouble only began when you tried to format it into a String
: When you take calendar.getTime()
, you are getting a Date
object that contains the same point in time (still the correct one), but a Date
cannot hold the time zone information, so you lost the information about UTC. Next you formatted the Date
using a SimpleDateFormat
. A SimpleDateFormat
has a time zone, and if you don’t set it yourself, it uses the time zone setting of your JVM, which probably was some variant of Mountain Time. Therefore your time was printed in MT.
java.time
, the modern Java date and time API.java.time
types to use with which database types.Upvotes: 3
Reputation: 28289
You need call setTimeZone
on SimpleDateFormat
, not on Calendar
:
//getting local time
Calendar calendar = Calendar.getInstance(Locale.getDefault());
SimpleDateFormat outputFmt = new SimpleDateFormat("MMM dd, yyy h:mm a zz");
outputFmt.setTimeZone(TimeZone.getTimeZone("GMT")); //set timezone here
//shows calendar time correctly set
System.out.println(outputFmt.format(calendar.getTime()));
Upvotes: 6
Reputation: 29885
Here's how I convert a normal date to UTC. So first convert your Calendar object to a Date object:
public static String convertToUTC(Date date) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat.format(date);
}
Upvotes: 0