2014-05-21 14 views
23

Ho due moment date:Come enumerare date tra due date nel momento

var fromDate = moment(new Date('1/1/2014')); 
var toDate = moment(new Date('6/1/2014')); 

Vuol momento fornire un modo per enumerare tutte le date tra queste due date?

Se no, c'è una soluzione migliore diverso da fare un ciclo che incrementa il fromDate da 1 fino a raggiungere la toDate?

Edit: Aggiunta la data metodo di enumerazione e problema

ho preso in giro un metodo per enumerare i giorni tra due date, ma sto correndo in un problema.

var enumerateDaysBetweenDates = function(startDate, endDate) { 
    var dates = []; 

    startDate = startDate.add(1, 'days'); 

    while(startDate.format('M/D/YYYY') !== endDate.format('M/D/YYYY')) { 
     console.log(startDate.toDate()); 
     dates.push(startDate.toDate()); 
     startDate = startDate.add(1, 'days'); 
    } 

    return dates; 
    }; 

Date un'occhiata al output quando eseguo enumerateDaysBetweenDates(moment(new Date('1/1/2014')), moment(new Date('1/5/2014'));

Thu Jan 02 2014 00:00:00 GMT-0800 (PST) 
Fri Jan 03 2014 00:00:00 GMT-0800 (PST) 
Sat Jan 04 2014 00:00:00 GMT-0800 (PST) 
[ Sun Jan 05 2014 00:00:00 GMT-0800 (PST), 
    Sun Jan 05 2014 00:00:00 GMT-0800 (PST), 
    Sun Jan 05 2014 00:00:00 GMT-0800 (PST) ] 

E 'console.logging le date giuste, ma è essere aggiunto solo la data finale per l'array. Come/perché è questo? Questo odora di una sorta di problema di riferimento variabile - ma non lo vedo.

risposta

45

.add() è un metodo mutatore, quindi l'assegnazione di questa linea è inutile:

startDate = startDate.add(1, 'days'); 

Basta fare questo e avere lo stesso effetto:

startDate.add(1, 'days'); 

Mentre il suo nome implicherebbe la creazione di un nuovo Date oggetto, il metodo toDate() in realtà solo restituisce l'Date oggetto interno esistente.

Quindi, nessuna delle tue chiamate di metodo sta creando nuove istanze di oggetto Date o moment.Fix che utilizzando .clone() per ottenere una nuova istanza:

startDate = startDate.clone().add(1, 'days'); 

O meglio ancora, avvolgere i valori in una chiamata a moment() come Mtz suggerisce in un commento, e sarà clonare l'istanza, se il valore è un momento oggetto, o analizzerà l'input per creare una nuova istanza di momento.

startDate = moment(startDate).add(1, 'days'); 

Penso che un metodo di data enumeratore non dovrebbe cambiare uno dei due argomenti passati. Mi piacerebbe creare una variabile separata per l'enumerazione. Mi piacerebbe anche confrontare le date direttamente, piuttosto che le stringhe di confronto:

var enumerateDaysBetweenDates = function(startDate, endDate) { 
    var dates = []; 

    var currDate = moment(startDate).startOf('day'); 
    var lastDate = moment(endDate).startOf('day'); 

    while(currDate.add(1, 'days').diff(lastDate) < 0) { 
     console.log(currDate.toDate()); 
     dates.push(currDate.clone().toDate()); 
    } 

    return dates; 
}; 
+0

Non conoscevo il metodo clone. Dolce! Grazie. – doremi

+5

Nota che 'momento(). Aggiungi (punto, numero) è deprecato. Per favore usa il momento(). Aggiungi (numero, punto) '. – chteuchteu

+0

Interessante per l'opzione di ordine degli argomenti. Suppongo che l'abbiano fatto per fare in modo che una catena di funzioni di manipolazione della data leggesse più come una frase inglese, ma se si volesse usare Moment insieme a una libreria di applicazioni currying/parziale si vorrebbe '.add (punto, numero)', wouldn sei tu? – nnnnnn

4

momento non fornisce questo per sé, ma v'è un plugin che lo offre: moment-range

https://github.com/gf3/moment-range

In particolare, controllare la documentazione di iterazione: https://github.com/gf3/moment-range#iterate

+0

Grazie Cody. Penso di volerlo mantenere snello scrivendo il mio metodo ed evitando di aggiungere un'altra dipendenza. Dai un'occhiata alla mia pugnalata, forse avrai qualche intuizione. – doremi

16

preso per voi:

var enumerateDaysBetweenDates = function(startDate, endDate) { 
    var now = startDate.clone(), dates = []; 

    while (now.isSameOrBefore(endDate)) { 
     dates.push(now.format('M/D/YYYY')); 
     now.add(1, 'days'); 
    } 
    return dates; 
}; 

Riferimento a now anziché a startDate ha fatto la differenza.

Se non sei dopo una ricerca inclusiva poi cambiare .isSameOrBefore a .isBefore

Fiddle:http://jsfiddle.net/KyleMuir/sRE76/118/

+0

Grazie! Questo ha funzionato perfettamente bene per me. –

+0

dovette scambiare 'now.format ('M/D/YYYY') <= endDate.format ('M/D/YYYY')' per 'now.isBefore (endDate)' per ottenere questo funzionamento in fiddle – Mangopop

+0

@Mangopop Grazie, ho aggiornato la mia risposta per includere metodi migliori. Ho anche aggiunto '|| now.isSame (endDate) 'come la risposta originale era endDate inclusive. –

0

Come estensione della risposta di Kyle - Ho cercato di ottenere questo a lavorare con timestamp Unix e dopo un sacco di tentativi ed errori ho ottenuto per funzionare e ho pensato di pubblicarlo qui nel caso qualcuno stia cercando la stessa cosa e ne abbia bisogno. Vedere il mio codice qui sotto:

fromDate = moment.unix(req.params.dateFrom).format('YYYY-MM-DD') 
toDate = moment.unix(req.params.dateTo).format('YYYY-MM-DD') 

// Returns an array of dates between the two dates 
function enumerateDaysBetweenDates(startDate, endDate) { 
    startDate = moment(startDate); 
    endDate = moment(endDate); 

    var now = startDate, dates = []; 

    while (now.isBefore(endDate) || now.isSame(endDate)) { 
     dates.push(now.format('YYYY-MM-DD')); 
     now.add(1, 'days'); 
    } 
    return dates; 
}; 

Si noti che ho convertirlo in Unix, quindi convertire tale valore al momento di nuovo. Questo è stato il problema che ho avuto, è necessario renderlo un valore di un momento di nuovo in modo che funzioni.

Esempio di utilizzo:

fromDate = '2017/03/11' // AFTER conversion from Unix 
toDate = '2017/03/13' // AFTER conversion from Unix 

console.log(enumerateDaysBetweenDates(fromDate, toDate)); 

tornerà:

['2017/03/11', '2017/03/12', '2017/03/13']