Jak znaleźć całkowitą liczbę tygodni w Javie?

11

Pracuję nad projektem. Tam powinienem znaleźć całkowitą liczbę tygodni w roku. Próbowałem z następującym kodem, ale otrzymałem złą odpowiedź: 2020 ma 53 tygodnie, ale ten kod daje 52 tygodnie.

Gdzie popełniłem błąd w tym kodzie?

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

    }

}

Wynik:

52

Kumaresan Perumal
źródło
1
Niezupełnie duplikat, ale sugerowana lektura: stackoverflow.com/questions/44197872/...
Federico klez Culloca
1
Zaproponuj podanie definicji tygodnia.
Andy
4
Jest rok 2020. Unikaj używania starej, kłopotliwej starej daty API w pobliżu Datei Calendar. Użyj java.timezamiast tego, jest znacznie lepszy i prostszy.
Zabuzard
Jeśli (rok jest skokiem) i (1 stycznia to niedziela), to 54 jeszcze 53.
Akina
czy możesz dać mi kod?
Kumaresan Perumal

Odpowiedzi:

7

Korzystając z definicji Wikipedii tutaj . Rok ma 53 tygodnie, jeśli 1 stycznia jest czwartkiem lub 31 grudnia czwartkiem, w przeciwnym razie ma 52 tygodnie. Ta definicja jest równoważna definicji, której użyłeś. Myślę, że jest to o wiele łatwiejszy warunek do sprawdzenia, ponieważ nie musisz sprawdzać przez lata przestępne.

Korzystanie z java.timeinterfejsów API 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;
Zamiatarka
źródło
Maksymalny tydzień roku 53. Myślę, że to jest dobre @Naman nie ma 54 tygodnia, myślę, że poprawnym rozwiązaniem jest LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasedYear ()). GetMaximum ()
Kumaresan Perumal
1
daje 20 tygodni na 2021. Myślę, że to źle. przetestuj to
Kumaresan Perumal
1
@KumaresanPerumal Czy jesteś pewien?
Sweeper
1
tak Działa. Będę testować za 100 lat, a potem ci powiem. dzięki za twój wysiłek
Kumaresan Perumal
1
Testowałem na JDK 1.8.0_101 i 1.8.0_121. Nadal mam 52 tygodnie w 2021 roku, tak jak powinniśmy.
Ole VV
7

tl; dr

W przypadku standardowego tygodnia ISO 8601 użyj YearWeekklasy od biblioteki ThreeTen-Extra z instrukcją potrójną.

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. 

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

Zdefiniuj „tydzień”

Musisz zdefiniować tydzień. W przykładowym kodzie definicja tygodnia różni się w zależności od bieżącej wartości domyślnej maszyny JVMLocale . Dlatego wyniki mogą się różnić w czasie wykonywania.

Twój kod używa również strasznych klas daty i czasu, które zostały zastąpione wiele lat temu przez nowoczesne klasy java.time . Przestań używaćGregorianCalendar & Calendar; zostały zastąpione z dobrych powodów.

ISO 8601 tydzień

ISO 8601 norma definiuje tydzień jako:

  • Tygodnie zaczynają się w poniedziałek , a kończą w niedzielę.
  • Tydzień nr 1 ma pierwszy czwartek roku kalendarzowego.

Ta definicja oznacza:

  • Pierwszymi i ostatnimi kilkoma dniami roku tygodnia mogą być końcowe / wiodące dni poprzedniego / następnego roku kalendarzowego.
  • Rok tygodniowy ma 52 lub 53 pełne tygodnie.

Jeśli twoja definicja jest inna, zobacz odpowiedź Ole VV .

YearWeek:is53WeekYear

Jeśli jest to zgodne z definicją, dodaj bibliotekę ThreeTen-Extra do swojego projektu, aby rozszerzyć funkcjonalność java.time wbudowaną w Javę 8 i nowsze wersje . Masz wtedy dostęp do YearWeekklasy.

ZoneId z = ZoneId.of( "America/Montreal" ) ;
YearWeek yearWeekNow = YearWeek.now( z ) ;
boolean is53WeekYear = yearWeekNow.is53WeekYear() ;

int weeksLong = yearWeekNow.is53WeekYear() ? 53 : 52 ;

Aby zapytać o konkretny rok, wystarczy arbitralnie wybrać dowolny tydzień w roku. Na przykład w roku 2020 na tydzień prosimy o tydzień nr 1.

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

tygodnie Długo = 53

weekStart = 30.12.2019

Zwróć uwagę, jaki jest pierwszy dzień roku 2020 na podstawie tygodnia od roku kalendarzowego 2019.

Basil Bourque
źródło
Jestem w Indiach. Czy powinienem podać nazwę kraju?
Kumaresan Perumal
@KumaresanPerumal Nie, strefa czasowa jest dostępna now. Ponieważ chcesz, aby liczba tygodni dla konkretnego roku była wyświetlana zamiast bieżącego, po prostu użyj YearWeek.of(yourYear, 1).
Sweeper
ok dziękuję @sweeper Użyję go
Kumaresan Perumal
@KumaresanPerumal Wikipedia przechowuje tę listę nazw stref czasowych. Może być nieco nieaktualny. O ile mi wiadomo, wszystkie Indie korzystają ze strefy czasowej Asia/Kolkata, obecnie z przesunięciem +05: 30. W kodzie Java: ZoneId.of( "Asia/Kolkata" ). Aby uzyskać więcej informacji i historii, zobacz Wikipedia, Czas w Indiach .
Basil Bourque
4

Elastyczne rozwiązanie

Powinno to działać dla każdego schematu numeracji tygodni, który może być reprezentowany w WeekFieldsobiekcie.

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

Chodzi o to, aby znaleźć numer tygodnia ostatniego tygodnia roku opartego na tygodniu. Najpierw próbuję z 31 grudnia, ale może to być w pierwszym tygodniu następnego roku. Jeśli tak, wracam tydzień wcześniej.

Testowałem dość dokładnie z WeekFields.ISOinnymi WeekFieldsprzedmiotami, ale nie tak bardzo z innymi przedmiotami, ale jak powiedziałem, wierzę, że to działa.

Jeśli wiesz na pewno, że zawsze będziesz potrzebować tygodni ISO 8601 , myślę, że powinieneś wybrać jedną z dobrych odpowiedzi Sweeper i Basil Bourque . Wysłałem to na wypadek, gdybyś potrzebował bardziej elastycznego rozwiązania, które działałoby również z innymi schematami numeracji tygodni.

Użyj java.time

Kod w twoim pytaniu jest zabawny, ponieważ importuje klasy zarówno z Joda-Time, jak i z java.time, ale używa starej Calendari GregorianCalendarz Java 1.1. Klasy te zostały źle zaprojektowane i są już dawno przestarzałe, nie należy ich używać. Joda-Time jest w trybie konserwacji, java.time przejął po nim. Tego używam i polecam.

Ole VV
źródło
1

Myślę, że to też powinno działać dobrze:

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);
Tim Hunter
źródło
Miła myśl. Daje poprawny wynik za 2020 r. (53 tygodnie), a także 2019 i 2021 r. (52 tygodnie każdy). Przekonanie się może być jednak trochę trudne.
Ole VV
Wydaje się, że daje to 53 tygodnie na wszystkie lata przestępne, co nie jest poprawne.
Ole VV
@ OleV.V. Hmm, w porządku. Jestem zatem ciekawy, jak obliczenia LocalDate działają pod maską. Głupia Ziemia i jej nieco niedoskonały cykl czasowy, co czyni sprawy bardziej skomplikowanymi, niż muszą być.
Tim Hunter
LocalDate.datesUntil to Java 9+
ZhekaKozlov
0

Po wielu próbach w Javie 8. nie mogłem znaleźć rozwiązania. potem przygotowałem zależność Jody od daty i godziny. Dał mi dobrą odpowiedź, jak się spodziewałem

kod:

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

Zależność Maven:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>
Kumaresan Perumal
źródło