【问题标题】:Converting Long to Date in Java returns 1970在 Java 中将 Long 转换为 Date 返回 1970
【发布时间】:2011-11-21 04:40:54
【问题描述】:

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

Date d = new Date(1220227200);

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

【问题讨论】:

  • 您能说出您期望的值吗?秒/毫秒的问题可能是一个有效的问题,但 1220227200 不是 1/1/1970。看起来您正在将 0 传递给构造函数。更多代码可能会有所帮助。
  • @mmmiki - 你应该接受答案
  • 这里返回 1970 年 1 月 15 日,而不是 1 月 1 日。
  • 仅供参考,存在严重缺陷的日期时间类,例如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 现在是 legacy,被 Java 8 及更高版本中内置的 java.time 类所取代.

标签: java date long-integer


【解决方案1】:

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.

了解您的数据

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

  • 什么时代?
    Many epochs dates已在各种系统中使用。常用的是POSIX/Unix time,其中纪元是 1970 年 UTC 的第一个时刻。但是你不应该假设这个时代。
  • 什么精度?
    我们说的是秒,millisecondsmicroseconds,还是nanoseconds 自纪元以来?
  • 什么时区?
    通常一个计数,因为纪元是在UTC/GMT 时区,也就是说,根本没有时区偏移。但有时,当涉及缺乏经验或不了解日期时间的程序员时,可能会有隐含的时区。

在您的情况下,正如其他人所指出的,自 Unix 时代以来,您似乎已经被给予了几秒钟的时间。但是您将这些秒数传递给期望毫秒的构造函数。所以解决方法是乘以 1,000。

经验教训:

  • 确定而不是假设接收数据的含义。
  • 阅读the doc

您的数据

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

乔达时间

Java 捆绑的 java.util.Date 和 .Calendar 类是出了名的麻烦。避开他们。请改用 Joda-Time 库或 Java 8 中捆绑的新 java.time package(并受 Joda-Time 启发)。

请注意,与 j.u.Date 不同,Joda-Time 中的 DateTime 真正知道自己分配的 time zone。因此,在下面看到的示例 Joda-Time 2.4 代码中,请注意,我们首先使用 UTC 的默认假设解析毫秒。然后,其次,我们分配一个巴黎的时区进行调整。宇宙时间线上的同一时刻,但不同wall-clock time。为了演示,我们再次调整为 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 纪元。因此,在构造之后根据需要调整时区。

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

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

java.time

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 时间线上的一个时刻,分辨率为纳秒。它的纪元是 1970 年 UTC 的第一个时刻。

Instant instant = Instant.ofEpochSecond( 1_220_227_200L );

申请offset-from-UTC ZoneOffset 以获得OffsetDateTime

如果知道的话,最好应用一个时区ZoneId 来获得ZonedDateTime

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

【讨论】:

  • 干杯哥们。很好的解释。我从 1970 年开始得到新的 DateTime(),当时我意识到我是以秒为单位给出它,而以毫秒为单位需要它
【解决方案2】:

尝试调整日期格式。

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

注意:检查 24 小时或 12 小时周期。

【讨论】:

    【解决方案3】:

    仅在日历对象上设置时间,单位为毫秒

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

    【讨论】:

      【解决方案4】:

      long 值很可能对应于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));
      

      以下是将转换后的 long 值显示为 java.util.Date 的结果 使用和使用 DateFormat:

      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
      

      【讨论】:

        【解决方案5】:

        试试这个:

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

        【讨论】:

          【解决方案6】:

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

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

          这里显示

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

          【讨论】:

          • 或者,也可以使用Date d = new Date(TimeUnit.SECONDS.toMillis(1220227200L)); 获得更简洁的magic-numberesque解决方案。
          【解决方案7】:

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

          【讨论】:

            【解决方案8】:

            为我工作。您可能希望将其乘以 1000,因为您得到的是 1970 年的秒数,而您必须通过 1970 年 1 月 1 日的毫秒数

            【讨论】:

              【解决方案9】:

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

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

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                • 更恰当地说 30000 毫秒太慢了
                【解决方案11】:

                看起来你的 long 是秒,而不是毫秒。日期构造函数以毫秒为单位,所以

                Date d = new Date(timeInSeconds * 1000);
                

                【讨论】:

                • @f1sh:我没有投反对票,但最初的答案不同。他在 5 分钟的宽限期内对其进行了编辑。
                • 感谢您的澄清。这就是 SO 自身的缺点...... :-/
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-01-16
                • 1970-01-01
                • 2011-05-27
                • 2015-04-27
                • 1970-01-01
                • 2020-11-21
                相关资源
                最近更新 更多