1970年1月从毫秒返回1970年1月的日期时失去一个小时
-
26-10-2019 - |
题
我有以下代码进行一串毫秒(将来自RSS feed,因此将是一个字符串,下面的示例是快速测试程序),然后将这些毫里转换为日期对象。
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
如您所见,在日历对象的格式和结果字符串的解析之间,丢失了一个小时。同样,输出的格式已更改。谁能帮助我了解为什么会发生这种情况以及如何解决?我希望日期对象与“日期格式”输出的格式相同。
解决方案
我相信这是因为英国没有 实际上 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
请注意,它声称是GMT的凌晨1点...这是不正确的。它 曾是 在欧洲/伦敦时间上午1点,但欧洲/伦敦没有观察GMT。
乔达时间 正确地说,它打印出BST-但Joda Time不喜欢 解析 时区缩写的值。但是,您可以让它使用时区 OFFET 反而:
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
}
}
其他提示
这 乔恩·斯基特(Jon Skeet)的回答 是正确的。
Java.Time
让我们通过Java进行相同的输入。时间以查看结果。
指定 适当的时区名称. 。切勿使用3-4个字母缩写 BST
, EST
, , 或者 IST
因为它们不是真正的时区,而不是标准化的,甚至不是唯一的(!)。所以我们使用 Europe/London
.
这 Instant
班级代表时间表上的片刻 世界标准时间 分辨率 纳秒.
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
.
这 乔达时间 项目,现在 维护模式, ,建议迁移到Java.Time。
要了解更多,请参阅 Oracle教程. 。并搜索堆栈溢出以获取许多示例和解释。
java的大部分功能都将后输入到Java 6&7 in Threeten-Backport 并进一步适应 安卓 在 三分.
这 Threeten-Extra 项目扩展Java.Time提供其他类。该项目是可能将来在Java.Time中增加的遗嘱。