¿Cómo encontrar el total de semanas de un año en Java?


11

Estoy trabajando en un proyecto Allí debería encontrar el total de semanas de un año. Intenté con el siguiente código, pero recibí la respuesta incorrecta: 2020 tiene 53 semanas, pero este código da 52 semanas.

¿Dónde me he equivocado en este código?

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

    }

}

Salida:

52


1
No es exactamente un duplicado, pero la lectura sugerida: stackoverflow.com/questions/44197872/…
Federico klez Culloca

1
Sugiera proporcionar su definición de una semana.
Andy

44
Es 2020. Por favor, evite el uso de la problemática de edad fecha legado api alrededor Datey Calendar. Utilice en su java.timelugar, es mucho mejor y más simple.
Zabuzard

Si (año es bisiesto) y (1 de enero es domingo) entonces 54 más 53.
Akina

¿me puede dar un código?
Kumaresan Perumal

Respuestas:


7

Usando la definición de Wikipedia aquí . Un año tiene 53 semanas si el 1 de enero es un jueves, o el 31 de diciembre es un jueves, de lo contrario tiene 52 semanas. Esta definición es equivalente a la que usó. Creo que esta es una condición mucho más fácil de verificar, ya que no es necesario verificar los años bisiestos.

Usando las java.timeAPI de 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;

La semana máxima del año 53. Creo que es bueno @Naman no hay 54 semanas, creo que la solución correcta es LocalDate.of (i, 1, 1) .range (WeekFields.ISO.weekOfWeekBasedYear ()). GetMaximum ()
Kumaresan Perumal

1
da 53 semanas para 2021. Creo que está mal. por favor probarlo
Kumaresan Perumal

1
@KumaresanPerumal ¿Estás seguro?
Barrendero

1
Sí, está funcionando. Voy a probar con 100 años y luego te digo. gracias por tu esfuerzo
Kumaresan Perumal

1
He probado en JDK 1.8.0_101 y 1.8.0_121. Todavía tengo 52 semanas en 2021 como deberíamos.
Ole VV

7

tl; dr

Para una semana estándar ISO 8601, use la YearWeekclase de la biblioteca ThreeTen-Extra con una declaración ternaria.

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. 

Es decir, YearWeek.of( 2020 , 1 ).is53WeekYear() ? 53 : 52

Definir "semana"

Necesitas definir una semana. En su ejemplo de código, la definición de semana varía según el valor predeterminado actual de la JVM Locale. Por lo tanto, sus resultados pueden variar en tiempo de ejecución.

Su código también usa terribles clases de fecha y hora que fueron reemplazadas hace años por las modernas clases java.time . Dejar de usar GregorianCalendar& Calendar; fueron reemplazados por buenas razones.

ISO 8601 semana

La ISO 8601 estándar define una semana como:

  • Las semanas comienzan el lunes y terminan el domingo.
  • La semana 1 tiene el primer jueves del año calendario.

Esa definición significa:

  • Los primeros y últimos días de un año basado en la semana pueden ser los días finales / iniciales del año calendario anterior / siguiente.
  • El año basado en la semana tiene 52 o 53 semanas completas.

Si su definición difiere, vea la Respuesta de Ole VV .

YearWeek:is53WeekYear

Si esto coincide con su definición, agregue la biblioteca ThreeTen-Extra a su proyecto para ampliar la funcionalidad java.time integrada en Java 8 y versiones posteriores. Entonces tienes acceso a la YearWeekclase.

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

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

Para preguntar sobre un año en particular basado en la semana, simplemente elija arbitrariamente cualquier semana del año. Por ejemplo, para el año 2020 basado en la semana, solicitamos la semana n. ° 1.

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

semanas de duración = 53

weekStart = 2019-12-30

Observe cómo el primer día del año basado en la semana de 2020 es del año calendario 2019.


Estoy en India. ¿Debo especificar el nombre del país?
Kumaresan Perumal

@KumaresanPerumal No, la zona horaria está ahí para now. Dado que desea obtener el recuento de semanas para un año específico, en lugar del año actual, simplemente utilícelo YearWeek.of(yourYear, 1).
Barrendero

ok gracias @sweeper lo
usaré

@KumaresanPerumal Wikipedia mantiene esta lista de nombres de zonas horarias. Puede estar un poco desactualizado. Hasta donde yo sé, toda la India usa la zona horaria Asia/Kolkata, actualmente con un desplazamiento de +05: 30. En el código de Java: ZoneId.of( "Asia/Kolkata" ). Para obtener más información e historia, consulte Wikipedia, Time in India .
Basil Bourque

4

La solución flexible

Esto debería funcionar para cualquier esquema de numeración semanal que se pueda representar en un WeekFieldsobjeto.

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

La idea es encontrar el número de semana de la última semana del año basado en la semana. Intento primero con el 31 de diciembre, pero puede ser en la primera semana del año siguiente. Si es así, voy una semana atrás.

He probado bastante a fondo WeekFields.ISO, no tanto con otros WeekFieldsobjetos, pero como dije, creo que funciona.

Si sabe con certeza que siempre necesitará ISO 8601 semanas, creo que debería ir con una de las buenas respuestas de Sweeper y Basil Bourque . Publiqué esto en caso de que necesitara una solución más flexible que funcionara también con otros esquemas de numeración de semanas.

Use java.time

El código en su pregunta es divertido porque importa clases tanto de Joda-Time como de java.time, pero usa el antiguo Calendary GregorianCalendarJava 1.1. Estas clases estaban mal diseñadas y ahora están desactualizadas, no debes usarlas. Joda-Time está en modo de mantenimiento, java.time se ha hecho cargo después. Que es lo que uso y recomiendo que uses.


1

Creo que esto también debería funcionar bien:

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

Buena idea. Da el resultado correcto para 2020 (53 semanas), así como para 2019 y 2021 (52 semanas cada uno). Sin embargo, puede ser un poco difícil convencerse a uno mismo.
Ole VV

Sin embargo, parece dar 53 semanas para todos los años bisiestos, lo cual no es correcto.
Ole VV

@ OleV.V. Hmm, bastante justo. Tengo curiosidad por saber cómo funcionan los cálculos de LocalDate debajo del capó. Estúpida Tierra y su ciclo de tiempo ligeramente imperfecto, lo que complica las cosas más de lo necesario.
Tim Hunter


0

Después de intentar mucho en Java 8. No pude encontrar una solución. entonces preparé la dependencia de fecha y hora de Joda. Me dio una buena respuesta como esperaba

código:

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

Dependencia de Maven:

<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <version>2.10.5</version>
</dependency>
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.