Los cálculos son exactos. El truco para simplificar la función es usar dos variables de fecha auxiliares f1 y f2 y forzar a que f2 siempre sea la mayor de fa y fb y por tanto f1 la menor.
En la red no he encontrado nada similar por lo que me atrevo a publicarla y espero que pueda servir de ayuda.
Código:
function diferenciafechas(fa,fb){ //fa y fb dos fechas var totdias = fa-fb; totdias /=3600000; totdias /=24; totdias= Math.floor(totdias); totdias= Math.abs(totdias); var ans, meses, dias, m2, m1, d3, d2, d1; var f2=new Date(); var f1=new Date(); if (fa > fb){f2=fa;f1=fb;}else{var f2=fb; f1=fa;} //Siempre f2 > f1 ans=f2.getFullYear()-f1.getFullYear(); // dif de años inicial m2=f2.getMonth(); m1=f1.getMonth(); meses=m2-m1; if (meses<0){meses +=12; --ans; } d2=f2.getDate(); d1=f1.getDate(); dias=d2-d1; var f3=new Date(f2.getFullYear(),m2,1); f3.setDate(f3.getDate()-1); d3=f3.getDate(); if (d1>d2) { dias +=d3; --meses; if (meses<0){meses +=12; --ans; } if (fa>fb){ //corrección por febrero y meses de 30 días f3=new Date(f1.getFullYear(),m1+1,1); f3.setDate(f3.getDate()-1); d3=f3.getDate(); if (d3==30) dias -=1; if (d3==29) dias -=2; if (d3==28) dias -=3; } } return {ans:ans,meses:meses,dias:dias,Tdias:totdias}; }