2013-04-22 10 views
6

Ho calcolato utilizzando la funzione seguente e fornisce l'o/p nel formato di "X YEARS, Y MONTHS, Z DAYS" e per alcune date il suo dare sbagliato o/p. Penso di aver fatto qualche calcolo mancante nelle formule.Calcolo anno, mese, giorni tra le date nello script di google apps

La funzione è,

/** 
* @param {Date} startdate 
* @param {Date} enddate 
* @return {String} 
*/ 
function leasePeriodCalc(startDate,endDate) 
{ 
    var sdate=startDate; 
    var edate=endDate; 
    edate.setDate(edate.getDate()+1); 
    edate=new Date(edate); 
    if(sdate.valueOf()>edate.valueOf()){ 
    return('0'); 
    } 
    else{ 
    var years=((((edate.getDate()-sdate.getDate())<0 ? -1:0)+((edate.getMonth()+1)-(sdate.getMonth()+1)))< 0 ? -1 : 0)+(edate.getFullYear()-sdate.getFullYear()); 
    var months=((((edate.getDate()-sdate.getDate())<0 ? -1:0)+((edate.getMonth()+1)-(sdate.getMonth()+1)))< 0 ?12:0)+((edate.getDate()-sdate.getDate())<0 ? -1:0)+((edate.getMonth()+1)-(sdate.getMonth()+1)); 
    if((edate.getMonth()-1)!=1.0) 
    { 
     var days=((edate.getDate()-sdate.getDate())< 0 ?new Date(edate.getFullYear(), edate.getMonth(),0).getDate():0)+(edate.getDate()-sdate.getDate()); 
    } 
    else 
    { 
     var days=((edate.getDate()-sdate.getDate())< 0 ?new Date(edate.getFullYear(), edate.getMonth()+1,0).getDate():0)+(edate.getDate()-sdate.getDate()); 
    } 
    var day; 
    var month; 
    var year; 
    if(years>1)year= years+ 'Years'; 
    else year=years+'Year'; 
    if(months>1) month= months+ 'Months'; 
    else month=months+'Month'; 
    if(days>1) day= days+ 'Days'; 
    else day=days+'Day'; 
    if(years==0&&months!=0&&days!=0) return(month+', '+day); 
    else if(years!=0&&months==0&&days!=0) return(year+', '+day); 
    else if(years!=0&&months!=0&&days==0) return(year+', '+month); 
    else if(years==0&&months==0&&days!=0) return(day); 
    else if(years==0&&months!=0&&days==0) return(month); 
    else if(years!=0&&months==0&&days==0) return(year); 
    else if(years==0&&months==0&&days==0) return(day); 
    else if(years!=0&&months!=0&&days!=0) return(year+', '+month+', '+day); 
    } 
} 

se ti da i/p come sotto di esso la restituzione del falso o/p:

28 feb 2013 - 28 febbraio 2014

Previsto o/p: 1 anno, 1 GIORNO

Dato O/P: 1 anno, 4 GIORNI

Ma se io Selec t 28 Feb 2013 - 27 feb 2014 mezzi, ha dato il corretto O/P:

atteso o/p: 1 ANNO

Dato O/P: 1 ANNO

Si prega di consulenza per correggere colpa mia se ho fatto qualcosa

E anche io devo dire che non sto impostando le regole n tutte. In generale un mese sta calcolando secondo i giorni che si trovano sul mese.

Ad esempio, se otteniamo un prestito da una banca, pagheremo gli interessi al mese, solo quel mese potrebbe avere 30 giorni o 29 giorni o 28 giorni o 31 giorni.

E anche se prendiamo una stanza per i mezzi di noleggio mensili, pagheremo l'affitto al mese solo rito? anche dal 20 marzo al 19 aprile. Anche se contiene 31 giorni, si dice che sia solo un mese. Per favore aiutami a concludere questo.

Tnx, CL.

+1

miglior consiglio che posso darvi è quello di utilizzare moment.js per manipolare i valori di data (vedi http://momentjs.com/) – jbl

+0

Perché si aspetterebbe differenza dal 28 febbraio 2013 - 28 feb 2014 per essere 1 anno 1 giorno? – HMR

+0

Perché dovresti aspettarti che la differenza tra il 28 feb 2013 e il 27 feb 2014 sia di 1 anno invece di 11 mesi e 27 giorni? – HMR

risposta

0

Secondo tentativo:

function periodCalc(startDate, endDate) { 

    var output = ''; 

    var sYear = startDate.getFullYear(); 
    var sMonth = startDate.getMonth(); 
    var sDay = startDate.getDate() - 1; 
    var eYear = endDate.getFullYear(); 
    var eMonth = endDate.getMonth(); 
    var eDay = endDate.getDate(); 

    var tMonths = eYear * 12 + eMonth - sYear * 12 - sMonth; 
    var days = eDay - sDay; 

    if (days < 0) { 
    tMonths--; 
    var sDate = new Date(sYear, sMonth + tMonths, sDay); 
    var eDate = new Date(eYear, eMonth, eDay); 
    days = (eDate.getTime() - sDate.getTime())/86400000; 
    } 

    if (tMonths < 0) return '0'; 
    var months = tMonths % 12; 
    var years = (tMonths - months)/12; 

    output += (years == 0 ? '' : (', ' + years + ' Year' + (years == 1 ? '' : 's'))); 
    output += (months == 0 ? '' : (', ' + months + ' Month' + (months == 1 ? '' : 's'))); 
    output += (days == 0 ? '' : (', ' + days + ' Day' + (days == 1 ? '' : 's'))); 

    return output.substr(2); 
} 

Tuttavia un problema rimane quando la data di inizio è il primo giorno di un mese, e la data di fine è l'ultimo giorno del mese. Pertanto, ad esempio, dal 1 ° gennaio 2013 al 31 marzo 2013 verranno restituiti 2 mesi e 31 giorni. È questo il risultato desiderato?


Edit: primo tentativo (che è imperfetto, vedi primo commento):

devo ammettere il mio cervello faceva male un po 'guardando il codice, che sono sicuro che avrebbe solo un errore minore nella logica da qualche parte. Ho pensato che sarebbe stato più veloce se ho provato a riscrivere da zero, ma penso che avrebbe bisogno di qualche ulteriore prova (che funziona con il mio test limitata finora):

function periodCalc(startDate, endDate) { 
    var output = ''; 
    endDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), endDate.getDate() + 1); 
    var sYear = startDate.getFullYear(); 
    var sMonth = startDate.getMonth(); 
    var sDay = startDate.getDate(); 

    var eDay = endDate.getDate(); 
    var days = eDay - sDay; 
    if (days < 0) { 
    var eopm = new Date(endDate); 
    eopm.setDate(0); 
    days = eDay + eopm.getDate() - sDay; 
    endDate.setDate(eDay - days); 
    } 

    var eMonth = endDate.getMonth(); 
    var months = eMonth - sMonth; 
    if (months < 0) { 
    months = eMonth + 12 - sMonth; 
    endDate.setMonth(eMonth - months); 
    } 

    var eYear = endDate.getFullYear(); 
    var years = eYear - sYear; 
    if (years < 0) return '0'; 

    output += (years == 0 ? '' : (', ' + years + ' Year' + (years == 1 ? '' : 's'))); 
    output += (months == 0 ? '' : (', ' + months + ' Month' + (months == 1 ? '' : 's'))); 
    output += (days == 0 ? '' : (', ' + days + ' Day' + (days == 1 ? '' : 's'))); 

    return output.substr(2); 
} 
+0

Ottimo lavoro e mentre ho testato il tuo codice per il periodo di ** 29 - Feb - 2012 - 28 - Feb - 2013 ** sta dando ** 1 anno 1 mese ** che è errato e per il periodo di ** 31st - Marzo - 2013-30-30 - 2013 ** sta dando ** 2 mesi ** che è anche sbagliato o/p. Pls controlla questi scenari e Pls mi guida. Altrimenti tutti gli altri scenari sono inoltre perfetti ... – chocka

+0

Mille grazie per il bug report. Ho cambiato la logica un po 'e riscritto. Ma nota il potenziale problema. – AdamL

+0

2 mesi, 31 giorni non è il risultato desiderato per 1 gen 2013 31 marzo 2013, il risultato desiderato è di 3 mesi. E anche per gli scenari come dal 31 marzo 2013 al 30 aprile 2013 l'o/p desiderato è 1 mese 1 giorno, ma è solo 1 mese. Dai un'occhiata anche a Mr. AdamL, Tnx. – chocka

0

Ecco qualcosa che ho scritto qualche tempo fa, non è completamente testato, ma credo che dovrebbe fare quello che si suppone di fare

[UPDATE]: corretto il bug, ma ancora sconveniente quando la bassa data è 29 febbraio e diff è più di un anno

function dateDiff(a,b){ 
    var low = (a>b)?b:a, 
    heigh = (a>b)?a:b, 
    diff = { 
     years:0, 
     months:0, 
     days:0 
    }, 
    tmpDate, 
    tmpMonth; 
    //if you'd like the diff to be including the the last day 
    // of the end date you can do: lob.setDate(low.getDate()+1); 
    if(low==heigh){return diff;}//a===b no difference 
    diff.years=heigh.getFullYear()-low.getFullYear(); 
    tmpDate=new Date(low.getTime()); 
    tmpDate.setFullYear(low.getFullYear()+diff.years); 
    if(tmpDate>heigh){ 
     diff.years--; 
    } 
    low.setFullYear(low.getFullYear()+diff.years); 
    tmpMonth=heigh.getMonth()-low.getMonth(); 
    diff.months=(tmpMonth<0)?tmpMonth+12:tmpMonth; 
    tmpDate=new Date(low.getTime()); 
    tmpDate.setMonth(low.getMonth()+diff.months); 
    if(tmpDate>heigh){ 
     diff.months--; 
    } 
    low.setMonth(low.getMonth()+diff.months); 
    while(low<heigh){ 
     low.setDate(low.getDate()+1); 
     diff.days++; 
     if(low>heigh){ 
      low.setDate(low.getDate()-1); 
      diff.days--; 
      break; 
     } 
    } 
    return diff; 
} 


var a = new Date(2013,9,30); 
var b = new Date(2014,1,26); 
console.log(dateDiff(a,b)); 
//next one is a bit buggy, one might say it's 
// 1 year and 1 day if considoring end of feb 2000 
// to 1st of mar 2001 
var a = new Date(2000,1,29); 
var b = new Date(2001,2,1); 
console.log(dateDiff(a,b)); 
+0

Nice work @HMR, ma alcune piccole correzioni necessarie per gli scenari come 26 feb 2013 - 30 marzo 2013 sono di 33 giorni, 27 feb 2013 - 30 marzo 2013 sono di 32 giorni (cioè se la data di fine è l'ultima ma una data del mese significa che restituisce l'errore o/p). Pls chiarisce questo dubbio e inoltre il calcolo è perfetto. Tnx. – chocka

+0

Sei sicuro? Ho copiato e incollato il codice nella console in firebug e quando si fa var a = new Date (2013,1,26); // Feb 26 var b = new Date (2013,2,30); // Mar 30 console .log (dateDiff (a, b)); Ottengo oggetto {anni = 0, mesi = 1, giorni = 4} – HMR

+0

C'è un bug nel codice; quanto segue fornirà un diff non corretto: var a = new Date (2013,9,30); var b = new Date (2014,1,26); console.log (dateDiff (a, b)); – HMR

19

Per complesse manipolazioni di data/ora in JavaScript trovo che la biblioteca Moment.js può davvero aiutare. L'ho incluso in una libreria di Apps Script, che puoi includere utilizzando la chiave di progetto MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48. L'ho usato per prendere una crepa a questo problema, anche se potrei aver perso alcuni casi limite.

// Load the library (key: MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48). 
var moment = Moment.load(); 

function getDuration(startDate, endDate) { 
    var start = moment(startDate); 
    var end = moment(endDate); 
    var units = ['years', 'months', 'days']; 
    var parts = []; 
    units.forEach(function(unit, i) { 
    var diff = Math.floor(end.diff(start, unit, true)); 
    if (diff > 0 || i == units.length - 1) { 
     end.subtract(unit, diff); 
     parts.push(diff + ' ' + unit); 
    } 
    }) 
    return parts.join(', '); 
} 
+3

Brillante, @Eric. Come hai avvolto il momento del consumo da parte di GAS? –

+2

Vorrei anche sapere come avvolgere una lib JavaScript per lo script di Google Apps. – Karakuri

+0

Vorrebbe ancora sapere – howMuchCheeseIsTooMuchCheese

0

seguente codice di lavoro per me assicurarsi u associare moment.js in script prima di eseguire

var moment = Moment.load() 

    var StartDate= new Date(StartDate1); 
    var DD1 = StartDate.getDate();  
    var MM1 = StartDate.getMonth(); 
    var MM1=MM1+1     //As Month Start with Zero 
    var YYYY1 = StartDate.getYear(); 

    var EndDate= new Date(EndDate1); 
    var DD = EndDate.getDate();  
    var MM = EndDate.getMonth(); 
    var MM=MM+1     //As Month Start with Zero 
    var YYYY = EndDate.getYear(); 



    var a = moment([YYYY, MM, DD]); 
    var b = moment([YYYY1, MM1, DD1]); 
    return a.diff(b, 'days') 
    Logger.log(a.diff(b, 'days')) 
0

Altra alternativa di Date.Diff. xDate è un wrapper sopra oggetto JavaScript Date:

//----------------------------------------------------------------------------- 
// Date Wrapper 
//----------------------------------------------------------------------------- 
var kDate = function() { 
    "use strict"; 
    var dat = NaN, that = this; 
    switch (arguments.length) { 
    case 0: dat = new Date(); break; 
    case 1: dat = new Date(arguments[0]); break; 
    default: 
     dat = new Date(arguments[0] || null, arguments[1] || null, arguments[2] || null, arguments[3] || null, 
         arguments[4] || null, arguments[5] || null, arguments[6] || null); 
    } 
    Object.getOwnPropertyNames(Date.prototype).forEach(function(prop) { 
     that[prop] = function() { 
      return dat[prop].apply(dat, arguments); 
     }; 
    }); 
    return this; 
}; 
Object.getOwnPropertyNames(Date).forEach(function(prop) { 
    if (["length", "name", "arguments", "caller", "prototype"].indexOf(prop) < 0) { 
     kDate[prop] = Date[prop]; 
    } 
}); 

kDate.MAXDATE = 8640000000000000; 
kDate.MINDATE = -8640000000000000; 
kDate.YEARZERO = -62167132800000; 
kDate.YEAR = 31536000000; 
kDate.MONTH = 2592000000; 
kDate.DAY = 86400000; 
kDate.HOUR = 3600000; 
kDate.MINUTE = 60000; 
kDate.SECOND = 1000; 

//----------------------------------------------------------------------------- 
// kDate.diff() 
//----------------------------------------------------------------------------- 
kDate.diff = function(date1, date2) { 
    var d1, d2; 
    d1 = kDate.MAXDATE + (typeof date1 === 'number' ? date1 : date1.getTime()); 
    d2 = kDate.MAXDATE + (typeof date2 === 'number' ? date2 : date2.getTime()); 
    diff = new kDate(NaN); 
    diff.diffDate1 = new kDate(typeof date1 === 'number' ? date1 : date1.getTime()); 
    diff.diffDate2 = new kDate(typeof date2 === 'number' ? date2 : date2.getTime()); 
    diff.diffTotalMilliseconds = d2 < d1 ? d1 - d2 : d2 - d1; 
    diff.setTime(kDate.YEARZERO + diff.diffTotalMilliseconds); 
    diff.diffTotalSeconds = diff.diffTotalMilliseconds/kDate.SECOND; 
    diff.diffTotalMinutes = diff.diffTotalMilliseconds/kDate.MINUTE; 
    diff.diffTotalHours = diff.diffTotalMilliseconds/kDate.HOUR; 
    diff.diffTotalDates = diff.diffTotalMilliseconds/kDate.DAY; 
    diff.diffYears =  diff.diffDate1.getUTCFullYear() - diff.diffDate2.getUTCFullYear(); 
    diff.diffMonth =  diff.diffDate1.getUTCMonth() - diff.diffDate2.getUTCMonth(); 
    diff.diffDate =   diff.diffDate1.getUTCDate() - diff.diffDate2.getUTCDate(); 
    diff.diffHours =  diff.diffDate1.getUTCHours() - diff.diffDate2.getUTCHours(); 
    diff.diffMinutes =  diff.diffDate1.getUTCMinutes() - diff.diffDate2.getUTCMinutes(); 
    diff.diffSeconds =  diff.diffDate1.getUTCSeconds() - diff.diffDate2.getUTCSeconds(); 
    diff.diffMilliseconds = diff.diffDate1.getUTCMilliseconds() - diff.diffDate2.getUTCMilliseconds(); 
    return diff; 
}; 
kDate.prototype.diff = function (date) { 
    return kDate.diff(this, date); 
}; 
Problemi correlati