Comment trouver le total des semaines d'une année à Java?

11

Je travaille sur un projet. Là, je devrais trouver le total des semaines d'une année. J'ai essayé avec le code suivant, mais je reçois la mauvaise réponse: 2020 a 53 semaines, mais ce code donne 52 semaines.

Où me suis-je trompé dans ce code?

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

    }

}

Production:

52

Kumaresan Perumal
la source
1
Pas exactement un doublon, mais une lecture suggérée: stackoverflow.com/questions/44197872/…
Federico klez Culloca
1
Suggérez de fournir votre définition d'une semaine.
Andy
4
Nous sommes en 2020. Veuillez éviter d'utiliser l'ancienne API de date héritée gênante autour Dateet Calendar. Utilisez à la java.timeplace, c'est beaucoup mieux et plus simple.
Zabuzard
Si (l'année saute) et (le 1er janvier est le dimanche), 54 sinon 53.
Akina
pouvez-vous me donner du code?
Kumaresan Perumal

Réponses:

7

Utilisation de la définition Wikipedia ici . Une année compte 53 semaines si le 1er janvier est un jeudi ou le 31 décembre est un jeudi, sinon elle compte 52 semaines. Cette définition est équivalente à celle que vous avez utilisée. Je pense que c'est une condition beaucoup plus facile à vérifier, car vous n'avez pas besoin de vérifier les années bissextiles.

Utilisation des 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;
Balayeuse
la source
La semaine maximale de l'année 53. Je pense que c'est bon @Naman il n'y a pas 54 semaines, je pense que la bonne solution est LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasedYear ()). GetMaximum ()
Kumaresan Perumal
1
cela donne 53 semaines pour 2021. Je pense que c'est faux. veuillez le tester
Kumaresan Perumal
1
@KumaresanPerumal Êtes-vous sûr?
Sweeper
1
ouais ça marche. Je vais tester avec 100 ans puis je vous le dirai. merci pour votre effort
Kumaresan Perumal
1
J'ai testé sur JDK 1.8.0_101 et 1.8.0_121. Encore 52 semaines en 2021 comme il se doit.
Ole VV
7

tl; dr

Pour une semaine ISO 8601 standard, utilisez la YearWeekclasse de la bibliothèque ThreeTen-Extra avec une déclaration ternaire.

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. 

C'est, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

Définir la «semaine»

Vous devez définir une semaine. Dans votre exemple de code, la définition de week varie selon la valeur par défaut actuelle de la JVM Locale. Vos résultats peuvent donc varier lors de l'exécution.

Votre code utilise également de terribles classes de date-heure qui ont été remplacées il y a des années par les classes modernes de java.time . Arrêtez d'utiliser GregorianCalendar& Calendar; ils ont été remplacés pour de bonnes raisons.

ISO 8601 semaine

L' ISO 8601 norme définit une semaine comme:

  • Les semaines commencent le lundi et se terminent le dimanche.
  • La semaine # 1 a le premier jeudi de l'année civile.

Cette définition signifie:

  • Les premiers et derniers jours d'une année hebdomadaire peuvent être les jours de fin / début de l'année civile précédente / suivante.
  • L'année hebdomadaire comprend 52 ou 53 semaines complètes.

Si votre définition diffère, consultez la réponse d'Ole VV .

YearWeek:is53WeekYear

Si cela correspond à votre définition, ajoutez la bibliothèque ThreeTen-Extra à votre projet pour étendre la fonctionnalité java.time intégrée à Java 8 et versions ultérieures. Vous avez alors accès à la YearWeekclasse.

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

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

Pour vous renseigner sur une année en particulier, choisissez simplement n'importe quelle semaine de l'année. Par exemple, pour l'année 2020 basée sur la semaine, nous demandons la semaine # 1.

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

semaines Long = 53

weekStart = 2019-12-30

Remarquez comment le premier jour de l'année hebdomadaire 2020 est à partir de l'année civile 2019.

Basil Bourque
la source
Je suis en Inde. Dois-je spécifier le nom du pays?
Kumaresan Perumal
@KumaresanPerumal Non, le fuseau horaire est là pour now. Étant donné que vous souhaitez obtenir le nombre de semaines pour une année spécifique, au lieu de l'année en cours, utilisez simplement YearWeek.of(yourYear, 1).
Sweeper
ok merci @sweeper je vais l'utiliser
Kumaresan Perumal
@KumaresanPerumal Wikipedia conserve cette liste de noms de fuseaux horaires. Peut être légèrement obsolète. Pour autant que je sache, toute l'Inde utilise le fuseau horaire Asia/Kolkata, actuellement avec un décalage de +05: 30. Dans le code Java: ZoneId.of( "Asia/Kolkata" ). Pour plus d'informations et d'histoire, voir Wikipedia, Time in India .
Basil Bourque
4

La solution flexible

Cela devrait fonctionner pour tout schéma de numérotation de semaine qui peut être représenté dans un WeekFieldsobjet.

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

L'idée est de trouver le numéro de semaine de la dernière semaine de l'année basée sur la semaine. J'essaie d'abord avec le 31 décembre, mais cela peut être dans la première semaine de l'année suivante. Si c'est le cas, je retourne une semaine en arrière.

J'ai testé assez soigneusement avec WeekFields.ISO, pas tellement avec d'autres WeekFieldsobjets, mais comme je l'ai dit, je crois que cela fonctionne.

Si vous savez pertinemment que vous aurez toujours besoin d' ISO 8601 semaines, je pense que vous devriez choisir l'une des bonnes réponses de Sweeper et de Basil Bourque . J'ai posté cela au cas où vous auriez besoin d'une solution plus flexible qui fonctionnerait également avec d'autres schémas de numérotation des semaines.

Utilisez java.time

Le code dans votre question est drôle en ce qu'il importe des classes à la fois de Joda-Time et de java.time, tout en utilisant l'ancien Calendar et GregorianCalendarde Java 1.1. Ces classes étaient mal conçues et sont maintenant dépassées depuis longtemps, vous ne devriez pas les utiliser. Joda-Time est en mode maintenance, java.time a pris le relais. C'est ce que j'utilise et vous recommande d'utiliser.

Ole VV
la source
1

Je pense que cela devrait aussi bien fonctionner:

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
la source
Bonne idée. Il donne le résultat correct pour 2020 (53 semaines) ainsi que 2019 et 2021 (52 semaines chacun). Cependant, il peut être un peu difficile de se convaincre.
Ole VV
Cela semble donner 53 semaines pour toutes les années bissextiles, ce qui n'est pas correct.
Ole VV
@ OleV.V. Hmm, assez bien. Je suis alors curieux de voir comment les calculs de LocalDate fonctionnent sous le capot. Terre stupide et son cycle temporel légèrement imparfait, ce qui rend les choses plus compliquées qu'elles ne doivent l'être.
Tim Hunter
LocalDate.datesUntil est Java 9+
ZhekaKozlov
0

Après avoir essayé beaucoup en java 8. Je n'ai pas pu trouver de solution. puis j'ai préparé la dépendance de date et d'heure de Joda. Cela m'a donné une bonne réponse comme je m'y attendais

code:

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

Dépendance Maven:

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