繁体   English   中英

在 Java 中将 Long 转换为 Date 返回 1970

[英]Converting Long to Date in Java returns 1970

我有从 web 服务下载的长值列表(例如:1220227200、1220832000、1221436800...)。 我必须将它转换为日期。 不幸的是,例如:

Date d = new Date(1220227200);

1970 年 1 月 1 日返回。有人知道另一种正确转换它的方法吗?

Date的构造(点击链接!)接受的时间long单位为毫秒,不秒。 您需要将其乘以 1000,并确保提供的时间与long一样long

Date d = new Date(1220227200L * 1000);

这显示在这里

2008 年 8 月 31 日星期日 20:00:00 GMT-04:00

tl;博士

java.time.Instant                    // Represent a moment as seen in UTC. Internally, a count of nanoseconds since 1970-01-01T00:00Z.
.ofEpochSecond( 1_220_227_200L )     // Pass a count of whole seconds since the same epoch reference of 1970-01-01T00:00Z.

了解您的数据

自一个纪元以来,人们使用各种精度来跟踪时间作为一个数字。 因此,当您获得一些要被解释为自一个纪元以来的计数的数字时,您必须确定:

  • 什么时代?
    许多纪元日期已用于各种系统。 常用的是POSIX/Unix time ,其中纪元是 UTC 中的 1970 年的第一个时刻。 但是你不应该假设这个时代。
  • 什么精度?
    自纪元以来,我们是在谈论秒、毫秒微秒还是纳秒
  • 什么时区?
    通常是一个计数,因为纪元在UTC /GMT 时区,也就是说,根本没有时区偏移。 但有时,当涉及没有经验或对日期时间一无所知的程序员时,可能会隐含时区。

在您的情况下,正如其他人指出的那样,自 Unix 时代以来,您似乎已经获得了几秒钟的时间。 但是您将这些秒数传递给需要毫秒的构造函数。 因此,解决方案是乘以 1,000。

得到教训:

  • 确定,不要假设,接收数据的含义。
  • 阅读文档

图表显示了日期时间系统中的各种分辨率粒度,包括整秒、毫秒、微秒和纳秒。

您的数据

您的数据似乎整整几秒钟。 如果我们假设一个纪元是 1970 年初,如果我们假设 UTC 时区,那么1,220,227,200是 2008 年 9 月第一天的第一个时刻。

乔达时间

与 Java 捆绑在一起的 java.util.Date 和 .Calendar 类是出了名的麻烦。 避开它们。 使用Joda-Time库或 Java 8 中捆绑的新java.time 包(受 Joda-Time 启发)。

请注意,与 juDate 不同,Joda-Time 中的DateTime真正知道自己分配的时区 因此,在下面看到的示例 Joda-Time 2.4 代码中,请注意我们首先使用 UTC 的默认假设解析毫秒。 然后,其次,我们分配一个巴黎的时区进行调整。 宇宙时间线中的同一时刻,但挂钟时间不同。 为了演示,我们再次调整为 UTC。 几乎总是更好地明确指定您想要/期望的时区,而不是依赖隐式默认值(通常是日期时间工作中出现问题的原因)。

我们需要毫秒来构造一个 DateTime。 因此,输入您的秒数,然后乘以一千。 请注意,结果必须是 64 位long因为我们会溢出 32 位int

long input = 1_220_227_200L;  // Note the "L" appended to long integer literals.
long milliseconds = ( input * 1_000L ); // Use a "long", not the usual "int". Note the appended "L".

将毫秒数提供给构造函数。 该特定构造函数假定计数来自 1970 年的 Unix 时代。因此,在构造之后根据需要调整时区。

使用 正确的时区名称,大陆和城市/地区的组合。 切勿使用EST等 3 或 4 个字母的代码,因为它们既不是标准化的也不是唯一的。

DateTime dateTimeParis = new DateTime( milliseconds ).withZone( DateTimeZone.forID( "Europe/Paris" ) );

为了演示,再次调整时区。

DateTime dateTimeUtc = dateTimeParis.withZone( DateTimeZone.UTC );
DateTime dateTimeMontréal = dateTimeParis.withZone( DateTimeZone.forID( "America/Montreal" ) );

转储到控制台。 请注意蒙特利尔的日期有何不同,因为新的一天已在欧洲开始,但在美国尚未开始。

System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUTC: " + dateTimeUtc );
System.out.println( "dateTimeMontréal: " + dateTimeMontréal );

跑的时候。

dateTimeParis: 2008-09-01T02:00:00.000+02:00
dateTimeUTC: 2008-09-01T00:00:00.000Z
dateTimeMontréal: 2008-08-31T20:00:00.000-04:00

时间

Joda-Time 的制造商要求我们尽快迁移到它的替代品java.time框架。 虽然 Joda-Time 继续得到积极支持,但所有未来的开发都将在 ThreeTen-Extra 项目中的 java.time 类及其扩展上完成。

java-time 框架由JSR 310定义并内置于 Java 8 及更高版本中。 java.time 类已在ThreeTen- Backport项目中移植到 Java 6 和 7,在ThreeTenABP项目中移植到 Android。

一个InstantUTC时间线上的一个时刻,分辨率为纳秒。 它的纪元是 UTC 时间的 1970 年的第一个时刻。

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

应用偏移 UTC ZoneOffset以获得OffsetDateTime

更好的是,如果已知,应用时区ZoneId来获取ZonedDateTime

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Java 中所有日期时间类型的表,包括现代的和传统的

看起来你的 longs 是秒,而不是毫秒。 日期构造函数需要时间为毫秒,所以

Date d = new Date(timeInSeconds * 1000);

只在日历对象上设置时间

Calendar c = Calendar.getInstance();
c.setTimeInMillis(1385355600000l);
System.out.println(c.get(Calendar.YEAR));
System.out.println(c.get(Calendar.MONTH));
System.out.println(c.get(Calendar.DAY_OF_MONTH));
// get Date
System.out.println(c.getTime());

这些可能是以为单位的时间戳,而不是以毫秒为单位的,这是 java new Date(long) 构造函数所需的。 只需将它们乘以 1000 就可以了。

长值很可能对应于Epoch时间戳,这些值是:

1220227200 = 2008 年 9 月 1 日星期一 00:00:00 GMT

1220832000 = 2008 年 9 月 8 日星期一 00:00:00 GMT

1221436800 = 2008 年 9 月 15 日星期一 00:00:00 GMT

可以将这些长值转换为java.util.Date ,考虑到 java.util.Date 使用毫秒这一事实——如前所述,但有一些缺陷——像这样:

// note: enforcing long literals (L), without it the values would just be wrong.
Date date = new Date(1220227200L * 1000L); 

现在,为了正确显示日期,可以使用 java.text.DateFormat 如下所示:

DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("Wrong date time value: " + date);
System.out.println("Correct date time value: " + df.format(date));

下面是在不使用和使用 DateFormat 的情况下将转换后的 long 值显示为 java.util.Date 的结果:

Date wrong (off by 2 hours): Mon Sep 01 02:00:00 CEST 2008
Correct date : Monday, 1 September 2008 00:00:00 o'clock UTC

试试这个:

Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1220227200 * 1000);
System.out.println(cal.getTime());

尝试调整日期格式。

long longtime = 1212580300;
SimpleDateFormat dateFormat = new SimpleDateFormat("MMddyyHHmm");
Date date = (Date) dateFormat.parseObject(longtime + "");
System.out.println(date);

注意:检查 24 小时或 12 小时循环。

1220227200 对应于 1980 年 1 月 15 日(实际上 new Date(1220227200).toString() 返回“Thu Jan 15 03:57:07 CET 1970”)。 如果将 long 值传递给日期,即 01/01/1970 之前,它实际上将返回 01/01/1970 的日期。 确保您的值不在这种情况下(低于 82800000)。

因为 1220227200 毫秒 = 338,952 小时。 java.util.Date 具有构造函数 new Date(Long milliseconds) - 分配一个日期 object 并将其初始化以表示自称为“纪元”的标准基准时间以来指定的毫秒数,即 1970 年 1 月 1 日,00:00: 00 格林威治标准时间。 因此,在您的情况下,请记住 1 秒 = 1000 毫秒

New Date(number) 返回一个日期,它是 1970 年 1 月 1 日之后的毫秒number 。很可能您的日期格式没有显示小时、分钟和秒,让您看到它只是 1970 年 1 月 1 日之后的一点点。

您需要根据正确的解析路由来解析日期。 我不知道 1220227200 是什么,但如果它是 1970 年 1 月 1 日之后的几秒,则乘以它以产生毫秒。 如果不是,则以某种方式将其转换为 1970 年后的毫秒(如果您想继续使用 java.util.Date)。

为我工作。 你可能想用 1000 乘以它,因为你得到的是 1970 年的秒数,你必须传递 1970 年 1 月 1 日的毫秒数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM