Phil O
Phil O

Reputation: 1668

Convert java Calendar object from local time to UTC

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

Answers (4)

ImI
ImI

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

Anonymous
Anonymous

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();

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.

What went wrong in your code?

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.

Links

Upvotes: 3

xingbin
xingbin

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

Johann
Johann

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

Related Questions