2011-10-30 7 views
13

Sono un po 'alle prese con questo.Java: come ottengo la data del x giorno in un mese (ad es. Il terzo lunedì di febbraio 2012)

voglio impostare il mio calendario per diciamo: terzo Lunedi nel mese di febbraio 2012. E non ho trovato alcun modo per farlo utilizzando Java.

Per esempio, se volevo impostare il mio calendario per il Natale 2011, posso farlo facilmente, in questo modo:

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

Ma io sono perso su come configurarlo per diciamo Memorial Day 2012, che è l'ultimo lunedì di maggio. Questo è il mio codice, ma è ovviamente sbagliato, perché semplicemente non può supporre che l'ultimo Lunedi di maggio sarà nella quarta settimana di maggio di quell'anno:

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

Qualche suggerimento su come posso programatically trovare fuori, in quale settimana del mese di maggio 2012 (nell'esempio sopra) è l'ultimo lunedì? Supponendo che io possa ottenere quell'informazione, dovrei essere in grado di ottenere il mio codice sopra per funzionare.

Ho bisogno di qualcosa che funzioni fondamentalmente per altri esempi. Qualcosa che potrebbe dare un giorno esatto per gli stessi scenari. Esempi:

quale data è:

  • Giovedi 3 di maggio 2015
  • 1 ° Lunedi del giugno 2050
  • quarto Martedì di Dicembre 2012
  • 2 ° Mercoledì del luglio 2000

Ho davvero bisogno di questo per il mio progetto e sono sicuro che sia semplice, ma mi sto rompendo la testa senza risultati concreti da mostrare :) E inoltre non ho trovato nulla in rete.


Aggiunto:

Ok, questo è dove ho per l'ultimo Lunedi in un mese:

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

Ma io non sono sicuro di come dovrei andare a fare ad esempio secondi lunedì dello stesso mese, come questo?

when.set (GregorianCalendar.DAY_OF_WEEK_IN_MONTH, 2); 

Qualche suggerimento?

risposta

10

per fare aritmetica delle date in Java (e, in generale, di fare qualsiasi cosa con datetimes, tranne che per le cose più banali) Joda-Time è la risposta:

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

Edit: Dal momento che Java 8 (2014) il nuovo Data API (pacchetto java.time), che è ispirato a/simile a Jodatime, should be preferred.

+0

Mi piace molto questo codice, funziona davvero. Solo non so come specificare l'ultimo mercoledì (in questo caso) nel mese. Puoi aiutare. – jjj

+0

Sto provando qualcosa come: LocalDate d = getNDayOfMonth (DateTimeConstants.WEDNESDAY, -1, 10, 2011); Ma non funziona. – jjj

+0

@jjj: Per ottenere l'ultimo mercoledì del mese richiede un leggero cambiamento, ho aggiunto un metodo per questo. Puoi anche utilizzare il primo metodo: ad esempio, per ottenere l'ultimo mercoledì dell'otto 2001, ottenere il primo mercoledì di novembre 2011 e sottrarre una settimana. – leonbloy

4

Non conosco il modo "facile" ma posso suggerire quanto segue.

  1. Imposta il calendario sul primo giorno del mese.
  2. Recupera il giorno della settimana
  3. Calcola la data del primo lunedì del mese.
  4. Aggiungi 14 giorni utilizzando il metodo calendar.add(). Otterrai il terzo lunedì.
0

Qualche possibilità che stai utilizzando 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")); 

stampe Questo semplice codice corretto i risultati:

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 

Il termine CronExpression non ha dipendenze sul resto del quarzo, per cui si potrebbe prendere in considerazione copiandolo al progetto (orologio per licenza)

nota

laterale: l'implementazione interna di getNextValidTimeAfter() è di 400 linee di codice ...

1

Tutto ciò che serve è un ciclo:

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

Ecco un'alternativa. Quello che fa è: ottenere la settimana desiderata (n) e gli altri parametri e restituire la data del giorno in quella settimana. Poiché Calendar indica la data del mese precedente (ad esempio il 29 febbraio anziché il 7 marzo, poiché la prima settimana di marzo si scontra con l'ultima settimana di febbraio), la funzione calcola la seconda settimana se la data supera 7 o multipli di per ogni settimana di esso. Spero possa aiutare.

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

Forse non capisco cosa stai cercando di fare. Per l'anno 2012, passo (2, 2, 2, 2012) al metodo. Come risultato ricevo lunedì, 2012-03-05. Il mese è chiaro: Java enumera per 0, quindi per il mese 2 mi metto in marcia - bene. Ma qual è il giorno? A seconda del locale, il giorno della settimana viene conteggiato di domenica (credo negli Stati Uniti) e di lunedì altrove. Ma come è contato - entro 1 o 2? Quindi possiamo avere domenica come 0, 1 o 6, 7 e lunedì come 0, 1 o 2. Quindi il lunedì ha un punto qui. Ma come è lunedì 5 maggio il secondo lunedì di marzo? Non sembra giusto. –

5

Il seguente codice è stato controllato con successo per tutte le vacanze nel 2013 e 2014. Mi rendo conto che in realtà non rispondere alla domanda iniziale, ma penso che potrebbe essere utile per le persone che vengono in questo post, nella speranza di capire come lavorare con le vacanze 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)); 

... e ...

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

java.time

Molto facile da fare utilizzando le classi java.time che ora soppiantano sia Joda- Il tempo e le fastidiose vecchie lezioni di data-ora in bundle con le prime versioni di Java.

Per prima cosa è necessario specificare il mese desiderato. La classe YearMonth può farlo. Da lì otteniamo uno LocalDate, una data senza un'ora del giorno e senza fuso orario.

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

L'interfaccia TemporalAdjuster prevede per regolare un valore data-ora in un altro valore data-ora. Implementazioni fornite dalla classe TemporalAdjusters (notare il plurale 's'). Specificare un giorno della settimana utilizzando l'utile enumerazione .

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

Suggerimento: Piuttosto che passare meri numeri interi per anno e mese attraverso il vostro codice di base, passare oggetti come YearMonth, Year, Month, e DayOfWeek. Ciò elimina l'ambiguità, rende il tuo codice più auto-documentante, fornisce types-safety e garantisce valori validi.

Chi java.time

Il quadro java.time è integrato in Java 8 e versioni successive. Queste classi soppiantano le fastidiose vecchie lezioni di data-ora come java.util.Date, .Calendar, & java.text.SimpleDateFormat.

Il progetto Joda-Time, ora in maintenance mode, consiglia la migrazione a java.time.

Per ulteriori informazioni, vedere Oracle Tutorial. E cerca Stack Overflow per molti esempi e spiegazioni.

Molte delle funzionalità java.time è back-porting di Java 6 & 7 in ThreeTen-Backport e in seguito atto a Android in ThreeTenABP (vedi How to use…).

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un terreno di prova per possibili aggiunte future a java.time. È possibile trovare alcune classi utili come Interval, YearWeek, YearQuarter e 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) visualizzerà la prima domenica di Nov 2017. nweek è l'ennesima settimana in un mese e il nday è l'ennesimo giorno della settimana – Kishore

Problemi correlati