¿Por qué dec 31 2010 devuelve 1 como semana del año?

Por ejemplo:

Calendar c = Calendar.getInstance(); DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

Imprime 1

Lo mismo sucede con la hora de Joda.

🙂

La definición de Semana del año depende de la Locale .

Cómo se define en los EE. UU. Se discute en las otras publicaciones. Por ejemplo, en Alemania ( DIN 1355-1 / ISO 8601 ): la primera semana * del año es la primera semana con 4 o más días en el año nuevo.

* el primer día de la semana es el lunes y el último día de la semana es el domingo

Y el Calendar de Java presta atención a la configuración regional. Por ejemplo:

 public static void main(String[] args) throws ParseException { DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); Date lastDec2010 = sdf.parse("31/12/2010"); Calendar calUs = Calendar.getInstance(Locale.US); calUs.setTime(lastDec2010); Calendar calDe = Calendar.getInstance(Locale.GERMAN); calDe.setTime(lastDec2010); System.out.println( "us: " + calUs.get( Calendar.WEEK_OF_YEAR ) ); System.out.println( "de: " + calDe.get( Calendar.WEEK_OF_YEAR ) ); } 

huellas dactilares:

 us: 1 de: 52 

AÑADIDO Para los EE. UU. (Y puedo pensar que es lo mismo para México) la 1. Semana del Año es la semana a la que pertenece el 1. Enero. – Entonces, si 1. Januar es un sábado, entonces el viernes anterior (31. Dic) pertenece la misma semana, y en este caso este día pertenece a la 1. Semana del Año 2011.

Los valores calculados para el campo WEEK_OF_YEAR van del 1 al 53. La semana 1 para un año es el primer período de siete días que comienza en getFirstDayOfWeek () que contiene al menos días getMinimalDaysInFirstWeek () a partir de ese año. Por lo tanto, depende de los valores de getMinimalDaysInFirstWeek (), getFirstDayOfWeek () y el día de la semana del 1 de enero. Las semanas entre la semana 1 de un año y la semana 1 del año siguiente se numeran secuencialmente de 2 a 52 o 53 (como necesario).

Para determinar si esa semana es la última semana de 2010 o la primera de 2011, Java usa getMinimalDaysInFirstWeek javadoc . Si ese método devuelve 7, la primera semana en que todos los días de la semana son del mismo año es la primera semana, si devuelve 1, entonces la primera semana con cualquier día del próximo año es la primera semana del próximo año.

En este caso, el primero de enero de 2011 es un sábado, por lo que se considera la primera semana de 2011, siempre y cuando desee una semana con un día para considerarla ya la primera semana del año siguiente, si no lo hace entonces hazlo:

 Calendar c = Calendar.getInstance(); c.setMinimalDaysInFirstWeek(7);//anything more than 1 will work in this year DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); System.out.println( c.get( Calendar.WEEK_OF_YEAR ) ); 

devoluciones:

 52 

IIRC, la primera semana con una fecha del 1 de enero es la semana 1.
Es por eso que la semana 1 se devuelve el 31/12/2010.
Pruébalo el 31/12/2011 y obtendrás 52.

Editar: la semana es específica de la configuración regional, a veces definida como de domingo a sábado, a veces definida como de lunes a domingo

Esto se debe a que el comienzo de la semana depende del lugar.

En los Estados Unidos, la semana 1 comienza el domingo anterior al 1 de enero. En 2010, es el 26 de diciembre. Por eso, el 31 de diciembre sigue siendo la semana 1.

En Europa, la semana 1 comienza el lunes antes del 1 de enero. En 2010 es el 27 de diciembre. Por eso también en Europa el 31 de diciembre sigue siendo la semana 1.

tl; dr

 java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK ) ) .get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) 

52

O bien, agregue una biblioteca, y luego …

 org.threeten.extra.YearWeek.from( // Convert from a `LocalDate` object to a `YearWeek` object representing the entire week of that date's week-based year. java.time.LocalDate.parse( "31/12/2010" , DateTimeFormatter.ofLocalizedDate( FormatStyle.SHORT ).withLocale( Locale.UK ) ).getWeek() // Extract an integer number of that week of week-based-year, either 1-52 or 1-53 depending on the year. 

52

java.time

Como otros señalaron, la definición de una semana varía según la Locale en la antigua clase java.util.Calendar .

Esa clase problemática, y su compañero java.util.Date , han sido suplantados por el marco java.time integrado en Java 8 y posterior.

La clase IsoFields define una semana con el estándar ISO 8601 : la semana siempre comienza el lunes y la semana 1 el primer jueves del año calendario.

Obtenga el momento actual.

 ZoneId zoneId = ZoneId.of ( "America/Montreal" ); ZonedDateTime now = ZonedDateTime.now ( zoneId ); 

Pregunte sobre el año estándar basado en la semana.

 int week = now.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR ); int weekYear = now.get ( IsoFields.WEEK_BASED_YEAR ); 

Definición de semana estándar

Hay muchas maneras de definir “una semana” y “primera semana del año”.

Sin embargo, hay una definición estándar principal : el estándar ISO 8601 . Ese estándar define las semanas del año, incluida la primera semana del año.

la semana con el primer jueves del año

Una semana estándar comienza el lunes y termina el domingo.

La semana n. ° 1 de un año basado en la semana tiene el primer jueves del año calendario.

Las clases java.time admiten la semana ISO 8601 a través de la clase IsoFields , que contiene tres constantes que implementan TemporalField :

  • WEEK_OF_WEEK_BASED_YEAR
  • WEEK_BASED_YEAR
  • WEEK_BASED_YEARS

Llame a LocalDate::get para acceder a TemporalField .

 LocalDate ld = LocalDate.parse( "2010-12-31" ) ; int weekOfWeekBasedYear = ld.get( IsoFields.WEEK_OF_WEEK_BASED_YEAR ) ; int yearOfWeekBasedYear = ld.get( IsoFields.WEEK_BASED_YEAR ) ; 

ld.toString (): 2010-12-31

semana de semana de año: 52

yearOfWeBasedYear: 2010

Formato de cadena ISO 8601

La norma ISO 8601 define un formato de texto así como un significado para los valores de la semana-año base: yyyy-Www . Para una fecha específica, agregue el día de la semana, numerado del 1 al 7, de lunes a domingo: yyyy-Www-d .

Construye una cadena de este tipo

 String outputWeek = String.format( "%04d" , yearOfWeekBasedYear ) + "-W" + String.format( "%02d" , weekOfWeekBasedYear ) ; String outputDate = outputWeek + "-" + ld.getDayOfWeek().getValue() ; 

2010-W52-5

YearWeek

Este trabajo es mucho más fácil si agrega la biblioteca ThreeTen-Extra a su proyecto. Luego usa la clase YearWeek .

 YearWeek yw = YearWeek.from( ld ) ; // Determine ISO 8601 week of a `LocalDate`. 

Genera la cadena estándar.

 String output = yw.toString() ; 

2010-W52

Y parse.

 YearWeek yearWeek = YearWeek.parse( "2010-W52" ) ; 

yearWeek.toString (): 2010-W52

Determine una fecha. Pase un objeto enum de java.time.DayOfWeek para el día de la semana de lunes a domingo.

 LocalDate localDate = yw.atDay( DayOfWeek.MONDAY ) ; 

localDate.toString (): 2010-12-27

Recomiendo encarecidamente agregar esta biblioteca a su proyecto. Entonces puedes pasar objetos inteligentes en lugar de tontos. Hacerlo hace que su código sea más autodocumentado, proporciona seguridad de tipo y garantiza valores válidos.


Acerca de java.time

El marco java.time está integrado en Java 8 y posterior. Estas clases suplantan a las problemáticas antiguas clases heredadas de fecha y hora como java.util.Date , Calendar y SimpleDateFormat .

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Para obtener más información, consulte el Tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .

Usando un controlador JDBC que cumpla con JDBC 4.2 o posterior, puede intercambiar objetos java.time directamente con su base de datos. No necesita cadenas ni clases java.sql. *.

¿Dónde obtener las clases de java.time?

  • Java SE 8 , Java SE 9 y posterior
    • Incorporado.
    • Parte de la API Java estándar con una implementación integrada.
    • Java 9 agrega algunas características y correcciones menores.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de java.time se transfiere a Java 6 y 7 en ThreeTen-Backport .
  • Androide
    • Versiones posteriores de las implementaciones del paquete de Android de las clases java.time.
    • Para Android anterior, el proyecto ThreeTenABP adapta ThreeTen-Backport (mencionado anteriormente). Consulte Cómo utilizar ThreeTenABP ….

El proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí, como Interval , YearWeek , YearQuarter y más .


Para obtener más detalles, consulte mi respuesta a la pregunta similar:

  • java obtener la semana del año para una fecha dada

… y ver mi respuesta a la pregunta similar:

  • Cómo calcular la fecha a partir del número de semana ISO8601 en Java

Siento que este es un mejor enfoque.

 Calendar c = Calendar.getInstance(); DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy"); c.setTime( sdf.parse("31/12/2010")); int thisWeek = c.get(Calendar.WEEK_OF_YEAR); if (c.get(Calendar.MONTH) == Calendar.DECEMBER && thisWeek == 1) thisWeek = 53; System.out.println(thisWeek); 

La suposición principal aquí es que, para el mes de diciembre, la semana no puede ser 1, por lo tanto, devuelve 53.

Sugiero, si estoy equivocado en alguna parte, y por qué esto no se implementa en el Calendario de Java.