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).
4 Answers
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()));
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();
Should I use LocalDateTime here?
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.