【问题标题】:Convert java Calendar object from local time to UTC将 java Calendar 对象从本地时间转换为 UTC
【发布时间】:2018-12-09 10:23:55
【问题描述】:

如何将 Java Calendar 对象从本地时间转换为 UTC?这是我尝试过的:

    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)

时间始终以 MT 而非 GMT 显示。我想将 UTC 中的日历存储在数据库中(我不关心格式化或显示时间)。

【问题讨论】:

标签: java datetime utc java.util.calendar


【解决方案1】:

您需要在SimpleDateFormat 上致电setTimeZone,而不是在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()));

【讨论】:

  • 谢谢,修复了显示的值,但我想将日历以 UTC 格式存储在数据库中。我不关心格式化或显示时间
  • 如果您只想存储不带格式的日期,日历日期始终采用 UTC 格式。
【解决方案2】:

不要将您的日期时间转换为字符串以存储到 SQL 数据库中。使用日期时间对象。

我假设您将存储到数据类型为 datetimetimestamp 的数据库列中,没有时区,并且该列包含 UTC 值(推荐做法)。在这种情况下,进一步假设您至少使用 Java 8 和 JDBC 4.2,请将 UTC 格式的 LocalDateTime 存储到数据库中。

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

代码示例在 7 月 1 日上午 9 点在丹佛进行转换并打印:

UTC:2018-07-01T15:00

然后它将打印的 UTC 时间存储到数据库中。注意setObject 方法的使用。

您使用的Calendar 类早已过时,而且设计总是很糟糕。如果您从旧版 API 获得了一个 Calendar 对象,而您现在无法更改或不想更改,请先将其转换为 Instant,然后从那里进行进一步转换:

    Calendar localDateTime = // …;
    LocalDateTime dateTimeInUtc = localDateTime.toInstant()
            .atOffset(ZoneOffset.UTC)
            .toLocalDateTime();

我应该在这里使用 LocalDateTime 吗?

编辑:这取决于您在数据库中使用的数据类型和 JDBC 驱动程序的要求。正如我所说,我假设 知道数据库中的值是 UTC 并且您使用的数据类型没有时区,所以数据库 知道。如果是这种情况,则使用带有时区或偏移信息的 Java 类型毫无意义,因为在存储时它们无论如何都会丢失。

有些人会说,在这种情况下,您已经在数据库中使用了错误的类型,并建议您使用timestamp with timezone 列,这样数据库也知道时间是UTC。在这种情况下,您当然应该在存储的值中包含偏移信息。例如,PostgreSQL JDBC 驱动程序在这种情况下需要 OffsetDateTime,这是合乎逻辑的(因为它存储的是 UTC 偏移量,而不是实时时区)。

根据您的 DBMS 的功能,可能还有其他选项。我在底部添加了几个链接,您可以搜索更多。

你的代码出了什么问题?

您对Calendar 的转换工作正常,并且在UTC 中为您提供了相同的时间点。当您尝试将其格式化为String 时,问题才开始出现:当您使用calendar.getTime() 时,您将获得一个包含相同时间点(仍然是正确的时间点)的Date 对象,但是一个Date无法保存时区信息,因此您丢失了有关 UTC 的信息。接下来,您使用SimpleDateFormat 格式化DateSimpleDateFormat 有一个时区,如果您不自己设置,它会使用您的 JVM 的时区设置,这可能是 Mountain Time 的某种变体。因此,您的时间以 MT 打印。

链接

【讨论】:

  • LocalDateTime 是此处使用的错误类。 “在 UTC 中存储 LocalDateTime”这句话是自相矛盾的。
  • 恕我直言,@BasilBourque,我明确假设数据库不存储偏移信息,如果是这样,那么尝试存储来自 Java 的偏移信息显然是行不通的。当然,您可能会说,在这种情况下,数据库中使用了错误的数据类型,这就是我们在 Java 中也需要错误类型的原因。我在答案中添加了讨论。
【解决方案3】:

以下是我将正常日期转换为 UTC 的方法。所以首先将你的 Calendar 对象转换为 Date 对象:

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

【讨论】:

    【解决方案4】:

    这是我自己准备的日历对象,并将时区设置为 UTC,然后获取日期对象。获取日期对象后,您可以获取以毫秒为单位的时间,即自纪元以来的毫秒数。

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

    【讨论】:

      猜你喜欢
      • 2016-08-27
      • 2013-09-12
      • 2023-03-26
      • 2019-03-04
      • 1970-01-01
      • 2018-07-27
      • 2012-09-11
      • 2012-02-29
      • 2017-02-14
      相关资源
      最近更新 更多