2011-10-30 21 views
13

Tengo un poco de problemas con esto.Java: cómo obtengo la fecha de x día en un mes (por ejemplo, el tercer lunes de febrero de 2012)

Quiero fijar mi calendario a digamos: tercer lunes de febrero de 2012. Y no encontré ninguna manera de hacer esto utilizando Java.

Por ejemplo, si quería establecer mi calendario para la Navidad de 2011, que puedo hacer esto fácilmente, de esta manera:

Calendar when = Calendar.getInstance(); 
when.set (Calendar.MONTH, Calendar.DECEMBER); 
when.set (Calendar.DAY_OF_MONTH, 25) 
when.set (Calendar.YEAR, 2011); 

Pero estoy perdido en cuanto a cómo configurarlo para digamos Memorial Day 2012, que es el último lunes de mayo. Este es mi código, pero es obviamente erróneo, porque simplemente no puede asumir que el último lunes de mayo estará en la cuarta semana de mayo de ese año:

Calendar when = Calendar.getInstance(); 
when.set (Calendar.DAY_OF_WEEK,Calendar.MONDAY); 
when.set (Calendar.MONTH, Calendar.MAY); 
when.set (Calendar.WEEK_OF_MONTH, 4) 
when.set (Calendar.YEAR, 2012); 

Cualquier sugerencia en cuanto a cómo puedo encontrar programáticamente fuera, ¿en qué semana del mes de mayo de 2012 (en el ejemplo anterior) es el último lunes? Suponiendo que pueda obtener esa información, debería poder hacer que mi código anterior funcione.

Necesito algo que básicamente funcionaría para cualquier otro ejemplo. Algo que podría dar un día exacto para los mismos escenarios. Ejemplos:

¿Qué fecha es:

  • jueves 3 de mayo, el año 2015
  • lunes 1 de junio para el año 2050
  • martes 4 de diciembre 2012 para
  • miércoles 2 de julio de 2000

Realmente necesito esto para mi proyecto y estoy seguro de que es simple, pero me estoy rompiendo la cabeza en esto sin ningún resultado real para mostrar :) Y tampoco pude encontrar nada en la red.


Agregado:

Ok, aquí es donde tengo para el último lunes de un mes:

when.set (GregorianCalendar.MONTH, GregorianCalendar.MAY); 
when.set (GregorianCalendar.DAY_OF_WEEK, Calendar.MONDAY); 
when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, -1); 
when.set (Calendar.YEAR, 2012); 

Pero no estoy seguro de cómo iba a ir haciendo, por ejemplo, segundos el lunes en el mismo mes, así?

when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2); 

¿Alguna sugerencia?

Respuesta

10

para hacer la aritmética de fechas en Java (y, en general, a hacer cualquier cosa con datetimes, a excepción de las cosas más triviales) Joda-Time es la respuesta:

public static LocalDate getNDayOfMonth(int dayweek,int nthweek,int month,int year) { 
    LocalDate d = new LocalDate(year, month, 1).withDayOfWeek(dayweek); 
    if(d.getMonthOfYear() != month) d = d.plusWeeks(1); 
    return d.plusWeeks(nthweek-1); 
} 

public static LocalDate getLastWeekdayOfMonth(int dayweek,int month,int year) { 
    LocalDate d = new LocalDate(year, month, 1).plusMonths(1).withDayOfWeek(dayweek); 
    if(d.getMonthOfYear() != month) d = d.minusWeeks(1); 
    return d; 
} 

public static void main(String[] args) { 
    // second wednesday of oct-2011 
    LocalDate d = getNDayOfMonth(DateTimeConstants.WEDNESDAY, 2, 10, 2011); 
    System.out.println(d); 
    // last wednesday of oct-2011 
    LocalDate dlast = getLastWeekdayOfMonth(DateTimeConstants.WEDNESDAY, 10, 2011); 
    System.out.println(dlast); 
} 

Edición: Desde Java 8 (2014) La nueva fecha de API (paquete java.time), que está inspirado en/similar a Jodatime, should be preferred.

+0

Me gusta mucho este código, en realidad funciona. Simplemente no sé cómo especificar el último miércoles (en este caso) en el mes. Puede usted ayudar. – jjj

+0

Estoy intentando algo así como: LocalDate d = getNDayOfMonth (DateTimeConstants.WEDNESDAY, -1, 10, 2011); Pero no funciona. – jjj

+0

@jjj: para obtener el último miércoles del mes requiere un ligero cambio, he añadido un método para eso. También puede usar el primer método: por ejemplo, para obtener el último miércoles de octubre de 2001, obtener el primer miércoles de noviembre de 2011 y restar una semana. – leonbloy

4

No sé la manera "fácil" pero puedo sugerirle lo siguiente.

  1. Configure el calendario para el primer día del mes.
  2. Recupere el día de la semana
  3. Calcule la fecha del primer lunes del mes.
  4. Agregue 14 días con el método calendar.add(). Obtendrás el tercer lunes.
0

¿Alguna posibilidad de que esté usando Quartz scheduler? (?)

public Date date(String cronExpression) { 
    return new org.quartz.CronExpression(cronExpression). 
     getNextValidTimeAfter(new Date(0)); 
} 

System.out.println(date("0 0 0 ? May Thu#3 2015")); 
System.out.println(date("0 0 0 ? Jun Mon#1 2050")); 
System.out.println(date("0 0 0 ? Dec Tue#4 2012")); 
System.out.println(date("0 0 0 ? Jul Wed#2 2000")); 

grabados Este simple código correcto resultados:

Thu May 21 00:00:00 CEST 2015 
Mon Jun 06 00:00:00 CEST 2050 
Tue Dec 25 00:00:00 CET 2012 
Wed Jul 12 00:00:00 CEST 2000 

El requeridos CronExpression no tiene ninguna dependencia en el resto de cuarzo, lo que podríamos considerar lo copia a su proyecto (reloj por licencia)

nota

lateral: la implementación interna de getNextValidTimeAfter() es de 400 líneas de código ...

1

Todo lo que necesita es un bucle:

public class CalculateDate { 

public static void main(String ... args) { 

    Calendar c = Calendar.getInstance(); 
    c.set(Calendar.YEAR, 2012); 
    c.set(Calendar.MONTH , Calendar.MAY); 
    c.set(Calendar.DAY_OF_MONTH, 0); 
    c.add(Calendar.DAY_OF_MONTH, -1); 

    System.out.println(c.getTime()); 

    int mondaysCount = 0; 

    while (mondaysCount != 4) { 
     c.add(Calendar.DAY_OF_MONTH, 1); 
     if (c.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
      mondaysCount++; 
     }  
    } 

    System.out.printf("The fourth monday of may is %s", c.getTime());  

} 

} 
-2

Aquí es una alternativa. Lo que hace es: obtener la semana que desee (n) y los otros parámetros, y devolver la fecha del día de esa semana. Dado que Calendar da la fecha del mes anterior (por ejemplo, 29 de febrero en lugar de 7 de marzo, ya que la primera semana de marzo colisiona con la última semana de febrero), la función calcula la 2ª semana si la fecha supera 7 o múltiplos de por cada semana de eso. Espero que ayude.

public static int getNthWeekDay (int n, int day, int month, int year) { 
    Calendar calendar = Calendar.getInstance(); 

    calendar.set(Calendar.DAY_OF_WEEK, day); 
    calendar.set(Calendar.MONTH, month); 
    calendar.set(Calendar.WEEK_OF_MONTH,n); 
    calendar.set(Calendar.YEAR, year); 
    if (calendar.get(Calendar.DATE) > n * 7) { 
     calendar.set(Calendar.DAY_OF_WEEK,day); 
     calendar.set(Calendar.MONTH, month); 
     calendar.set(Calendar.WEEK_OF_MONTH,day+1); 

    } 
    return calendar.get(Calendar.DATE); 
} 
+0

Quizás no entiendo lo que estás tratando de hacer. Para el año 2012, paso (2, 2, 2, 2012) al método. Como resultado me sale el lunes, 2012-03-05. El mes está claro: Java enumera por 0, entonces para el mes 2 me sale marzo, está bien. Pero, ¿qué día es? Dependiendo de la configuración regional, el día de la semana se contará el domingo (supongo que en los EE. UU.) Y el lunes en otro lugar. Pero, ¿cómo se cuenta, por 1 o 2? Entonces, podemos tener el domingo como 0, 1 o 6, 7 y el lunes como 0, 1 o 2. Entonces el lunes tiene un punto aquí. Pero, ¿cómo es el lunes 5, posiblemente el segundo lunes de marzo? Eso no se ve bien. –

5

El siguiente código fue probado con éxito para todos los días festivos en 2013 y 2014. Soy consciente de que esto no responde realmente a la pregunta original, pero creo que podría ser útil para las personas que vienen a través de este post con la esperanza de averiguar cómo trabajar con las vacaciones usando Calendar.

public static boolean isMajorHoliday(java.util.Date date) { 
    Calendar cal = Calendar.getInstance(); 
    cal.setTime(date); 

    // check if New Year's Day 
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY 
     && cal.get(Calendar.DAY_OF_MONTH) == 1) { 
     return true; 
    } 

    // check if Christmas 
    if (cal.get(Calendar.MONTH) == Calendar.DECEMBER 
     && cal.get(Calendar.DAY_OF_MONTH) == 25) { 
     return true; 
    } 

    // check if 4th of July 
    if (cal.get(Calendar.MONTH) == Calendar.JULY 
     && cal.get(Calendar.DAY_OF_MONTH) == 4) { 
     return true; 
    } 

    // check Thanksgiving (4th Thursday of November) 
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 4 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) { 
     return true; 
    } 

    // check Memorial Day (last Monday of May) 
    if (cal.get(Calendar.MONTH) == Calendar.MAY 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY 
     && cal.get(Calendar.DAY_OF_MONTH) > (31 - 7)) { 
     return true; 
    } 

    // check Labor Day (1st Monday of September) 
    if (cal.get(Calendar.MONTH) == Calendar.SEPTEMBER 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 1 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    // check President's Day (3rd Monday of February) 
    if (cal.get(Calendar.MONTH) == Calendar.FEBRUARY 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    // check Veterans Day (November 11) 
    if (cal.get(Calendar.MONTH) == Calendar.NOVEMBER 
     && cal.get(Calendar.DAY_OF_MONTH) == 11) { 
     return true; 
    } 

    // check MLK Day (3rd Monday of January) 
    if (cal.get(Calendar.MONTH) == Calendar.JANUARY 
     && cal.get(Calendar.DAY_OF_WEEK_IN_MONTH) == 3 
     && cal.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) { 
     return true; 
    } 

    return false; 

} 
0

tl; dr

LocalDate thirdMondayInFebruary2012 = 
    YearMonth.of(2012 , Month.FEBRUARY) 
      .atDay(1) 
      .with(TemporalAdjusters.dayOfWeekInMonth(3 , DayOfWeek.MONDAY)); 

... y ...

LocalDate lastMondayInMay2012 = 
    YearMonth.of(2012 , Month.MAY) 
      .atDay(1); 
      .with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); 

java.time

muy fácil de hacer uso de las clases java.time que ahora suplantan tanto Joda- El tiempo y las antiguas clases problemáticas de fecha y hora se incluyen con las primeras versiones de Java.

Primero debemos especificar el mes deseado. La clase YearMonth puede hacer eso. A partir de ahí obtenemos un LocalDate, una fecha sin hora y sin zona horaria.

YearMonth ym = YearMonth.of(2012 , Month.FEBRUARY); // Or pass '2' for 'February'. 
LocalDate ld = ym.atDay(1); 

La interfaz TemporalAdjuster proporciona para el ajuste de un valor de fecha y hora en otro valor de fecha y hora. Implementaciones proporcionadas por la clase TemporalAdjusters (observe el plural 's'). Especifique un día de la semana usando la práctica enumeración DayOfWeek.

int ordinal = 3 ; // Use '3' for 'third occurrence in month' such as '3rd Monday'. 
LocalDate thirdMondayInFebruary2012 = ld.with(TemporalAdjusters.dayOfWeekInMonth(ordinal , DayOfWeek.MONDAY)); 

Consejo: En lugar de pasar meros enteros para año y mes a través de su base de código, pasar objetos como YearMonth, Year, Month, y DayOfWeek. Hacerlo elimina la ambigüedad, hace que su código sea más autodocumentado, proporciona types-safety y garantiza valores válidos.

Sobre java.time

java.time El marco está construido en Java 8 y versiones posteriores. Estas clases suplantan a las antiguas clases problemáticas de fecha y hora como java.util.Date, .Calendar, & java.text.SimpleDateFormat. El proyecto Joda-Time, ahora en maintenance mode, recomienda la migración a java.time.

Para obtener más información, consulte el Oracle Tutorial. Y busque Stack Overflow para obtener muchos ejemplos y explicaciones.

Gran parte de la funcionalidad java.time está de vuelta-portado a Java 6 & 7 en ThreeTen-Backport y adaptado además para Android en ThreeTenABP (ver How to use…).

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 more.

0
public String nDow(int year, int month, int nweek, int nday) 
{ 
    Calendar cdt = Calendar.getInstance(); 
    cdt.set(year, month -1, 1); 
    return year + "-" + month + "-" + (getPosOfWeekday(cdt.get(Calendar.DAY_OF_WEEK), nday) + ((nweek - 1) *7)); 
} 

private int getPosOfWeekday(int startday, int nday) 
{ 
    nday = weekDayValue(nday); 
    return constructCircularArray(startday).indexOf(nday) + 1; 
} 

private ArrayList<Integer> constructCircularArray(int weekday) 
{ 
    ArrayList<Integer> circularArray = new ArrayList<Integer>(); 
    for(int i = 0; i < 7; i++) 
    { 
     circularArray.add(i, weekDayValue(weekday++)); 
    } 
    return circularArray; 
} 

private int weekDayValue(int x) 
{ 
    return ((x-1) % 7) + 1; 
} 
+0

nDow (2017, 11, 1, 1) se mostrará el primer domingo de noviembre de 2017. nweek es enésima semana en un mes y nday es enésimo día de la semana – Kishore

Cuestiones relacionadas