【问题标题】:How can I find all week numbers of month that are the # week of month in a year with Java?如何使用 Java 找到一年中 # 月的所有周数?
【发布时间】:2019-12-24 22:34:55
【问题描述】:

我希望构建一个函数,该函数返回一个数组,其中包含一年中前几个月的所有周数,这些周数与某个特定月份的周数相同。

我使用星期一作为一周的第一天,我使用当月的第一个星期一作为本月的第一周。

输入:一年中的一周和一年。例如 27 日和 2019 年。7 月的第一周 (7)。

输出:月份周数数组。例如 [2, 6, 10, 14, 19, 23, 27]。

我的尝试

private void getResult(int weekYear)
{
    LocalDate date = LocalDate.now();
    final int weekNumber = 27;
    LocalDate newDate = date.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, weekNumber);
    int month = newDate.getMonthValue();;
        
    int weekMonth = LocalDate.from(newDate).get(WeekFields.ISO.weekOfMonth());
        
    System.out.println(newDate);
    System.out.println(month);
    System.out.println(weekMonth);
        
    ArrayList<Integer> list = new ArrayList<Integer>();
        
    for (int i = 1; i <= month; i++)
    {
        LocalDate tempDate = date.withYear(2019).withMonth(i).with(WeekFields.ISO.weekOfMonth(), weekMonth);
        int tempYear = LocalDate.from(tempDate).get(WeekFields.ISO.weekOfWeekBasedYear());
        list.add(tempYear);
    }
        
    list.forEach((e) -> System.out.print(e + " "));
}
int weekYear = 27;
getResult(weekYear);

我得到了什么:[1 6 10 14 18 23 27]。

我在寻找什么:我有两个问题:

  1. 第一个:得到的结果与预期的不同。我认为问题是由于我没有指定如何计算每月的第一周(每月的第一个星期一)。这样对吗?我该如何解决?
  2. 第二个:有什么更好的解决方案?

【问题讨论】:

  • 我认为你应该分开你的问题。问题 #1 是关于 StackOverflow 的主题。问题 #2 在codereview.stackexchange.com 你有一个有效的实现之后会更好。
  • @Freiheit 感谢您的关注。我会听从你的建议。
  • 我觉得这个功能可以解决问题:firstIntMonth docs.oracle.com/javase/8/docs/api/java/time/temporal/…。切换到LocalDate tempDate = date.withYear(2019).withMonth(i).with(WeekFields.ISO.weekOfMonth(), weekMonth).with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); 返回正确的列表。
  • @lezan 没有。首先,我得到2 6 10 14 14 23 27 ,注意14 出现了两次。其次,如果你的出发点恰好在一个月的第二周或第四周,firstInMonth 显然不会给你。

标签: java date time dayofweek java-time


【解决方案1】:

这里的关键是理解几点:

  1. 您以两种不同的方式计算周数。对于您使用 ISO 编号的一年中的一周:一年中的第一周至少包括新年的 4 天。对于一个月中的一周,您计算的是星期一(您可能会说一个月的第一周包括一个月的 天,而不是四天)。
  2. 周数可能并不总是存在。如果您的起点是该月的第 0 周或第 5 周,则上个月可能没有该周。

得到的结果与预期的不同。我觉得 问题是由于我没有指定如何计算 每月的第一周(每月的第一个星期一)。这样对吗?如何 我能解决吗?

你是对的。要计算每月的星期一,您可以使用:

        LocalDate tempDate = date.withYear(2019)
                .withMonth(i)
                .with(ChronoField.DAY_OF_WEEK, DayOfWeek.MONDAY.getValue())
                .with(ChronoField.ALIGNED_WEEK_OF_MONTH, weekMonth);

(当然DayOfWeek.MONDAY.getValue()只是说1的罗嗦方式,但更好地传达了意图,所以我更喜欢它。)

对您的代码进行此更改后,输出是预期的:

2 6 10 14 19 23 27

密钥是ChronoField.ALIGNED_WEEK_OF_MONTH。一个月的对齐周数从该月的 1 日开始,并且始终为 7 天,与一周中的哪几天无关。第一个对齐的周是从每月的 1 日到 7 日,如果是从 8 日到 14 日,则为第 2 个对齐的周,依此类推。由于我们已将星期几设置为星期一,将对齐的周设置为 1 为我们提供了第一个星期一月份等。

我们还没有完成。如果我将weekNumber 设置为 40,我得到:

2 6 10 14 14 23 27 27 36 41

我原本预计 40 会是列表中的最后一个数字,但它不存在。 2019 年的第 40 周是从 9 月 30 日星期一到 10 月 6 日,所以如果我理解正确,你想要那些有第 5 周的月份的第 5 周。这让我们回到了并非所有月份都有第 5 周的问题(因为他们没有 5 个星期一)。发生的情况是,由于我在星期二运行您的代码,因此以第 40 周的星期二(即 10 月 1 日)为起点,因此给了我每个月的第 1 周而不是第 5 周。

有更好的解决方案吗?你能推荐一个吗?

我真的不能。你所拥有的一切都很好。

只有你没有使用 int weekYear 参数。您可能希望使用它来代替您的 weekNumber 局部变量。在任何情况下,您都应该删除其中一个并使用另一个。

还有这个不相关的提示:您对LocalDate.from(someLocalDate) 的使用是多余的,因为它只是再次给您相同的LocalDate(相同的对象或相同的对象,我不知道也不关心)。在这些情况下只需使用someLocalDate

【讨论】:

  • 感谢您的回答。我需要一些时间来了解您写的内容,我会尽快提供反馈。
  • 我犯了几个错误:首先我没有考虑到你在第 1 点所说的话。我不能将每月的第一个星期一用作每月的第一周。我认为对一年中的一周和一个月的一周使用两种不同的表示形式(iso 和 not-iso)不好,会造成太多混乱。说这个 [1 6 10 14 18 23 27] 是一个月的第一周有 iso rappresentation,对吧?
  • 第二个错误,当您说“只有您没有使用..”时,您是对的:我在 stackoverflow 上报告了错误,这是我的代码的简化版本。我在这里做正确的事情。第三个错误,当您说“还有这个不相关的提示..”时:我可以使用int weekMonth = newDate.get(WeekFields.ISO.weekOfMonth());int tempYear = tempDate,get(WeekFields.ISO.weekOfWeekBasedYear());,对吗?
  • 是的,我同意每个月的第一个 ISO 周是 1 6 10 14 18 23 27。是的,int weekMonth = newDate.get(WeekFields.ISO.weekOfMonth());int tempYear = tempDate.get(WeekFields.ISO.weekOfWeekBasedYear()); 将给出与您的代码相同的结果在那些地方。 @lezan
  • 那么如果 w6-2019 是 2 月的第一周,那么 w5-2019 呢?是一月的最后一周吗?一月会是一个有 5 周的月份吗?
猜你喜欢
  • 2017-12-07
  • 1970-01-01
  • 2020-05-13
  • 1970-01-01
  • 2015-11-14
  • 2015-10-22
  • 2018-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多