【问题标题】:Instant time from week of year从一年中的一周开始的即时时间
【发布时间】:2020-02-06 19:07:42
【问题描述】:

我需要从一年中的周数中获取 Instant 时间。现在我使用旧的Calendar API 来计算时间:

int week = 1; // week of year
final Calendar cal = new GregorianCalendar();
cal.set(0, 1, 0, 0, 0, 0); // reset calendar
cal.set(Calendar.YEAR, Year.now().getValue());
cal.set(Calendar.WEEK_OF_YEAR, week);
cal.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
final Instant start = cal.getTime().toInstant();
final Instant end = start.plus(Period.ofWeeks(1));

是否可以使用新的 Java 时间 API(java.time 包)从一年中的一周获取 Instant

【问题讨论】:

  • 使用新的日期 API 摆脱日历。如果没有日历,您可能会实现这一目标
  • 什么是start
  • @BrunoDM 抱歉,我将 instant 重命名为 start
  • 谢谢@Kirill。我帮你回答了
  • 你的周数怎么样? GregorianCalendar 将使用 JVM 的默认语言环境的周编号,这是您想要的吗?

标签: java time java-time


【解决方案1】:
    WeekFields wf = WeekFields.of(Locale.getDefault());

    int week = 1; // week of year

    LocalDate startDate = LocalDate.now(ZoneOffset.UTC)
            .with(wf.weekOfWeekBasedYear(), week)
            .with(wf.dayOfWeek(), 1);
    Instant startInstant = startDate.atStartOfDay(ZoneOffset.UTC).toInstant();
    LocalDate endDate = startDate.plusWeeks(1);
    Instant endInstant = endDate.atStartOfDay(ZoneOffset.UTC).toInstant();

    System.out.println("" + startInstant + " - " + endInstant);

我的语言环境使用 ISO 周数。这里的输出是:

2019-12-29T00:00:00Z - 2020-01-05T00:00:00Z

如果您希望 ISO 周独立于区域设置,请将 wf 设置为 WeekFields.ISO。如果您想要其他周编号方案,请相应地设置wf

如果其他读者想知道,Kirill 将本周末定义为下一周的第一刻。这是推荐的。它被称为使用半开间隔作为时间间隔。

我也同意这个问题,显然应该更喜欢使用 java.time 来完成这项任务,而不是 CalendarCalendar 设计的很差而且过时了,我相信使用 java.time 的代码更容易阅读。

此外,问题中使用Calendar 的代码没有将日期设置为一周的第一天,因此不会给你那一天。虽然我还没有测试过,但我怀疑代码有时会在新年前后产生意想不到的结果。

我在 java.time 中使用WeekFields 的代码将保持在当前基于周的年份,这与日历年不同。例如,如果我在 2019 年 12 月 30 日运行它,它仍然会在 2020 年的第 1 周提供药物,因为我们已经在那周了。

【讨论】:

    【解决方案2】:

    您可以使用以下方法调整星期:

    LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 0, 0);
    System.out.println(localDateTime); //2020-01-01T00:00
    localDateTime = localDateTime.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 2);
    System.out.println(localDateTime); //2020-01-08T00:00
    localDateTime = localDateTime.plusWeeks(10);
    System.out.println(localDateTime); //2020-03-18T00:00
    

    并将其解析为 Instant 取决于您使用的 API 中的哪个类:

    LocalDateTime.now().toInstant(ZoneOffset.of("+04:00"));
    ZonedDateTime.now().toInstant();
    

    LocalDateTime 没有区域,因此您必须提供 ZoneOffset 才能将其解析为 Instant。

    【讨论】:

      【解决方案3】:

      为了设置月份,您可以使用这个 lambda 表达式:

      LocalDate.now().with(temporal
                      -> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
              );
      

      现在获取即时很容易:

      LocalDate localDate = LocalDate.now().with(temporal
                      -> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
              );
      Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
      

      如果你不想 cto 改变时间,那么你可以用这个代替最后一行:

      Instant instant = localDate.atTime(LocalTime.now()).atZone(ZoneId.systemDefault()).toInstant();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-03
        • 2021-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-26
        • 2016-11-29
        相关资源
        最近更新 更多