每周的即时时间

3

我需要从一年的周数中获取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 Time API(java.time包),是否可以从一年中的周数获取Instant

使用新的日期 API 取代日历。你可能可以在不使用日历的情况下实现这一点。 - Hassam Abdelillah
什么是 start - Bruno
1
@BrunoDM 抱歉,我把 instant 重命名为 start - Kirill
谢谢 @Kirill。我为你做了一个答案。 - Bruno
1
你的周数怎么样?GregorianCalendar将使用JVM默认语言环境的周编号,这是你想要的吗? - Ole V.V.
3个回答

2
    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周,因为我们已经在那个周中。


1
您可以使用以下方法调整周数:
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


0

为了设置月份,您可以使用此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();

如果您不想更改时间,那么您可以使用这个代替最后一行:
Instant instant = localDate.atTime(LocalTime.now()).atZone(ZoneId.systemDefault()).toInstant();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接