Как найти общее количество недель в году в Java? - PullRequest
11 голосов
/ 27 января 2020

Я работаю над проектом. Там я должен найти общее количество недель в году. Я попытался с помощью следующего кода, но я получил неправильный ответ: 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

Ответы [ 5 ]

7 голосов
/ 28 января 2020

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. Так что ваши результаты могут отличаться во время выполнения.

В вашем коде также используются ужасные классы даты и времени, которые были заменены годами go современными java .time . Прекратите использовать GregorianCalendar & Calendar; они были заменены по уважительным причинам.

ISO 8601 неделя

ISO 8601 стандарт определяет неделю как:

  • недели начинаются в понедельник , заканчиваются в воскресенье.
  • Неделя № 1 имеет первый четверг календарного года.

Это определение означает:

  • Первые и последние несколько дней в году недели могут быть последними / ведущими днями предыдущего / следующего календарного года.
  • недельный год содержит 52 или 53 полных недели.

Если ваше определение отличается, см. Answer by Ole VV .

YearWeek:is53WeekYear

Если это соответствует вашему определению, то добавьте в ваш проект библиотеку ThreeTen-Extra , чтобы расширить встроенную функциональность java .time . Java 8 и позже. Затем у вас есть доступ к классу 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 ) ;

daysLong = 53

weekStart = 2019-12-30

Обратите внимание, как первый день недели 2020 года совпадает с календарным годом 2019.

7 голосов
/ 27 января 2020

Используя определение Википедии здесь . В году 53 недели, если 1 января - четверг, или 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;
4 голосов
/ 29 января 2020

Гибкое решение

Это должно работать для любой схемы нумерации недель, которая может быть представлена ​​в 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());
    }
}

Идея состоит в том, чтобы найти номер недели для последняя неделя года. Я пробую сначала с 31 декабря, но это может быть в первую неделю следующего года. Если так, я go неделю назад.

Я довольно тщательно протестировал с WeekFields.ISO, а не с другими WeekFields объектами, но, как я уже сказал, я считаю, что это работает.

Если вы точно знаете, что вам всегда будут нужны ISO 8601 недели, я думаю, вам следует go с одним из хороших ответов от Sweeper и от Базилик Бурк . Я разместил это на тот случай, если вам нужно более гибкое решение, которое будет работать и с другими схемами нумерации на неделю.

Используйте java .time

Код в вашем вопросе забавен тем, что он импортирует классы как из Joda-Time, так и из java .time, но используют старые Calendar и GregorianCalendar из Java 1.1. Эти классы были плохо спроектированы и сейчас давно устарели, не стоит их использовать. Joda-Time находится в режиме обслуживания, java .time вступил во владение после этого. Именно это я и рекомендую использовать.

1 голос
/ 27 января 2020

Я думаю, что это должно работать просто отлично:

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);
0 голосов
/ 28 января 2020

После много попыток в 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>
...