4

我有以下代码需要毫秒的字符串(将来自 RSS 提要,因此将是一个字符串,下面的示例是一个快速测试程序)并将这些毫秒转换为 Date 对象。

public static void main(String[] args) {
    String ms = "1302805253";
    SimpleDateFormat dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
    Calendar calendar = Calendar.getInstance();
    calendar.setTimeInMillis(Long.parseLong(ms));

    try {
        String dateFormat = dateFormatter.format(calendar.getTime());
        System.out.println("Date Format = " + dateFormat);

        Date dateParse = dateFormatter.parse(dateFormatter.format(calendar.getTime()));
        System.out.println("Date Parse  = " + dateParse);
    } catch (ParseException e) {
        // TODO: handle exception
    }
}


Output:
    Date Format = Fri, 16 Jan 1970 02:53:25 GMT
    Date Parse  = Fri Jan 16 03:53:25 GMT 1970

如您所见,在日历对象的格式化和结果字符串的解析之间,浪费了一个小时。此外,输出的格式也发生了变化。任何人都可以帮助我了解为什么会发生这种情况,以及如何解决它?我希望日期对象的格式与“日期格式”输出的格式相同。

4

2 回答 2

9

我相信它正在发生,因为英国在 1970 年实际上并没有使用 GMT,而 Java 对此有一个错误......它将在 1970 年格式化日期,就好像英国正在使用 GMT,但实际上并没有改变偏移量。简单的例子:

Date date = new Date(0);
SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss zzz");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(sdf.format(date));

结果:

01 Jan 1970 01:00:00 GMT

请注意,它声称它是格林威治标准时间凌晨 1 点......这是不正确的。欧洲/伦敦时间是凌晨1 点,但欧洲/伦敦没有观察格林威治标准时间。

Joda Time正确地打印出 BST,但 Joda Time 不喜欢使用时区缩写解析值。但是,您可以让它改用时区偏移量

import org.joda.time.*;
import org.joda.time.format.*;

public class Test {
    public static void main(String[] args) throws Exception {
        DateTime date = new DateTime(0, DateTimeZone.forID("Europe/London"));

        DateTimeFormatter formatter = DateTimeFormat.forPattern(
            "dd MMM yyyy HH:mm:ss Z");

        String text = formatter.print(date); // 01 Jan 1970 01:00:00 +0100
        System.out.println(text);

        DateTime parsed = formatter.parseDateTime(text);
        System.out.println(parsed.equals(date)); // true
    }
}
于 2011-04-28T09:38:44.637 回答
1

Jon Skeet的答案是正确的。

java.time

让我们通过 java.time 运行相同的输入来查看结果。

指定适当的时区名称。切勿使用 3-4 个字母的缩写,例如BST, EST,或者IST因为它们不是真正的时区,不标准化,甚至不是唯一的(!)。所以我们使用Europe/London.

该类代表UTCInstant时间线上的一个时刻,分辨率为nanoseconds

String input = "1302805253";
long millis = Long.parseLong ( input );
Instant instant = Instant.ofEpochMilli ( millis );

应用时区来生成ZonedDateTime对象。

ZoneId zoneId = ZoneId.of ( "Europe/London" );
ZonedDateTime zdt = instant.atZone ( zoneId );

转储到控制台。我们确实看到Europe/London当时时间比 UTC 早一个小时。所以一天中的时间是02小时而不是01小时。两者都代表时间线上的同一时刻,只是通过两个不同的挂钟时间的镜头来观察。

System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt );

输入:1302805253 | 瞬间:1970-01-16T01:53:25.253Z | zdt: 1970-01-16T02:53:25.253+01:00[欧洲/伦敦]

整秒

顺便说一句,我怀疑您的输入字符串代表自 1970 UTC 纪元以来的整秒而不是毫秒。将我们解释为秒,我们在 2011 年得到一个日期,在这个问题发布的月份。

String output = Instant.ofEpochSecond ( Long.parseLong ( "1302805253" ) ).atZone ( ZoneId.of ( "Europe/London" ) ).toString ();

2011-04-14T19:20:53+01:00[欧洲/伦敦]

关于 java.time

java.time框架内置于 Java 8 及更高版本中这些类取代了旧的麻烦的日期时间类,例如java.util.Date, .Calendar, & java.text.SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到 java.time。

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。

许多 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7,并在ThreeTenABP进一步适应Android

ThreeTen -Extra项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。

于 2016-08-14T22:00:43.300 回答