【问题标题】:How to find total weeks of a year in Java?如何在 Java 中找到一年中的总周数?
【发布时间】:2020-05-13 02:34:39
【问题描述】:

我正在做一个项目。在那里我应该找到一年中的总周数。我尝试使用以下代码,但得到错误答案:2020 年有 53 周,但此代码给出了 52 周。

这段代码哪里出错了?

package com.hib.mapping;

import java.time.LocalDate;
import java.time.temporal.WeekFields;
import java.util.Calendar;
import java.util.GregorianCalendar;

import org.joda.time.DateTime;

public class TestWeek {

    public static void main(String args[]) {
        System.out.println(getWeeks());
    }

    public static int getWeeks() {

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, 2020);
        cal.set(Calendar.MONTH, Calendar.JANUARY);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        GregorianCalendar gregorianCalendar = new GregorianCalendar();

        int weekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (gregorianCalendar.isLeapYear(2020)) {
            if (weekDay == Calendar.THURSDAY || weekDay == Calendar.WEDNESDAY)
                return 53;
            else
                return 52;
        } else {
            if (weekDay == Calendar.THURSDAY)
                return 53;
            else
                return 52;
        }

    }

}

输出:

52

【问题讨论】:

  • 不完全重复,但建议阅读:stackoverflow.com/questions/44197872/…
  • 建议提供一周的定义。
  • 现在是 2020 年。请避免在 DateCalendar 周围使用麻烦的旧旧日期 api。改用java.time,更好更简单。
  • 如果(年份是闰年)并且(1 月 1 日是星期日)则为 54,否则为 53。
  • 你能给我一些代码吗?

标签: java date java-8 week-number


【解决方案1】:

使用维基百科定义here。如果 1 月 1 日是星期四,一年有 53 周,或者 12 月 31 日是星期四,否则有 52 周。此定义等同于您使用的定义。我认为这是一种更容易检查的条件,因为您不需要检查闰年。

使用 Java 8 java.time API:

int year = 2020;
boolean is53weekYear = LocalDate.of(year, 1, 1).getDayOfWeek() == DayOfWeek.THURSDAY ||
        LocalDate.of(year, 12, 31).getDayOfWeek() == DayOfWeek.THURSDAY;
int weekCount = is53weekYear ? 53 : 52;

【讨论】:

  • 一年中的最大周数为 53。我认为这很好 @Naman 没有 54 周,我认为正确的解决方案是 LocalDate.of(i, 1, 1).range(WeekFields. ISO.weekOfWeekBasedYear()).getMaximum()
  • 它给出了 2021 年的 53 周。我认为这是错误的。请测试一下
  • @KumaresanPerumal Are you sure?
  • 是的,它正在工作。我会测试 100 年然后告诉你。感谢您的努力
  • 我已经在 J​​DK 1.8.0_101 和 1.8.0_121 上进行了测试。我们应该在 2021 年获得 52 周。
【解决方案2】:

我认为这也应该可以正常工作:

int year = 2020;
long numOfWeeks = LocalDate.of(year, 1, 1).datesUntil(LocalDate.of(year, 12, 31), Period.ofDays(7)).count();
System.out.println("Weeks: " + numOfWeeks);

【讨论】:

  • 好主意。它给出了 2020 年(53 周)以及 2019 年和 2021 年(各 52 周)的正确结果。不过,说服自己可能有点困难。
  • 不过,似乎所有闰年都有 53 周,这是不正确的。
  • @OleV.V.嗯,够公平的。我很好奇 LocalDate 的计算是如何在幕后工作的。愚蠢的地球,而且它的时间周期有点不完美,让事情变得比他们必须的要复杂。
  • LocalDate.datesUntil 是 Java 9+
【解决方案3】:

在 java 8 中尝试了很多之后。我找不到解决方案。然后我准备了 Joda 日期和时间依赖项。正如我所料,它给了我一个很好的答案

代码:

for (int i = 2020; i < 2100; i++) {
  int weeks = new DateTime().withYear(i).weekOfWeekyear().getMaximumValue();
  System.out.println(i + " years : " + weeks); 
}

Maven 依赖:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>

【讨论】:

    【解决方案4】:

    tl;博士

    对于标准 ISO 8601 周,请使用 ThreeTen-Extra 库中的 YearWeek 类和三元语句。

    YearWeek          // Represents an entire week of a week-based-year.
    .of( 2020 , 1 )   // Pass the number of the week-based-year (*not* calendar year), and a week number ranging from 1 to 52 or 1 to 53.
    .is53WeekYear()   // Every standard week-based-year has either 52 or 52 complete weeks.
    ? 53              // Ternary statement returns 53 if the predicate returns True, …
    : 52              // … otherwise returns 52. 
    

    YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

    定义“周”

    您需要定义一周。在您的代码示例中,星期的定义因 JVM 当前默认的 Locale 而异。因此,您的结果可能会在运行时有所不同。

    您的代码还使用了多年前被现代 java.time 类取代的糟糕的日期时间类。停止使用GregorianCalendar & Calendar;他们被替换是有充分理由的。

    ISO 8601 周

    ISO 8601 标准 defines a week 为:

    • 每周从星期一开始,在星期日结束。
    • 第 1 周是日历年的第一个星期四

    这个定义意味着:

    • 一周年的头几天和最后几天可能是上一个/下一个日历年的尾数/前几天。
    • 基于周的年有 52 或 53 个完整的周。

    如果您的定义不同,请参阅Answer by Ole V.V.

    YearWeek:is53WeekYear

    如果这符合您的定义,则将ThreeTen-Extra 库添加到您的项目中,以扩展Java 8 及更高版本中内置的java.time 功能。然后您可以访问YearWeek 类。

    ZoneId z = ZoneId.of( "America/Montreal" ) ;
    YearWeek yearWeekNow = YearWeek.now( z ) ;
    boolean is53WeekYear = yearWeekNow.is53WeekYear() ;
    
    int weeksLong = yearWeekNow.is53WeekYear() ? 53 : 52 ;
    

    要询问基于周的特定年份,只需随意选择一年中的任何一周。例如,对于基于周的 2020 年,我们要求第 1 周。

    int weeksLong = YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52 ;
    LocalDate weekStart = YearWeek.of( 2020 , 1 ).atDay( DayOfWeek.MONDAY ) ;
    

    weeksLong = 53

    weekStart = 2019-12-30

    请注意 2020 年一周年的第一天与 2019 年日历年的差异。

    【讨论】:

    • 我在印度。我应该指定国家名称吗?
    • @KumaresanPerumal 不,now 的时区在那里。由于您想获取特定年份的周数,而不是当前年份,因此只需使用 YearWeek.of(yourYear, 1)
    • @KumaresanPerumal 维基百科保留this list 的时区名称。可能有点过时了。据我所知,印度所有使用的时区是Asia/Kolkata,目前的偏移量为+05:30。在 Java 代码中:ZoneId.of( "Asia/Kolkata" )。有关详细信息和历史记录,请参阅 Wikipedia,Time in India
    【解决方案5】:

    灵活的解决方案

    这应该适用于可以在 WeekFields 对象中表示的任何周编号方案。

    public static int noOfWeeks(WeekFields wf, int year) {
        LocalDate lastDayOfYear = YearMonth.of(year, Month.DECEMBER).atEndOfMonth();
        if (lastDayOfYear.get(wf.weekBasedYear()) > year) { // belongs to following week year
            return lastDayOfYear.minusWeeks(1).get(wf.weekOfWeekBasedYear());
        }
        else {
            return lastDayOfYear.get(wf.weekOfWeekBasedYear());
        }
    }
    

    这个想法是找到基于年份的一周的最后一周的周数。我先在 12 月 31 日尝试,但那可能是在第二年的第一周。如果是这样,我会回去一星期。

    我已经对 WeekFields.ISO 进行了相当彻底的测试,对其他 WeekFields 对象的测试不多,但正如我所说,我相信它有效。

    如果您知道您总是需要ISO 8601 周,我认为您应该选择by Sweeperby Basil Bourque 中的一个好的答案。如果您需要更灵活的解决方案,也可以与其他周编号方案一起使用,我发布了此信息。

    使用 java.time

    您问题中的代码很有趣,因为它从 Joda-Time 和 java.time 导入类,但使用 Java 1.1 中的旧 CalendarGregorianCalendar。这些类设计得很糟糕,现在已经过时了,你不应该使用它们。 Joda-Time 处于维护模式,java.time 已经接管了它。这是我使用并建议您使用的。

    【讨论】:

      【解决方案6】:

      以下代码对我有用。

      public static int getTotalWeeksInYear(int year){
              int totalWeeks=0;
              Calendar calendar=Calendar.getInstance();
              for(int month=0;month<12;mmonth++){
                  int day=1;
                  do{
                      calendar.set(year, month, day);
                      if(calendar.get(Calendar.DAY_OF_WEEK)==5)
                          totalWeeks++;
                      day++;
                  }while (day <=calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
              }
              return totalWeeks;
      }
      

      使用 Java.time

      public static long getTotalWeekByLocalDate(LocalDate ldate) {
      
              long weeksInYear = IsoFields.WEEK_OF_WEEK_BASED_YEAR.rangeRefinedBy(ldate).getMaximum();
      
              return weeksInYear;
          }
      

      【讨论】:

      • 我当然推荐 java.time 代码。与其说它更短,不如说它首先更容易理解。你为什么不把它放在第一位?
      • 我也支持java.time。但是在用户尝试使用日历类解决问题的问题中。
      • 这个问题真正要问的问题尚不清楚。代码导入java.time.LocalDatejava.time.temporal.WeekFields。我的解释是,要么 java.time 真的是 OP 想要的,要么她或他根本没有决定。
      猜你喜欢
      • 2019-12-24
      • 2017-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-30
      • 1970-01-01
      • 2017-11-16
      • 1970-01-01
      相关资源
      最近更新 更多