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


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;

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.


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.


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

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


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>
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.