【问题标题】:How can I iterate over every week in a year in Java 8?如何在 Java 8 中一年中的每个星期进行迭代?
【发布时间】:2016-03-22 15:52:06
【问题描述】:

如果我在这里混淆了任何与 ISO 日期相关的术语,请提前道歉。

我希望能够在给定年份(例如 2015 年)的每周进行迭代。我意识到您可以计算 2015 年 1 月 1 日到 2015 年 12 月 31 日之间的周数,但这不符合 ISO 标准的一周。相反,它给出了两个日期之间的 7 天周期数。一年中的第一个 ISO 周不一定从 2015 年 1 月 1 日开始。

如果我能得到第一周的第一个日期,我相信我可以简单地通过 ZonedDateTime.plusWeeks(1) 迭代 52 周。您可以通过字段访问器获取任意日期的周数:

ZonedDateTime date = ZonedDateTime.now();
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int weekNumber = date.get(weekFields.weekOfWeekBasedYear());

鉴于此,我认为在Java8 Time API中一定可以获取特定年第一周的第一天的日期,但我还没有找到方法还没完成。

【问题讨论】:

  • 另请参阅my examples,了解如何在不同的库中构建 ISO-week-date。即使是带有java.util.GregorianCalendar 的旧 JDK 也显然更简单,因为 JSR-310(java.time-package)在这里缺少一个简单的工厂方法..

标签: java java-time


【解决方案1】:

您可以构造一个日期并将其调整为一年中第一周的第一天:

int year = 2016;
WeekFields weekFields = WeekFields.ISO;
LocalDate date = LocalDate.now().with(weekFields.weekBasedYear(), year)
                                .with(weekFields.weekOfWeekBasedYear(), 1)
                                .with(ChronoField.DAY_OF_WEEK, 1);

感谢JodaStephen 的评论,另一种说法是使用IsoFields 类。

LocalDate date = LocalDate.now().with(IsoFields.WEEK_BASED_YEAR, year)
                                .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 1)
                                .with(ChronoField.DAY_OF_WEEK, 1);

WeekFields.ISO代表一周的ISO定义:

ISO-8601 定义,其中一周从星期一开始,第一周至少有 4 天。

ISO-8601 标准定义了一个基于周的日历系统。它使用基于周的年和基于周的年概念来拆分天的流逝,而不是标准的年/月/日。

请注意,第一周可能从上一个日历年开始。另请注意,一个日历年的前几天可能是与上一个日历年对应的基于周的年份。

根据这个定义,你可以得到:

  • weekBasedYear() 表示基于周的年份字段:

    这表示年份的概念,其中周从固定的星期几开始,例如星期一,并且每周正好属于一年。

    在这种情况下,我们希望将其设置为想要的年份。

  • weekOfWeekBasedYear() 表示基于周的年份中的第几周

    这表示一年中周数的概念,其中周从固定的星期几开始,例如星期一,并且每周正好属于一年。

    在这种情况下,我们想要一周年的第一周,因此我们将其设置为 1。

  • ChronoField.DAY_OF_WEEK 代表星期几。在本例中,我们想要一周的第一天,因此我们设置为 1。

然后,有了这样的日期,您确实可以通过调用LocalDate.plusWeeks(1) 来遍历一年中的所有星期。问题是:您需要迭代多少次?一年可以有超过 52 周。以周为单位的年有 52 或 53 周。

您可以使用以下方法检索周数。此调用 rangeRefinedBy(date) 以检索给定日期的年周字段的有效值,并获取其最大值。

long maxWeekOfYear = weekFields.weekOfWeekBasedYear().rangeRefinedBy(date).getMaximum();

【讨论】:

  • 您需要weekOfWeekBasedYear()weekBasedYear(),而不是weekOfYear()dayOfWeek()。两者是不同的。然而,在这种情况下,更有意义的是使用IsoFields.WEEK_OF_WEEK_BASED_YEARIsoFields.WEEK_BASED_YEAR,这样可以避免混淆。
  • @JodaStephen 你能扩大一点吗?我在 2010 年到 2020 年进行了测试,结果似乎是正确的,但我承认有时所有这些定义都有问题:)(我什至不知道 IsoFields 存在......)。
  • weekOfYear() 在一个日历年内运行。 weekOfWeekBasedYear()weekBasedYear() 内运行(一周年的第一天可能在上一个日历年,最后一天可能在下一个日历年)。由于 OP 询问 ISO 基于周的年份,因此您需要基于周的年份方法。
  • @JodaStephen 非常感谢您的意见,我用它进行了编辑。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-20
  • 2023-01-13
  • 2017-08-08
相关资源
最近更新 更多