Obtenga la fecha de inicio y finalización de la semana dada una fecha actual y un inicio de semana

Si es posible, preferiría una solución joda o no-joda para el siguiente escenario

Digamos si mi semana comienza el 02/05/2012 y la fecha actual dada es 22/02/2011. Necesito calcular la fecha de inicio y finalización de la semana para la fecha actual dada. Así que mi solución debería tener la semana que comienza como 02/19 y la semana termina a las 02/25. Para simplificar, he configurado mi semana para comenzar aquí el 02/05/2011 pero podría ser cualquier día potencialmente y mi semana siempre tiene 7 días.

Mi código actual está debajo pero no parece funcionar como se esperaba.

public Interval getWeekInterval(Date calendarStartDate, Date date) { Calendar sDate = Calendar.getInstance(); sDate.setTime(getMidnightDate(calendarStartDate)); Calendar eDate = Calendar.getInstance(); eDate.setTime(date); Calendar weekStartDate = (Calendar) sDate.clone(); logger.debug("Date:" + sDate.getTime()); while (sDate.before(eDate)) { weekStartDate = sDate; sDate.add(Calendar.DAY_OF_WEEK_IN_MONTH, 1); } return new Interval(weekStartDate.getTime(), sDate.getTime()); } 

Pruebe esto (pseudo-código):

 // How many days gone after reference date (a known week-start date) daysGone = today - referenceDate; // A new week starts after each 7 days dayOfWeek = daysGone % 7; // Now, we know today is which day of the week. // We can find start & end days of this week with ease weekStart = today - dayOfWeek; weekEnd = weekStart + 6; 

Ahora, podemos acortar todo esto en dos líneas:

 weekStart = today - ((today - referenceDate) % 7); weekEnd = weekStart + 6; 

Tenga en cuenta que restamos valores de fecha como enteros para mostrar el algoritmo. Debes escribir tu código java correctamente.

Definiendo una semana

Si está utilizando objetos de fecha y hora, debe definir una semana como hasta, pero sin incluir, el primer momento del día posterior al final de la semana. Como se ve en este diagtwig.

Línea de tiempo que muestra (/> = inicio del día 1) y (<inicio del día 8)

Este enfoque se conoce como Half-Open . Este enfoque se usa comúnmente para trabajar con períodos de tiempo.

La razón es porque, lógicamente, ese último momento del día antes del nuevo día es infinitamente divisible como una fracción de segundo. Puede pensar que usar “.999” manejaría eso durante milisegundos, pero luego se equivocaría al escribir para las nuevas clases java.time. * En Java 8 que tienen una resolución de nanosegundos en lugar de milisegundos. Puede pensar que el uso de “.999999999” manejaría ese caso, pero se equivocaría al manejar valores de fecha y hora de muchas bases de datos, como Postgres que usa una resolución de microsegundos, “.999999”.

En la biblioteca Joda-Time de fuente abierta de terceros, esta lógica Half-Open es cómo funciona su clase Interval . El comienzo es inclusivo y el final es exclusivo. Esto funciona bien. De manera similar, al llamar a más plusWeeks(1) en un DateTime para agregar una semana al primer momento del día, se obtiene el primer momento del octavo día más tarde (ver ejemplo a continuación).

Zona horaria

La pregunta y otras respuestas ignoran el problema de la zona horaria. Si no especifica, obtendrá la zona horaria predeterminada. Por lo general, es mejor especificar un huso horario, utilizando un nombre de huso horario apropiado (no un código de 3 letras).

Joda-Time

Evite las clases java.util.Date y Calendar incluidas con Java. Son notoriamente problemáticos.

Aquí hay un código de ejemplo usando Joda-Time 2.3.

CAVEAT : No he probado completamente el código siguiente. Solo mi primera toma, un borrador. Bien puede ser defectuoso.

Semana estándar (lunes a domingo)

La biblioteca Joda-Time se basa en el estándar ISO 8601 . Ese estándar define el primer día de la semana como el lunes, último día como el domingo.

Si cumple con su definición de una semana, entonces es fácil obtener el principio y el final.

ACTUALIZACIÓN Como una alternativa a la discusión a continuación, vea esta solución muy simple y muy simple de SpaceTrucker .

Simplemente forzando las obras del día de la semana porque Joda-Time asume que usted quiere:

  • Lunes para estar antes (o lo mismo que) hoy.
  • Domingo para estar después (o lo mismo que) hoy.
 DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); DateTime now = new DateTime( timeZone ); DateTime weekStart = now.withDayOfWeek( DateTimeConstants.MONDAY ).withTimeAtStartOfDay(); DateTime weekEnd = now.withDayOfWeek(DateTimeConstants.SUNDAY).plusDays( 1 ).withTimeAtStartOfDay(); Interval week = new Interval( weekStart, weekEnd ); 

Volcado a la consola …

 System.out.println( "now: " + now ); System.out.println( "weekStart: " + weekStart ); System.out.println( "weekEnd: " + weekEnd ); System.out.println( "week: " + week ); 

Cuando se ejecuta …

 now: 2014-01-24T06:29:23.043+01:00 weekStart: 2014-01-20T00:00:00.000+01:00 weekEnd: 2014-01-27T00:00:00.000+01:00 week: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00 

Para ver si una fecha y hora aterriza dentro de ese intervalo, llame al método contains .

 boolean weekContainsDate = week.contains( now ); 

Semana no estándar

Si eso no coincide con tu definición de una semana, le das un giro a ese código.

 DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" ); DateTime now = new DateTime( timeZone ); DateTime weekStart = now.withDayOfWeek( DateTimeConstants.SUNDAY ).withTimeAtStartOfDay(); if ( now.isBefore( weekStart )) { // If we got next Sunday, go back one week to last Sunday. weekStart = weekStart.minusWeeks( 1 ); } DateTime weekEnd = weekStart.plusWeeks( 1 ); Interval week = new Interval( weekStart, weekEnd ); 

Volcado a la consola …

 System.out.println( "now: " + now ); System.out.println( "weekStart: " + weekStart ); System.out.println( "weekEnd: " + weekEnd ); System.out.println( "week: " + week ); 

Cuando se ejecuta …

 now: 2014-01-24T00:54:27.092-05:00 weekStart: 2014-01-19T00:00:00.000-05:00 weekEnd: 2014-01-26T00:00:00.000-05:00 week: 2014-01-19T00:00:00.000-05:00/2014-01-26T00:00:00.000-05:00 

El primer día de la semana depende del país. Lo que hace que el cálculo sea frágil es que uno puede romper el límite del año y el número de la semana ( Calendar.WEEK_OF_YEAR ). Lo siguiente haría:

  Calendar currentDate = Calendar.getInstance(Locale.US); int firstDayOfWeek = currentDate.getFirstDayOfWeek(); Calendar startDate = Calendar.getInstance(Locale.US); startDate.setTime(currentDate.getTime()); //while (startDate.get(Calendar.DAY_OF_WEEK) != firstDayOfWeek) { // startDate.add(Calendar.DATE, -1); //} int days = (startDate.get(Calendar.DAY_OF_WEEK) + 7 - firstDayOfWeek) % 7; startDate.add(Calendar.DATE, -days); Calendar endDate = Calendar.getInstance(Locale.US); endDate.setTime(startDate.getTime()); endDate.add(Calendar.DATE, 6); 

Un error en el Calendario rompe tu código, clone , parece dar simplemente el objeto idéntico, por lo tanto, al final tienes fechas idénticas. (Java 7 al menos).

  DateTime sDateTime = new DateTime(startDate); // My calendar start date DateTime eDateTime = new DateTime(date); // the date for the week to be determined Interval interval = new Interval(sDateTime, sDateTime.plusWeeks(1)); while(!interval.contains(eDateTime)) { interval = new Interval(interval.getEnd(), interval.getEnd().plusWeeks(1)); } return interval;