Moment.js diferencia de meses

4 minutos de lectura

He estado usando moment.js por un tiempo y ha hecho que la manipulación de fechas sea mucho más fácil, pero tengo un caso específico que está fallando y no veo por qué.

Al calcular la diferencia entre hoy (31 de octubre de 2013) y el 1 de febrero de 2014, la diferencia de meses vuelve a ser 2, aunque hay 3 meses completos y un día entre las dos fechas.

La diferencia entre el 31 de octubre y el 31 de enero funciona bien: 3 meses y cero días.

var mStartDate = moment([ periodStartDate.getFullYear(), periodStartDate.getMonth(), periodStartDate.getDate() ]);
var mTermDate = moment([ someDate.getFullYear(), someDate.getMonth(), someDate.getDate() ]);

console.log('periodStartDate: ' + periodStartDate);
console.log('someDate: ' + someDate);

// Years
var yearsDiff = mTermDate.diff(mStartDate, 'years');

// Months
var monthsDiff = mTermDate.diff(mStartDate, 'months', true);

La consola registra lo siguiente:

periodStartDate: Thu Oct 31 2013 11:13:51 GMT+0000 (GMT)
someDate: Sat Feb 01 2014 11:13:51 GMT+0000 (GMT)
monthsDiff: 2

Si paso verdadero como el booleano para no redondear, la diferencia de meses es

monthsDiff: 2.983050847457627 

¿Es esto solo un error en Moment.js.diff()? Todos y cada uno de mis otros casos de prueba pasan con éxito.

  • Me encontré con esto en la versión 2.2.1; también puedo ver que sucede con la 2.4.0.

    – Khain

    31/10/2013 a las 11:45

avatar de usuario de robertklep
robertklep

Creo que esto tiene que ver con el ‘manejo especial’ como se describe en el fino manual:

Está optimizado para garantizar que dos meses con la misma fecha estén siempre separados por un número entero.

Así que del 15 de enero al 15 de febrero debería ser exactamente 1 mes.

Del 28 de febrero al 28 de marzo debería ser exactamente 1 mes.

Del 28 de febrero de 2011 al 28 de febrero de 2012 debe ser exactamente 1 año.

Moment.js aplica este manejo especial cuando se trata de 31 Jan y 31 Oct (que tiene el mismo día):

// 31 Oct 2013 - 1 Feb 2014
> moment([2014, 1, 1]).diff(moment([2013, 9, 31]), 'months', true)
2.983050847457627

// 31 Oct 2013 - 31 Jan 2014
> moment([2014, 0, 31]).diff(moment([2013, 9, 31]), 'months', true)
3

// 31 Oct 2013 - 30 Jan 2014
> moment([2014, 0, 30]).diff(moment([2013, 9, 31]), 'months', true)
2.967741935483871

Entonces el 2.98 El valor es correcto, es solo que el segundo ejemplo convierte el resultado en una diferencia de ‘meses calendario’.

(en cuanto al redondeo a 2, eso también está documentado en la misma página)

  • gracias roberto Pero, ¿no es extraño que el valor suba (al calcular la diferencia con el 31/01) en comparación con el 30/01 y luego vuelva a bajar? Esperaría algo como 2.967, luego 3, luego 3.02 o algo así. Si hay 3 meses completos entre dos fechas, ¿cómo puede haber menos cuando sumo un día? La otra cosa que hago después de todo esto, es que muestro la diferencia en forma de “X meses e Y días”. Entonces… si hay 2 meses, eso me lleva al 31/12, y luego hay 32 días para llegar al 1 de febrero.

    – Khain

    31 de octubre de 2013 a las 12:26


  • @Khain debido a que el valor de los días es el mismo, fija el valor a un número entero (ese es el “manejo especial”). Para las otras fechas, no se sujeta y usa el valor exacto (coma flotante).

    – robertklep

    31/10/2013 a las 13:00

  • @robertklep te refieres a momento([2013, 10, 31]).diferencia ? ¿Puede ser un error tipográfico?

    – GLP

    07/04/2016 a las 15:10

  • @LPG, ¿te refieres a crear una instancia que represente el 31 de octubre? eso debería ser moment([2013, 9, 31]) (dado que los meses están indexados en 0, por lo que 0 es enero, 1 es febrero, etc.).

    – robertklep

    7 abr 2016 a las 19:09

Avatar de usuario de MrB
mrb

Tomé una ruta diferente tratando de obtener la diferencia entre dos meses

function getAbsoluteMonths(momentDate) {
  var months = Number(momentDate.format("MM"));
  var years = Number(momentDate.format("YYYY"));
  return months + (years * 12);
}

var startMonths = getAbsoluteMonths(start);
var endMonths = getAbsoluteMonths(end);

var monthDifference = endMonths - startMonths;

Esto tenía sentido para mí y dado que moment está haciendo algunas cosas extrañas con diff, decidí dejar en claro cuál será mi resultado.

  • de la biblioteca de último momento, simplemente devuelva d.month() + d.year()*12

    – viento maomao

    16 de agosto de 2017 a las 13:05

  • ¿Por qué multiplicar los años por 12? ¿Esto no lograría el mismo resultado sin eso?

    – Irossy

    27 de diciembre de 2017 a las 18:57

  • Hice 12 porque si nuestro inicio es 04-2017 y el final es 01-2018 si solo tomaste los meses + el año te daría 2021 – 2019 = 4 que estoy buscando 9.

    – MrB

    11 de mayo de 2018 a las 2:37

Solución simple y fácil con la diferencia de valor correcta entre dos meses si está utilizando Moment Library

  const monthDifference =  moment(new Date(endDate)).diff(new Date(startDate), 'months', true);

Si desea agregar el número de días en endDate

 const monthDifference = moment(new Date(endDate.add(1, 'days'))).diff(new Date(startDate), 'months', true);

prueba esto method;

function getMonthDifference(startDate, endDate) {
    const increment = startDate.getMonth() === endDate.getMonth() ? 2 : 1;
    const diff = moment(endDate).diff(moment(startDate), 'months', true);
    return Math.ceil(diff) + increment;    // this increment is opitional and totally depends on your need.
}

¿Ha sido útil esta solución?