一年中一周的即时时间

Instant time from week of year

我需要从一年中的周数中获取 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

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

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 中的 class:

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

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

要设置月份,您可以使用此 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();
    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 而不是 Calendar 来完成这项任务。 Calendar 设计不佳且已过时,我相信使用 java.time 的代码更易读。

另外,题中使用Calendar的代码并没有设置一周的第一天,所以不会给你那一天。虽然我没有测试过,但我怀疑代码有时会在新年前后产生意想不到的结果。

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