Java:如何将UTC时间戳转换为本地时间?

50
我有一个以UTC格式表示的时间戳,我想将其转换为本地时间,但不使用像TimeZone.getTimeZone("PST")这样的API调用。你应该如何做到这一点呢?我一直在尝试以下代码,但效果不佳:
private static final SimpleDateFormat mSegmentStartTimeFormatter = new        SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

Calendar calendar = Calendar.getInstance();

    try {
        calendar.setTime(mSegmentStartTimeFormatter.parse(startTime));
    }
    catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar.getTimeInMillis();

示例输入值:[2012-08-15T22:56:02.038Z] 应返回等效的[2012-08-15T15:56:02.038Z]

更新:此处的代码使用了过时的日期时间类,这些类在多年前被 JSR 310 中定义的 java.time 类所取代。要使用现代解决方案,请参阅Ole V.V.的回答 - Basil Bourque
4个回答

76

Date没有时区,内部存储为UTC时间。只有在格式化日期时才会应用时区校正。使用DateFormat时,默认使用JVM所在的时区。如有需要,请使用setTimeZone进行更改。

DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

Date date = utcFormat.parse("2012-08-15T22:56:02.038Z");

DateFormat pstFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
pstFormat.setTimeZone(TimeZone.getTimeZone("PST"));

System.out.println(pstFormat.format(date));

这将打印出2012-08-15T15:56:02.038

请注意,我在PST格式中省略了'Z',因为它表示UTC。如果您只使用Z,则输出将为2012-08-15T15:56:02.038-0700


7
太酷了,它真的起作用了。我通过调用TimeZone.getDefault()成功获取了Android设备的默认时区。 - Android Noob
它没有改变,仍然是UTC时间,我该怎么办? - dara
1
这篇文章没有回答问题。 - Tung Vo

27

使用现代的Java日期和时间API是很简单的:

    String inputValue = "2012-08-15T22:56:02.038Z";
    Instant timestamp = Instant.parse(inputValue);
    ZonedDateTime losAngelesTime = timestamp.atZone(ZoneId.of("America/Los_Angeles"));
    System.out.println(losAngelesTime);

这会打印出来

2012-08-15T15:56:02.038-07:00[America/Los_Angeles]

注意以下几点:

  • 你的期望有一个小错误。时间戳中的Z代表UTC,也被称为Zulu时间。因此,在本地时间值中,Z不应该存在。相反,您会希望返回类似于2012-08-15T15:56:02.038-07:00这样的返回值,因为偏移量现在是-7小时,而不是Z。
  • 避免使用三个字母的时区缩写。它们没有标准化,因此通常很模糊。例如,PST可能代表Philppine Standard Time、Pacific Standard Time或Pitcairn Standard Time(尽管缩写中的S通常表示夏令时(即DST))。如果您打算使用太平洋标准时间,那么这甚至不是一个时区,因为在夏季(您的示例时间戳所处的时期)将使用太平洋夏令时。而不是缩写,请使用格式为区域/城市的时区ID,就像我的代码中一样。
  • 时间戳通常最好处理为Instant对象。仅在需要时(例如用于显示)才转换为ZonedDateTime

问题:我可以在我的Java版本中使用现代API吗?

如果至少使用Java 6,可以使用。


0
    Instant timestamp = Instant.parse("2023-07-25T11:04:31.650Z");  
    System.out.println(timestamp.atZone(ZoneId.systemDefault()).toOffsetDateTime());

我的位置打印:

2023-07-25T13:04:31.650+02:00


1
很高兴看到你想要为Stack Overflow做出贡献。然而,我对你的回答有两个问题:(A)这种方法已经在现有的Ole V.V.的回答中提到过了。(B)我不明白你将ZonedDateTime转换为OffsetDateTime的意义,因为这样会丢失宝贵的信息(时区),而没有得到任何好处。 - Basil Bourque

-1

这里是一个简单的修改方案

    public String convertToCurrentTimeZone(String Date) {
            String converted_date = "";
            try {

                DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

                Date date = utcFormat.parse(Date);

                DateFormat currentTFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                currentTFormat.setTimeZone(TimeZone.getTimeZone(getCurrentTimeZone()));

                converted_date =  currentTFormat.format(date);
            }catch (Exception e){ e.printStackTrace();}

            return converted_date;
    }


    //get the current time zone

    public String getCurrentTimeZone(){
            TimeZone tz = Calendar.getInstance().getTimeZone();
            System.out.println(tz.getDisplayName());
            return tz.getID();
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接