从毫秒返回 1970 年 1 月日期时损失了一个小时

发布于 2024-11-03 12:33:13 字数 946 浏览 3 评论 0原文

我有以下代码,它需要一个毫秒字符串(将来自 RSS feed,因此将是一个字符串,下面的示例是一个快速测试程序)并将这些毫秒转换为 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

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

I have the following code that takes a String of milliseconds (will be from an RSS feed so will be a String, the example below is a quick test program) and converts those millis into a Date object.

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

As you can see, between the formatting of the calendar object and parsing of the resulting String, an hour is being lost. Also, the formatting of the output has changed. Can anyone help me as to why this is happening, and how to get around it? I want the Date object to be the same format as the "Date Format" output.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

情绪少女 2024-11-10 12:33:13

我相信这种情况的发生是因为英国在 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
    }
}

I believe it's happening because the UK didn't actually use GMT in 1970, and Java has a bug around that... it will format a date in 1970 as if the UK were using GMT, but without actually changing the offset. Simple example:

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

Result:

01 Jan 1970 01:00:00 GMT

Note that it claims it's 1am GMT... which is incorrect. It was 1am in Europe/London time, but Europe/London wasn't observing GMT.

Joda Time gets this right in that it prints out BST - but Joda Time doesn't like parsing values with time zone abbreviations. However, you can get it to use time zone offets instead:

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
    }
}
野却迷人 2024-11-10 12:33:13

乔恩·斯基特的回答是正确的。

java.time

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

指定正确的时区名称。切勿使用 3-4 个字母的缩写,例如 BSTESTIST,因为它们不是真正的时区,不是标准化的,也不是甚至是独一无二的(!)。因此我们使用 Europe/London

即时 类代表 UTC 中时间轴上的时刻,分辨率为 纳秒

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

转储到控制台。我们确实看到欧洲/伦敦时间当时比 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 功能都向后移植到 Java 6 和 Java 6。 ThreeTen-Backport 中的 7 并进一步适应 AndroidThreeTenABP。

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

The Answer by Jon Skeet is correct.

java.time

Let’s run the same input through java.time to see the results.

Specify a proper time zone name. Never use the 3-4 letter abbreviation such as BST, EST, or IST as they are not true time zones, not standardized, and not even unique(!). So we use Europe/London.

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.

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

Apply a time zone to produce a ZonedDateTime object.

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

Dump to console. We see indeed that Europe/London time is an hour ahead of UTC at that moment. So the time-of-day is 02 hours rather than 01 hours. Both represent the same simultaneous moment on the timeline, just viewed through the lenses of two different wall-clock times.

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

input: 1302805253 | instant: 1970-01-16T01:53:25.253Z | zdt: 1970-01-16T02:53:25.253+01:00[Europe/London]

Whole seconds

By the way, I suspect your input string represents whole seconds since epoch of 1970 UTC rather than milliseconds. Interpreted that as seconds we get a date in 2011, in the month this Question posted.

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

2011-04-14T19:20:53+01:00[Europe/London]

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文