【问题标题】:Convert elapsed time between epoch time and current moment to ISO 8601 duration with Java使用 Java 将纪元时间和当前时刻之间的经过时间转换为 ISO 8601 持续时间
【发布时间】:2018-10-18 04:57:17
【问题描述】:

自 1970 年 1 月 1 日 UTC(纪元时间)以来,我有毫秒。

1512431637067

我需要将其转换为(ISO-8601 持续时间)。这将基于当前的今天日​​期。

P5M4D

知道如何使用 java 代码以简单的方式做到这一点吗?

【问题讨论】:

  • 想法:转换日期时间戳中的秒数。创建第一个相同日期的新时间戳,但使用 00:00:00。然后计算差异并将其转换为所需的 ISO 格式。
  • 您能否阐明“P5M4D”(五个月零四天)与您问题的其余部分的关系(因为 1512431637067 的持续时间肯定要长得多)?
  • 似乎给出的数字实际上是自 1970 年以来的 毫秒
  • “基于当前今天的日期”,这是否意味着您想要那个纪元时间和现在时间之间的时间长度?

标签: java datetime duration epoch


【解决方案1】:

试试这条线

import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.util.Locale;

public class HelloWorld
{
  public static void main(String[] args)
  {
    Date date=new Date (1512431637067L);
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
    System.out.print(df.format(date));
  }
}

iso 8601 的输出日期:

2017-12-04T23:53:57.067Z

【讨论】:

【解决方案2】:

严格来说,你不能,因为所谓的“纪元时间”实际上是一瞬间而不是持续时间。但是您可能希望将自该纪元(Unix 纪元)以来经过的时间建模为持续时间。所以给你:

System.out.println(Duration.of(1512431637067L, ChronoUnit.MILLIS));
// output: PT420119H53M57.067S

java.time.Duration.toString() 方法自动将秒和纳秒标准化为 HMS 格式(否则我们必须声明新的持续时间类的打印能力是有限的)。如果您希望对 ISO 格式进行更多控制,请考虑使用 toHours() 等方法自行解决问题,或者使用 3rd-party-library 进行持续打印。

另一件事:1512431637067 似乎以毫秒为单位,而不是您所说的以秒为单位,否则您将在遥远的将来得到一个瞬间:

System.out.println(Instant.ofEpochMilli(1512431637067L));
// output: 2017-12-04T23:53:57.067Z

System.out.println(Instant.ofEpochSecond(1512431637067L));
// far future: +49897-01-18T19:11:07Z

【讨论】:

  • 我认为 OP 正在询问如何输出给定 Instant 和当前时钟时间之间的月和日差异。 Duration.between(givenInstant, now) 但有几个月和几天而不是总小时数。
【解决方案3】:
ZoneId zone = ZoneId.of("Europe/Guernsey");  // Specify a time zone by proper name `Contintent/Region`, never by 3-4 letter codes such as `PST`, `CST`, or `IST`.
LocalDate then =                             // Represent a date-only value, without time zone and without time-of-day.
    Instant.ofEpochMilli(1_512_431_637_067L) // Parse your number of milliseconds since 1970-01-01T00:00Z as a value in UTC.
           .atZone(zone)                     // Adjust from UTC to some other zone. Same moment, different wall-clock time. Returns a `ZonedDateTime`.  
           .toLocalDate();                   // Extract a date-only value.
LocalDate today = LocalDate.now(zone);       // Get the current date as seen in the wall-clock time in use by the people of a particular region.
Period diff = Period.between(then, today);   // Determine the number of years-months-days elapsed.
System.out.println(diff);                    // Generate a String is standard ISO 8601 format: `PnYnMnDTnHnMnS`.

刚才运行时的输出正是你所要求的:

P5M4D

结果取决于时区。对于任何给定的时刻,日期在全球范围内因地区而异。

因此,如果您想要的时区不是Europe/Guernsey,请替换它。如果您希望在UTC 中进行计算,请使用ZoneOffset.UTCOffsetDateTime 类。

例如,为Europe/Guernsey 运行上面的代码会导致 P5M4D,而切换到 Europe/Moscow 会导致 P5M3D,相差一天,具体取决于您指定的区域。

Period.between(then, LocalDate.now(ZoneId.of("Europe/Moscow")))

提问当天的输出将是:

P5M3D

对于包含大于一天的单位的持续时间,您需要使用 java.timePeriodDuration 类适用于较小的单位,即天-小时-分钟-秒-纳秒。

【讨论】:

  • 您对我的代码行为的描述是正确的,@DodgyCodeException。这是一个问题还是正确取决于你想要什么。 :-) 根据你说的正确,我们应该只从询问者的数据中获取 P5M3D,但要求的是 P5M4D。提问者还说“当前日期”,而不是“当前时间”。
  • 是的。但是现在您的解决方案取决于时区。例如,如果您只是将“Europe/Guernsey”替换为“Europe/Moscow”,您将获得 P5M3D。答案是否应该取决于时区取决于 OP,但我想我只是指出来。
  • @DodgyCodeException 实际上,这种计算总是依赖于时区。问题是程序员是否足够小心以显式处理该区域而不是隐式/无知地忽略该问题。但我很高兴你提出了这一点,因为它非常重要。我编辑了答案以提及您的具体示例。
  • @DodgyCodeException 计算总是取决于时区。例如,如果您(可能与提问者相反)想要确切时间点之间的时间段,这可能会因夏令时 (DST) 的转换而有所不同(并且此类转换因时区而异)。
  • @OleV.V.啊,是的,那些该死的夏季时间转换在原本简单的计算中投入了一把扳手。
猜你喜欢
  • 2015-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
相关资源
最近更新 更多