【问题标题】:Java LocalDate How to get last week of year as 53rd week instead of 1st week of new year?Java LocalDate 如何将一年中的最后一周作为第 53 周而不是新年的第 1 周?
【发布时间】:2023-03-29 12:01:01
【问题描述】:

如果您认为该周将从每年的 Jan 01 开始,并且周开始是 SUNDAY,那么 2019 年将有 53 周。 跟随上面的Jan 29,30,31 2019 将进入Week-53 of 2019

正如IsoFields 的文档中所给出的WEEK_OF_WEEK_BASED_YEAR all three fields are validated against their range of valid values. The week-of-week-based-year field is validated from 1 to 52 or 53 depending on the week-based-year.

所以我假设以下代码应该给出输出:WEEK_OF_WEEK_BASED_YEAR 53 & WEEK_BASED_YEAR 2019。

但它的输出为:1 & 2020

import java.time.LocalDate;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.time.temporal.IsoFields;

public class WeekStartDemo {
    public static void main(String args[]) {
        DateTimeFormatter DATE_FORMATTER = DateTimeFormatter
                .ofPattern("uuuu-MM-dd")
                .withChronology(IsoChronology.INSTANCE)
                .withResolverStyle(ResolverStyle.STRICT);

        LocalDate updatedDate = LocalDate.parse("2019-12-30", DATE_FORMATTER);

        System.out.println(updatedDate.toString());

        System.out.println(updatedDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
        System.out.println(updatedDate.get(IsoFields.WEEK_BASED_YEAR));
    }
}

如果我将日期传递为2019-12-28,那么它会返回WEEK_OF_WEEK_BASED_YEAR 52WEEK_BASED_YEAR 2019。但不适用于 2019 年的最后一周(即第 53 周)

让我知道我在上面的代码中缺少什么。

【问题讨论】:

  • 基于周的年份本身是相对于标准 ISO 预测年份定义的。它与标准年的不同之处在于它总是从星期一开始。

标签: java java-time week-number


【解决方案1】:
    LocalDate date = LocalDate.of(2019, Month.DECEMBER, 30);
    int weekOfYear = date.get(WeekFields.SUNDAY_START.weekOfYear());
    System.out.println(weekOfYear);

这个 sn-p 的输出是:

53

我相信这就是WeekFields.weekOfWeekBasedYear()WeekFields.weekOfYear() 之间的确切区别。

正如 Elliott Frisch 也提到的那样,您的主要困惑也可能是使用了错误的星期字段。您使用的 ISO 周字段将星期一定义为一周的第一天,将一年中的第一周定义为一年中至少包含 4 天的第一周。相反,你说你想要:

如果你认为那一周将从每年的Jan 01 开始 & 周开始是SUNDAY ...

来自您的 cmets:

...新的一周 (Week-01) 是否将始终从每年的 Jan 01 开始?

会的。

我怎样才能在这个 weekOfYear 上执行负 1 周?至于Jan 01,2020weekOfYear 将是Week-01 2020。我可以执行什么类型的 minus 1 week 来获得 weekOfYearWeek-53 2019 ?我试过 date.minusWeeks(1) 但它返回 Week-52 2019

    LocalDate dateInWeek1 = LocalDate.of(2020, Month.JANUARY, 3);
    int weekOfYear = dateInWeek1.get(wf.weekOfYear());
    System.out.println(weekOfYear);
    LocalDate dateInPreviousWeek;
    if (weekOfYear == 1) {
        dateInPreviousWeek = dateInWeek1.minusWeeks(1)
                .with(TemporalAdjusters.lastDayOfMonth());
    }
    else {
        dateInPreviousWeek = dateInWeek1.minusWeeks(1);
    }
    System.out.format("%s %2d%n", dateInPreviousWeek, dateInPreviousWeek.get(wf.weekOfYear()));

我们需要专门处理第 1 周的情况。当减去 1 周时,我们知道我们将进入前一年的 12 月。选择该月的最后一天将为我们提供 12 月 31 日。这将始终在一年的最后一周(通常是第 53 周;如果在从星期六开始的闰年,偶尔会在第 54 周,我认为 2000 年和 2028 年就是这样的例子)。

【讨论】:

  • 我同意你和@Elliott Frisch 的观点,我对比了两件事。但是,如果我使用您在这种情况下提供的内容,新的一周 (Week-01) 是否将始终从每年的Jan 01 开始?尽管如此,它每周有 1/2/3/4 天。与当年(2020 年)一样,Week-01 将从 Jan 01, 2020 变为 Jan 04,2020Week-02 将从 Jan 05,2020 变为 Jan 11,2020
  • 我有同样的后续问题。我怎样才能在这个 weekOfYear 上执行负 1 周?至于Jan 01,2020weekOfYear 将是Week-01 2020。我可以执行什么类型的 minus 1 week 来获得 weekOfYearWeek-53 2019 ?我试过date.minusWeeks(1),但它返回Week-52 2019
  • 有趣的补充问题@AshwinK。请参阅我的快速编辑。很抱歉,我现在没有时间进行更深入的讨论。我希望您能够自己进一步探索。
  • 感谢我的探索,我也会针对我使用的方法编辑原始问题。
【解决方案2】:

正如我在 cmets 中提到的,以及来自 IsoFields 的 Javadoc 链接,基于周的年份本身是相对于标准 ISO 预测年份定义的。它与标准年的不同之处在于它总是从星期一(不是星期日)开始。使用您发布的代码找到 53 周的年份应该很容易,从 1900 迭代到 2300 并解析给定年份最后一天的 WEEK_OF_WEEK_BASED_YEAR 并打印它为 53 的值。像,

DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("uuuu-MM-dd")
        .withChronology(IsoChronology.INSTANCE)
        .withResolverStyle(ResolverStyle.STRICT);

for (int i = 1900; i < 2300; i++) {
    LocalDate updatedDate = LocalDate.parse(String.format("%d-12-31", i), DATE_FORMATTER);
    if (updatedDate.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR) == 53) {
        System.out.println(i);
    }
}

我得到的前几个值是

1903
1908
1914
1920
1925
1931
1936
1942

稍微往前跳……

2009
2015
2020
2026

所以这一年(2020 年)有 53 周,而 2019 年没有。

【讨论】:

  • 如果您在这种情况下使用ISO proleptic year,则 2019 年有 52 周,这是正确的。是的,我错过了ISOFields 给出的JavaDoc,这是我的错。但是,如果您考虑 WeekStart: SUNDAY 和从每个 Jan 01 新的一周(即 Week-01)开始,那么 2019 年将有 53 周。上周 53 将有 3 天:29,30,31。这就是我在我的 OP 中发布的内容。
【解决方案3】:

这里的问题是,给定的年份要么有 365 天,要么有 366 天(后者是闰年),这意味着每年超过 52 周有 1 天或 2 天。周年的 ISO 系统可以解决这个问题,这意味着有时一年的第一周可能不是从 1 月 1 日开始,一年的最后一天也不会在第 52 周。这里的一种解决方法是只计算从每年年初开始的一周,例如

LocalDate firstOfYear = LocalDate.of(2019, Month.JANUARY, 1);
LocalDate updatedDate = LocalDate.of(2019, Month.DECEMBER, 30);

int diff = (int)ChronoUnit.DAYS.between(firstOfYear, updatedDate);
int week = 1 + (diff / 7);
System.out.println("The week number is: " + week);

【讨论】:

  • 这种手持转换是否必要?问是因为如果是的话我会很惊讶。
  • @Ole 我也会感到惊讶,但我不太了解 Java 8 日期 API。我认为我的回答至少是朝着正确的方向,即 OP 要么想要计算年周,要么将一周定义为从 1 月 1 日开始。
  • 我知道这个解决方案很简单。但我更关注应该提供一周的 Java 内部 API。因为您无法在其中设置周开始/周最少天数等。
【解决方案4】:

根据 ISO-8601 (https://www.cl.cam.ac.uk/~mgk25/iso-time.html),这是正确的。 2019 年没有日历周 53。根据定义,一年的第 01 周是今年有星期四的第一周,相当于包含一月第四天的那一周。 据我所知,这样做是为了避免没有工作日的 cw 1。

【讨论】:

  • 没错,我错过了文档 The first week of a week-based-year is the first Monday-based week of the standard * ISO year that has at least 4 days in the new year. 但是我可以使用哪些 Java API 来满足我的要求,其中 Week 总是从 1 月 1 日开始,它将首先结束即将到来的 SATURDAY(如新的一周开始是SUNDAY)
猜你喜欢
  • 2013-02-02
  • 1970-01-01
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多