如何在Java中查找一年的总周数?


11

我正在做一个项目。我应该在那里找到一年的总周数。我尝试使用以下代码,但得到的答案是错误的: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



1
建议提供您对一周的定义。
安迪

4
现在是2020年。请避免在Date和周围使用麻烦的旧版传统日期api Calendarjava.time相反,使用它会更好,更简单。
Zabuzard

如果(今年是闰年)和(1月1日是星期天),那么其他54 53
森明

你能给我一些代码吗?
Kumaresan Perumal

Answers:


7

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

使用Java 8 java.timeAPI:

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 ()
Kumaresan Perumal

1
它为2021年提供了53周的时间。我认为这是错误的。请测试一下
Kumaresan Perumal

1
@KumaresanPerumal 您确定吗?
清道夫

1
是的,它正在工作。我将测试100年,然后告诉您。感谢您的努力
Kumaresan Perumal

1
我已经在JDK 1.8.0_101和1.8.0_121上进行了测试。到2021年,我们仍需要52周的时间。
Ole VV

7

tl; dr

对于一个标准的ISO 8601周,使用YearWeek从类 ThreeTen-Extra库中三元声明。

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类已在几年前取代了这个类。停止使用GregorianCalendarCalendar; 它们被替换是有充分的理由的。

ISO 8601周

ISO 8601标准定义了一个星期为:

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

该定义意味着:

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

如果您的定义不同,请参阅《Ole VV答案》

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 ) ;

周长= 53

weekStart = 2019-12-30

请注意,2020年基于周的年份的第一天是如何从2019日历年开始的。


我在印度。我应该指定国家名称吗?
Kumaresan Perumal

@KumaresanPerumal不,所在的时区为now。由于您要获取特定年份而不是当前年份的周数,因此只需使用YearWeek.of(yourYear, 1)
清扫器

好的,谢谢@sweeper我将使用它
Kumaresan Perumal

@KumaresanPerumal Wikipedia保留了时区名称列表。可能有些过时了。据我所知,所有印度使用的时区为Asia/Kolkata,当前偏移为+05:30。在Java代码中:ZoneId.of( "Asia/Kolkata" )。有关更多信息和历史记录,请参见Wikipedia,印度时间
罗勒·布尔克

4

灵活的解决方案

这适用于可以在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周,那么我认为您应该选择SweeperBasil Bourque提供的一个很好的答案。我发布了此信息,以防您需要更灵活的解决方案,该解决方案也可以与其他星期编号方案一起使用。

使用java.time

您问题中的代码很有趣,因为它从Joda-Time和java.time都导入了类,但使用了旧版本CalendarGregorianCalendarJava 1.1。这些类的设计很差,现在已经过时了,您不应使用它们。Joda-Time处于维护模式,java.time在此之后接管了工作。我使用的是哪种,建议您使用。


1

我认为这也应该很好:

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周)的正确结果。但是,说服自己可能有些困难。
Ole VV

但是,似乎所有leap年都给了53周的时间,这是不正确的。
Ole VV

@ OleV.V。嗯,还算公平。我很好奇,那时LocalDate的计算是如何进行的。愚蠢的地球,时间周期略微不完美,这使事情变得比原来复杂得多。
蒂姆·亨特


0

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

码:

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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.