2010-07-21 5 views
25

Sto rivedendo un certo codice sul posto di lavoro e mi sono imbattuto un'incoerenza nel modo in cui il codice gestisce l'aggiunta di 1 settimana a l'ora corrente e si chiedeva se ci fosse alcuna ragione per cui si dovrebbe davvero essere preferito rispetto all'altro:Aggiungi 1 settimana a una data, quale è la via preferita?

La prima era un metodo di utilità:

public static Date addDaysToDate(final Date date, int noOfDays) { 
    Date newDate = new Date(date.getTime()); 

    GregorianCalendar calendar = new GregorianCalendar(); 
    calendar.setTime(newDate); 
    calendar.add(Calendar.DATE, noOfDays); 
    newDate.setTime(calendar.getTime().getTime()); 

    return newDate; 
} 

E la seconda utilizzata semplice aritmetica millisecondo:

long theFuture = System.currentTimeMillis() + (86400 * 7 * 1000); 
Date nextWeek = new Date(theFuture); 

il secondo metodo utilizza ovviamente 'numeri magici' per definire una settimana, ma questo potrebbe essere mossa d a una costante MILLISECONDS_IN_ONE_WEEK = 86400 * 7 * 1000 Quindi, a parte questo, c'è qualche ragione per cui uno di questi metodi dovrebbe essere preferito rispetto all'altro?

Fondamentalmente voglio cambiare il codice per essere coerente in tutto, ma non sono del tutto sicuro quale rimuovere. Quindi qualsiasi argomento in un modo o nell'altro sarebbe utile.

+2

* tosse * Usa Joda-Time. 'DateTime newDate = date.plusWeeks (1); ' – ColinD

+7

Il codice viene eseguito su un dispositivo Windows Mobile utilizzando una JVM basata principalmente su Java 1.2. Joda viene testato solo contro 1.4 e versioni successive, quindi non voglio aggiungere una libreria di terze parti che non è stata progettata per funzionare sulla piattaforma che sto usando. Ma grazie per il suggerimento. – DaveJohnston

risposta

22

I due metodi si comportano in modo diverso sui confini legale.Il primo metodo continuerà a tornare alla stessa ora del giorno, indipendentemente dallo stato dell'ora legale. Il secondo metodo restituirà i tempi che variano un'ora in ciascuna direzione quando l'ora legale inizia e si arresta.

0

Più è generale, più sarà utile. Se aggiungete sempre una settimana, ho scelto il secondo metodo. Se hai aggiunte diverse, avrei scelto il primo, forse sostituendo giorni per secondi o anche millis se necessario.

0

Il primo sarà più lento, quindi se le prestazioni sono un problema, il secondo è migliore.

+0

Viene eseguito su un dispositivo Windows Mobile, quindi le prestazioni sono sicuramente un problema. Quanto di un impatto pensi che avrebbe (all'incirca)? – DaveJohnston

+0

Dipende da quanto spesso si chiama, quel genere di cose. Per avere un'idea avresti bisogno di delinearlo. Ad esempio, in un dato codice critico che ho dovuto esaminare, chiamavamo costantemente "new Date(). GetTime()" - sostituendolo con "System.currentTimeMillis()" facevo una differenza significativa perché non eravamo istanziando ripetutamente oggetti Date. – Rich

+3

"sarà più lento" è piuttosto soggettivo. La manipolazione del calendario e della data è principalmente relativa alla modifica della rappresentazione "lunga" della data in ogni caso, il che significa che "più lento" si riduce alla velocità di creazione degli oggetti, che è molto più veloce di quanto la maggior parte della gente pensi. –

1

Prima di tutto, direi che lo sostituisci con JodaTime. http://joda-time.sourceforge.net/ È una libreria di tempo molto bella. Ti consigliamo di guardare questa pagina per vedere quanto è facile aggiungere giorni o settimane a un particolare momento: http://joda-time.sourceforge.net/key_period.html Impossibile farlo, dispositivo mobile con JVM incompatibile. Bummer.

Il tuo primo esempio è più facile da leggere e sarà più facile da usare dai tuoi sviluppatori. Usa anche le classi Calendar che sono il modo generalmente accettato di manipolare le date in Java. Ciò che lo rende migliore è che ha un chiaro nome del metodo che stabilisce l'aspettativa per ciò che fa.

Quindi, se si effettua il refactoring del sistema per utilizzare in modo coerente com.DaveJ.util.date.DateUtils.addDaysToDate (data di fine data, int noOfDays), è quindi possibile eseguire qualsiasi cosa all'interno di tale metodo, che sia Calendar o millis o Joda ed essere coerenti con la tua applicazione. Non dimenticare di scrivere alcuni test unitari per questo!

+0

Un'altra risposta ha menzionato la velocità. Se questa logica è incapsulata in un metodo, in un punto, sarà MOLTO facile confrontarlo e sintonizzarlo per ottenere la velocità necessaria. – Freiheit

0

Dipende! A causa dei secondi bisestili, dell'ora legale e di altre stranezze del calendario, i due non sono sempre equivalenti.

Per il business e l'uso quotidiano, utilizzare sempre il primo metodo e le prestazioni non sono affatto male. Gestirà quelle cose per te.

Per esigenze scientifiche, spesso è necessario utilizzare un orologio monotona (qui la seconda).

0

I due metodi possono dare risultati diversi quando è necessario un cambiamento nell'ora legale. Immagina che l'ora corrente sia alle 23:50 e alle 02:00 l'orologio salta alle 03:00. Quando aggiungi solo 7 giorni in millisecondi, il giorno successivo sarà 00:50. Aggiunti 7 giorni, il tempo risultante sarebbe ancora 23:50.

Per rendere la confusione completa, si potrebbe anche provare add(Calendar.WEEK_OF_YEAR, 1), non so come sarebbe diverso però.

0

Dal momento che si sta utilizzando il dispositivo mobile, il primo metodo è preferibile. Il motivo è che il tuo codice dovrebbe essere indipendente dal calendario specifico, dall'ora legale e da altri problemi, come il superamento dei secondi (secondi bisestili).

È necessario rimuovere la dipendenza su GregorianCalendar e crearlo utilizzando Calendar.getInstance().

+0

In questo caso, _shouldn't_ non si usa 'getInstance()'. Sto indovinando che il codice sta cercando di calcolare 1 settimana in futuro secondo il calendario gregoriano, non una settimana in futuro secondo il calendario locale dell'utente. Anche se l'utente userebbe il Calendario decimale della Rivoluzione francese, non ne ho idea. –

3

Prestare molta attenzione all'utilizzo del metodo due che caught me out l'altro giorno. Si consideri

private static long ONE_YEAR_AS_MILLISECONDS = 365*24*60*60*1000; 

Questo sembra abbastanza innocente, ma in realtà non produrrà cosa ci si aspetta, come la moltiplicazione utilizza numeri interi che, se moltiplicato per ciascuno degli altri numeri interi, causa un overflow numerico e produrrà un risultato inaspettato. Questo perché il valore max int in Java è 2.147.483.647 eppure ci sono 31.536.000.000 di ms in un anno. Sulla mia macchina il codice sopra riportato produce 1.471.228.928 che ovviamente non è corretto.

Invece è necessario fare questo:

private static long ONE_YEAR_AS_MILLISECONDS = 365L*24L*60L*60L*1000L; 
3

Il sotto può essere fatto in Java 8, Java 8 rocce !!

public static void main(String[] args) { 
     LocalDate today = LocalDate.now(); 
     System.out.println("Current date: " + today); 

     //add 1 week to the current date 
     LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS); 
     System.out.println("Next week: " + nextWeek); 
    } 
+0

Codice più semplice più corto che omette il 'ChronoUnit' con lo stesso effetto:' today.plusWeeks (1) ' –

+0

Suggerisco sempre di passare un fuso orario (' ZoneId') al metodo 'now'. Se omesso, il fuso orario predefinito di JVM viene applicato implicitamente. Questo valore predefinito può variare, anche * durante * l'esecuzione della tua app! Il fuso orario è cruciale in quanto per un dato momento la data varia in tutto il mondo. 'LocalDate.now (ZoneId.of (" America/Montreal "))' –

0

Per un valore di sola data, vedere the Answer by javaHelper. La classe LocalDate non ha volutamente l'ora del giorno e nessun fuso orario.

ZonedDateTime

Per un valore data-ora, utilizzare ZonedDateTime per rappresentare una data e un tempo del giorno con un fuso orario per tenere conto di anomalie come l'ora legale (DST).

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

Oppure aggiungere un numero arbitrario di giorni.

ZonedDateTime later = now.plusDays(someNumberOfDays); 

Chi java.time

Il quadro java.time è costruito in Java 8 e versioni successive. Queste classi sostituiscono le vecchie e fastidiose 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.

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un terreno di prova per possibili aggiunte future a java.time.

Problemi correlati