Как найти общее количество недель в году на 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
Не совсем дубликат, но рекомендуется прочитать: stackoverflow.com/questions/44197872/…
Федерико Клез Каллока
1
Предложите дать свое определение недели.
Энди
4
Это 2020 год. Пожалуйста, избегайте использования проблемных старых API даты Dateи времени вокруг Calendar. Используйте java.timeвместо этого, это намного лучше и проще.
Забузард
Если (год прыжок) и (1 января - воскресенье), то 54 еще 53.
Акина
можешь дать мне немного кода?
Кумаресан Перумал

Ответы:

7

Используя определение Википедии здесь . Год имеет 53 недели, если 1 января - четверг, или 31 декабря - четверг, в противном случае - 52 недели. Это определение эквивалентно тому, которое вы использовали. Я думаю, что это гораздо проще проверить, так как вам не нужно проверять високосные годы.

Используя java.timeAPI Java 8 :

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 ()
Кумаресан Перумал
1
это дает 53 недели на 2021 год. Я думаю, что это неправильно. пожалуйста, проверьте это
Kumaresan Perumal
1
@KumaresanPerumal Вы уверены?
Подметальная
1
да, это работает. Я буду тестировать с 100 лет, а затем сказать вам. спасибо за ваши усилия
Кумаресан Перумал
1
Я проверил на JDK 1.8.0_101 и 1.8.0_121. Все еще получаю 52 недели в 2021 году, как мы должны.
Оле В.В.
7

ТЛ; др

Для стандартной недели 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 . Прекратить использование GregorianCalendar& Calendar; они были заменены по уважительным причинам.

ISO 8601 неделя

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

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

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

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

Если ваше определение отличается, см. Ответ 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 года.

Базилик Бурк
источник
Я в Индии. Должен ли я указать название страны?
Кумаресан Перумал
@ KumaresanPerumal Нет, часовой пояс для now. Поскольку вы хотите получить количество недель для определенного года, а не для текущего года, просто используйте YearWeek.of(yourYear, 1).
Подметальная
хорошо, спасибо @sweeper, я буду использовать его
Кумаресан Перумал
@KumaresanPerumal Wikipedia хранит этот список названий часовых поясов. Может быть немного устаревшим. Насколько я знаю, вся Индия использует часовой пояс Asia/Kolkata, в настоящее время со смещением +05: 30. В Java - код: ZoneId.of( "Asia/Kolkata" ). Для получения дополнительной информации и истории, см. Википедия, Время в Индии .
Василий Бурк
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());
    }
}

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

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

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

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

Код в вашем вопросе забавен тем, что он импортирует классы как из Joda-Time, так и из java.time, но использует старый Calendarи GregorianCalendarиз Java 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 недели каждый). Хотя может быть немного трудно убедить себя.
Оле В.В.
Это, кажется, дает 53 недели на все високосные годы, что не является правильным.
Оле В.В.
@ OleV.V. Хм, достаточно справедливо. Мне любопытно, как вычисления LocalDate работают под капотом тогда. Глупая Земля и ее слегка несовершенный временной цикл, делающий вещи более сложными, чем они должны быть.
Тим Хантер
LocalDate.datesUntil - это Java 9+
Жека Козлов
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>
Кумаресан Перумал
источник