Wie finde ich die gesamten Wochen eines Jahres in Java?

11

Ich arbeite an einem Projekt. Dort sollte ich die gesamten Wochen eines Jahres finden. Ich habe es mit dem folgenden Code versucht, aber ich bekomme die falsche Antwort: 2020 hat 53 Wochen, aber dieser Code gibt 52 Wochen.

Wo bin ich in diesem Code falsch gelaufen?

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

    }

}

Ausgabe:

52

Kumaresan Perumal
quelle
1
Nicht gerade ein Duplikat, aber empfohlene Lektüre: stackoverflow.com/questions/44197872/…
Federico klez Culloca
1
Schlagen Sie vor, Ihre Definition einer Woche anzugeben.
Andy
4
Es ist 2020. Bitte vermeiden Sie die Verwendung der lästigen alten Legacy-Date-API um Dateund Calendar. Verwenden Sie java.timestattdessen, es ist viel besser und einfacher.
Zabuzard
Wenn (Jahr ist Sprung) und (1. Januar ist Sonntag) dann 54 sonst 53.
Akina
Kannst du mir einen Code geben?
Kumaresan Perumal

Antworten:

7

Mit Hilfe der Wikipedia - Definition hier . Ein Jahr hat 53 Wochen, wenn der 1. Januar ein Donnerstag ist oder der 31. Dezember ein Donnerstag, andernfalls 52 Wochen. Diese Definition entspricht der von Ihnen verwendeten. Ich denke, dies ist eine viel einfachere Bedingung, da Sie nicht nach Schaltjahren suchen müssen.

Verwenden von Java 8 java.time APIs:

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;
Kehrmaschine
quelle
Die maximale Woche des Jahres 53. Ich denke, es ist gut @Naman, es gibt keine 54 Wochen, ich denke, die richtige Lösung ist LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasedYear ()). GetMaximum ()
Kumaresan Perumal
1
es gibt 53 Wochen für 2021. Ich denke, es ist falsch. Bitte testen Sie es
Kumaresan Perumal
1
@ KumaresanPerumal Bist du sicher?
Kehrmaschine
1
Ja, es funktioniert. Ich werde mit 100 Jahren testen, dann sag es dir.
Vielen
1
Ich habe auf JDK 1.8.0_101 und 1.8.0_121 getestet. Immer noch 52 Wochen im Jahr 2021, wie wir sollten.
Ole VV
7

tl; dr

Verwenden Sie für eine Standardwoche nach ISO 8601 die YearWeekKlasse aus der ThreeTen-Extra- Bibliothek mit einer ternären Anweisung.

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. 

Das ist, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

Definieren Sie "Woche"

Sie müssen eine Woche definieren. In Ihrem Codebeispiel hängt die Definition der Woche von der aktuellen Standardeinstellung der JVM ab Locale. Daher können Ihre Ergebnisse zur Laufzeit variieren.

Ihr Code verwendet auch schreckliche Datums- und Uhrzeitklassen , die vor Jahren durch die modernen java.time- Klassen ersetzt wurden. Verwenden Sie GregorianCalendar& nicht mehr Calendar. Sie wurden aus guten Gründen ersetzt.

ISO 8601 Woche

Die ISO 8601 - Standard definiert eine Woche als:

  • Die Wochen beginnen am Montag und enden am Sonntag.
  • Woche 1 hat den ersten Donnerstag des Kalenderjahres.

Diese Definition bedeutet:

  • Die ersten und letzten Tage eines wochenbasierten Jahres können die nachfolgenden / führenden Tage des vorherigen / folgenden Kalenderjahres sein.
  • Das wochenbasierte Jahr hat entweder 52 oder 53 vollständige Wochen.

Wenn Ihre Definition abweicht, lesen Sie die Antwort von Ole VV .

YearWeek:is53WeekYear

Wenn dies Ihrer Definition entspricht, fügen Sie Ihrem Projekt die ThreeTen-Extra- Bibliothek hinzu, um die in Java 8 und höher integrierte java.time- Funktionalität zu erweitern . Sie haben dann Zugriff auf die YearWeekKlasse.

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

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

Um nach einem bestimmten wochenbasierten Jahr zu fragen, wählen Sie einfach eine beliebige Woche des Jahres willkürlich aus. Zum Beispiel fragen wir für das wochenbasierte Jahr 2020 nach Woche 1.

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

Wochen lang = 53

weekStart = 2019-12-30

Beachten Sie, wie der erste Tag des wochenbasierten Jahres 2020 aus dem Kalenderjahr 2019 stammt.

Basil Bourque
quelle
Ich bin in Indien. Soll ich den Ländernamen angeben?
Kumaresan Perumal
@KumaresanPerumal Nein, die Zeitzone ist da für now. Da Sie die Wochenzahl für ein bestimmtes Jahr anstelle des aktuellen Jahres erhalten möchten, verwenden Sie einfach YearWeek.of(yourYear, 1).
Kehrmaschine
ok danke @sweeper Ich werde es benutzen
Kumaresan Perumal
@KumaresanPerumal Wikipedia führt diese Liste der Zeitzonennamen. Kann etwas veraltet sein. Soweit ich weiß, verwendet ganz Indien die Zeitzone Asia/Kolkata, derzeit mit einem Versatz von +05: 30. Im Java-Code : ZoneId.of( "Asia/Kolkata" ). Weitere Informationen und Geschichte finden Sie in Wikipedia, Zeit in Indien .
Basil Bourque
4

Die flexible Lösung

Dies sollte für jedes Wochennummerierungsschema funktionieren, das in einem WeekFieldsObjekt dargestellt werden kann.

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

Die Idee ist, die Wochennummer der letzten Woche des wochenbasierten Jahres zu ermitteln. Ich versuche es zuerst mit dem 31. Dezember, aber das kann in der ersten Woche des folgenden Jahres sein. Wenn ja, gehe ich eine Woche zurück.

Ich habe ziemlich gründlich getestet WeekFields.ISO, nicht so sehr mit anderen WeekFieldsObjekten, aber wie gesagt, ich glaube, es funktioniert.

Wenn Sie sicher sind, dass Sie immer ISO 8601 Wochen benötigen , sollten Sie sich für eine der guten Antworten von Sweeper und Basil Bourque entscheiden . Ich habe dies veröffentlicht, falls Sie eine flexiblere Lösung benötigen, die auch mit anderen Wochennummerierungsschemata funktioniert.

Verwenden Sie java.time

Der Code in Ihrer Frage ist insofern lustig, als er Klassen sowohl aus Joda-Time als auch aus java.time importiert, jedoch die alte Calendarund GregorianCalendarJava 1.1 verwendet. Diese Klassen waren schlecht gestaltet und mittlerweile längst veraltet. Sie sollten sie nicht verwenden. Joda-Time befindet sich im Wartungsmodus, danach hat java.time übernommen. Welches ist, was ich benutze und empfehle, dass Sie verwenden.

Ole VV
quelle
1

Ich denke, das sollte auch gut funktionieren:

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
quelle
Schöner Gedanke. Es gibt das richtige Ergebnis für 2020 (53 Wochen) sowie 2019 und 2021 (jeweils 52 Wochen). Es kann jedoch etwas schwierig sein, sich selbst zu überzeugen.
Ole VV
Es scheint jedoch 53 Wochen für alle Schaltjahre zu geben, was nicht korrekt ist.
Ole VV
@ OleV.V. Hmm, fair genug. Ich bin gespannt, wie die Berechnungen von LocalDate dann unter der Haube funktionieren. Dumme Erde und ein etwas unvollkommener Zeitzyklus, der die Dinge komplizierter macht, als sie sein müssen.
Tim Hunter
LocalDate.datesUntil ist Java 9+
ZhekaKozlov
0

Nachdem ich viel in Java 8 versucht hatte, konnte ich keine Lösung finden. dann habe ich Joda Datums- und Zeitabhängigkeit vorbereitet. Es gab mir eine gute Antwort, wie ich erwartet hatte

Code:

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

Maven-Abhängigkeit:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>
Kumaresan Perumal
quelle