将Epoch时间转换为日期

36
我已经尝试了无数种方法,但都没有成功。非常感谢您的帮助。
long millis = getMillisFromServer();
Date date = new Date(millis);
DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
String formatted = format.format(date);

上面的方法不起作用。

基本上,我想要做的是获取时间戳并将其转换为澳大利亚时间。我的本地时间是+05.30,但我当然不希望这成为影响转换的因素。

编辑 -

运行您准确的代码时的输出:

时间戳 1318388699000

2011年10月12日星期三08:34:59 GMT+05:30

2011年10月12日03:04:59

2011年10月12日14:04:59


这段代码没问题。我不明白你想要实现什么,以及为什么这段代码对你来说不好。你能给出一个带有输入和输出的代码示例吗? - JB Nizet
也许 OP 担心的问题是,“Australia/Sydney” 不被认为具有 05:30 的偏移量,而应该是 +10。请参见 http://ideone.com/qydGJ。 - Ray Toal
2
@Hades:你能说一下你的代码出了什么问题吗?你看到了什么,期望得到了什么?这段代码在我这里是可以运行的... - Jon Skeet
3个回答

41

编辑:好吧,所以您不希望您的本地时间(这不是澳大利亚)对结果产生影响,而是希望使用澳大利亚时区。您现有的代码应该完全没问题,尽管悉尼目前是UTC+11,而不是UTC+10。以下是简短但完整的测试应用程序:

import java.util.*;
import java.text.*;

public class Test {
    public static void main(String[] args) throws InterruptedException {
        Date date = new Date(1318386508000L);
        DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        String formatted = format.format(date);
        System.out.println(formatted);
        format.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
        formatted = format.format(date);
        System.out.println(formatted);
    }
}

输出:

12/10/2011 02:28:28
12/10/2011 13:28:28

我建议您开始使用Joda Time,这是一个更好的日期/时间API...

编辑:请注意,如果您的系统不知道Australia/Sydney时区,它会显示UTC。例如,如果我将代码更改为使用TimeZone.getTimeZone("blah/blah"),它将两次显示UTC值。我建议您打印TimeZone.getTimeZone("Australia/Sydney").getDisplayName()并查看其内容...还要检查您的代码是否有拼写错误 :)


1318386508000是以毫秒为单位的纪元时间。现在我想将其转换为澳大利亚时间,即GMT+10。我的手机本地时间是GMT+5。(我想忽略这个) - Hades
@Hades:悉尼时间目前是UTC+11,而不是UTC+10。因此,如果唯一的问题是您看到的时间比您预期的早一个小时,那么这可能只是您的期望问题... - Jon Skeet
问题是当我进行转换时...系统打印+0 GMT时间,而不是澳大利亚时间。纪元13183886990002011年10月12日星期三08:34:59 GMT+05:30 12/10/2011 03:04:59 12/10/2011 14:04:59这是我运行你的代码时得到的输出。 纪元13183886990002011年10月12日星期三08:34:59 GMT+05:30 12/10/2011 03:04:59 12/10/2011 14:04:59 - Hades
@Hades:啊——如果你之前提到你在使用Android的话,那就太有帮助了……尝试循环遍历TimeZone.getAvailableIDs(),看看有哪些可用的。 - Jon Skeet
@Hades:在你的一条评论的结尾,你说你得到了“12/10/2011 03:04:59 12/10/2011 14:04:59” - 这是正确的结果,对吗? - Jon Skeet
显示剩余4条评论

28

这里是现代的答案(从2014年开始有效)。接受的答案在2011年是非常好的答案。如今,我建议不再使用DateDateFormatSimpleDateFormat类。与现代的Java日期和时间API相比,这更加自然。

要从您的毫秒数获取日期时间对象:

    ZonedDateTime dateTime = Instant.ofEpochMilli(millis)
            .atZone(ZoneId.of("Australia/Sydney"));
如果millis等于1318388699000L,那么这会给你2011-10-12T14:04:59+11:00[Australia/Sydney]。如果代码在某种奇怪的方式下运行在不知道澳大利亚/悉尼时区的JVM上,你可以确信会通过异常被通知到。
如果你想以字符串格式呈现日期时间:
String formatted = dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));

结果:

12/10/2011 14:04:59

PS我不知道你所说的“上面不起作用”的意思。在我的电脑上,您问题中的代码也会打印12/10/2011 14:04:59


1
我认为问题在于运行Android的手机在转换时处于不同的时区;我认为在计算机上运行时这并不重要;这是我后来才发现的。感谢您更新的答案。 - Hades
2
在进行时间操作时,明确指定时区几乎总是一个好主意。感谢您回报旧问题。@Hades - Ole V.V.
很好。运行顺畅。 - NKM

17

请注意,时代时间以秒为单位,Date对象接受毫秒级别的Long值。 因此,您需要将时代值乘以1000以将其用作长值。 如下所示:

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddhhmmss");
sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
Long dateLong=Long.parseLong(sdf.format(epoch*1000));

1
为了使这个工作正常,epoch 需要是一个 long。如果它是一个 int,你的乘法将会溢出,导致得到错误的结果。此外,我不认为 OP 要求一个 Long 结果,但也许其他人可以使用它。 - Ole V.V.
2
正如Ole V.V.所说,您需要将long值相乘。您可以将1000更改为带有结尾的L1_000L,以将其声明为64位整数。下划线是Java最近版本中的新功能,可使数字文字更易读。 - Basil Bourque

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