web-dev-qa-db-fra.com

Comment énumérer des dates entre deux dates dans Moment

J'ai deux moment dates:

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

Le moment fournit-il un moyen d'énumérer toutes les dates entre ces deux dates?

Sinon, existe-t-il une meilleure solution que de faire une boucle qui incrémente le fromDate de 1 jusqu'à ce qu'il atteigne le toDate?

Edit: Ajout de la méthode d'énumération des dates et du problème

J'ai simulé une méthode pour énumérer les jours entre deux dates, mais je rencontre un problème.

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

Jetez un oeil à la sortie lorsque j'exécute 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) ]

C'est console.logging les bonnes dates, mais seule la date finale est ajoutée au tableau. Comment/pourquoi est-ce? Cela sent comme une sorte de problème de référence variable - mais je ne le vois pas.

40
doremi

.add() est une méthode de mutation, donc l'affectation dans cette ligne n'est pas nécessaire:

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

Vous pouvez simplement faire cela et avoir le même effet:

startDate.add(1, 'days');

Alors que son nom impliquerait la création d'un nouvel objet Date, la méthode toDate() retourne vraiment juste l'objet interne Date existant.

Ainsi, aucun de vos appels de méthode ne crée de nouvelles instances d'objet Date ou moment. Corrigez cela en utilisant .clone() pour obtenir une nouvelle instance:

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

Ou mieux encore, encapsulez les valeurs dans un appel à moment() comme Mtz le suggère dans un commentaire, et il clonera l'instance, si la valeur est un objet moment, ou analyser l'entrée pour créer une nouvelle instance de moment.

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

Je pense qu'une méthode d'énumérateur de date ne devrait changer aucun des arguments transmis. Je créerais une variable distincte pour l'énumération. Je comparerais également les dates directement, plutôt que de comparer des chaînes:

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;
};
72
gilly3

Je l'ai pour vous:

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

Référencer now plutôt que startDate a fait toute la différence.

Si vous ne recherchez pas une recherche inclusive, modifiez .isSameOrBefore à .isBefore

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

33
Kyle Muir

Momentjs ne fournit pas cela seul mais il existe un plugin qui le propose: moment-range .

Plus précisément, consultez les Documents d'itération .

4
Cody Caughlan

En tant qu'extension de la réponse de Kyle - j'ai essayé de faire fonctionner cela avec les horodatages Unix et après beaucoup d'essais et d'erreurs, je l'ai fait fonctionner et j'ai pensé le poster ici au cas où quelqu'un chercherait la même chose et aurait besoin il. Voir mon code ci-dessous:

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

Notez que je le convertis en Unix, puis convertis à nouveau cette valeur en moment. C'était le problème que j'avais, vous devez en faire une valeur de moment pour que cela fonctionne.

Exemple d'utilisation:

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

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

Reviendra:

['2017/03/11', '2017/03/12', '2017/03/13']
1
jock.perkins

Vous pouvez facilement énumérer avec moment.js Voici une solution plus générique pour les jours, semaines, mois ou années:

https://Gist.github.com/gvko/76f0d7b4b61b18fabfe9c0cc24fc3d2a

1
Milkncookiez