Java LocalDate 如何将一年中的最后一周作为第 53 周而不是新年的第一周?

Java LocalDate How to get last week of year as 53rd week instead of 1st week of new year?

如果您认为那一周将从每年的 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 52 & WEEK_BASED_YEAR 2019.但不适用于 2019 年的最后一周(即第 53 周)

让我知道我在上面的代码中遗漏了什么。

这里的问题是给定的年份有 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);

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

正如我在评论中提到的,从您的 Javadoc link for IsoFields基于周的年份本身是相对于标准 ISO proleptic 年份定义的。它与标准年的不同之处在于它总是从 星期一(而不是星期日)开始。使用发布的代码可以很容易地找到有 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年没有。

    LocalDate date = LocalDate.of(2019, Month.DECEMBER, 30);
    int weekOfYear = date.get(WeekFields.SUNDAY_START.weekOfYear());
    System.out.println(weekOfYear);

此片段的输出是:

53

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

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

If you consider that week will start from Jan 01 of every year & week start is SUNDAY

来自您的评论:

… will the new week (Week-01) will always start on Jan 01 of every year ?

会的。

How can I perform minus 1 week on this weekOfYear ? As for Jan 01,2020, weekOfYear will be Week-01 2020. What type of minus 1 week I can perform to get weekOfYear as Week-53 2019 ? I tried with date.minusWeeks(1) but it returns 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 周时,我们知道我们将进入前一年的 12 月。选择该月的最后一天将为我们提供 12 月 31 日。这将始终在一年中的最后一周(通常是第 53 周;如果是星期六开始的闰年,偶尔会是第 54 周,我认为是 2000 年和 2028 年就是这方面的例子)。