2015-05-02 26 views
0

我正在做一些日期庫的增強,它已經返回日期單位的差異,如這個問題的標題。我希望它返回相對單位。我寫了一些代碼,但感覺就像我在數學的錯誤結尾工作。相對日期:1/1/1981 01:01:01 - 1/1/1980 = 1y 366d等,想要1y 1d等

注意:忘記閏年和其他DateTime錯綜複雜。這是一個不嚴格的應用程序。

這裏是正在考慮的代碼。

// get ms between UTC dates and make into "difference" date 
var iDiffMS = dt2.valueOf() - dt1.valueOf(); 
var dtDiff = new Date(iDiffMS); 

// calc various diffs 
var nYears = dt2.getUTCFullYear() - dt1.getUTCFullYear(); 
var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears!=0 ? nYears*12 : 0); 
var nQuarters = parseInt(nMonths/3); //<<-- different than VBScript, which watches rollover not completion 

// these are in absolute terms, ie totals of unit differences, 1/2/1981 - 1/1/1980 = 1y 366d 
var nMilliseconds = iDiffMS; 
var nSeconds = parseInt(iDiffMS/1000); 
var nMinutes = parseInt(nSeconds/60); 
var nHours = parseInt(nMinutes/60); 
var nDays = parseInt(nHours/24); // <-- now fixed for DST switch days 
var nWeeks = parseInt(nDays/7); 
// save absolutes 
var nYears0=nYears; 
var nMonths0=nMonths; 
var nQuarters0=nQuarters; 
var nWeeks0=nWeeks; 
var nDays0=nDays; 
var nHours0=nHours; 
var nMinutes0=nMinutes; 
var nSeconds0=nSeconds; 

// HERE! go from absolute to relative, 1/2/1981 - 1/1/1980 = 1y 1d etc, not 1y 366d etc 
nQuarters  -=nYears0*4; 
nMonths  -=nYears0*12; 
nWeeks  -=parseInt((nYears0*52)+(nMonths0*(365.25/52))); 
nCalWeeks  -=parseInt((nYears0*52)+(nMonths0*(365.25/52))); 
nQuarters  -=nYears0*4; 
nDays   -=parseInt((nYears0*365.25)    +(nMonths*(365.25/12))); 
nHours  -=parseInt((nYears0*365.25*24)   +(nMonths*(365.25/12*24))   +(nDays*24)); 
nMinutes  -=parseInt((nYears0*365.25*24*60)   +(nMonths*(365.25/12*24*60))  +(nDays*24*60)   +(nHours*60)); 
nSeconds  -=parseInt((nYears0*365.25*24*60*60)  +(nMonths*(365.25/12*24*60*60))  +(nDays*24*60*60)  +(nHours*60*60)  +(nMinutes*60)); 
nMilliseconds -=parseInt((nYears0*365.25*24*60*60*1000) +(nMonths*(365.25/12*24*60*60*1000))+(nDays*24*60*60*1000) +(nHours*60*60*1000) +(nMinutes*60*1000) + (nSeconds*1000)); 
// END 
+0

按照你想要的格式,什麼是正確的答案爲3/3/1981 - 1/1/1980?你想要'1年,2個月,2天'嗎? –

+1

是的,只是把以毫秒爲單位的差異(1970年後),並將其轉換回 – maraca

+0

是,1年,2個月,2天,X小時,等 –

回答

0

有可能從更大的單位更小的單位工作實現這一點,但它可能更容易從小型工作很大,因爲你沒有繁殖的因素提前。例如,你不必提前知道一天是24 * 60 * 60 * 1000毫秒。相反,當你從最小單位到最大單位時,你可以建立這些因素。

第一步,你知道你有1000分的毫秒數來獲得的秒數。在第二步中,將秒數除以60得到分鐘數。接下來,你除以60來獲得小時數。接下來,你除以24得到的日子。

要確保你不重複計算單位,則可以使用模運算符,%。例如,如果分鐘數是135,則計算135 % 60以得到15,這是扣除整小時後剩下的分鐘數。一般來說,在顯示當前單位的數量之前,您想要針對下一個更大的單位取模。

以下腳本實現此方法。

function getDifferenceInWords(dateStart, dateEnd) { 
 
    var delta = dateEnd.valueOf() - dateStart.valueOf(); 
 
    if (delta < 0) { 
 
    var describe = "earlier"; 
 
    delta = -delta; 
 
    } else { 
 
    var describe = "later"; 
 
    } 
 
    var units = [{ name: 'second', multiple: 1000 }, 
 
       { name: 'minute', multiple: 60 },  
 
       { name: 'hour', multiple: 60 },  
 
       { name: 'day', multiple: 24 },  
 
       { name: 'week', multiple: 7 },  
 
       { name: 'quarter', multiple: 13 }, 
 
       { name: 'year', multiple: 4 }], 
 
     divisor = 1, 
 
     parts = []; 
 
    for (var i = 0; i < units.length; ++i) { 
 
    var unit = units[i]; 
 
    divisor *= unit.multiple; 
 
    if (divisor > delta) { 
 
     break; 
 
    } 
 
    var count = Math.floor(delta/divisor); 
 
    if (i+1 < units.length) { 
 
     count %= units[i+1].multiple; 
 
    } 
 
    if (count != 0) { 
 
     parts.push(count + ' ' + unit.name + (count == 1 ? '' : 's')); 
 
    } 
 
    } 
 
    parts.reverse(); 
 
    return parts.join(', ') + ' ' + describe; 
 
} 
 

 
var dateStart = new Date('January 1, 1995 09:01:30'), 
 
    dateEnd = new Date('May 1, 2015 23:05:15'); 
 

 
document.write(getDifferenceInWords(dateStart, dateEnd));

您可以通過縮寫單位名稱或變更單位的順序調整代碼根據自己的喜好。

例如,你可能想介紹個月周,如果你能在幾個月至數週的固定比率解決小區之間的中間部。我寧願忽略每月單位,因爲不同的月份有不同的長度,這會導致結果不一致,具體取決於您處理的日期。

修改單位的另一種方法可能是增加數十年,數百年和數千年。只要你遵循units數據結構的模式,每個單位是前一個單位的固定倍數,你就不會出錯。

+0

我喜歡這種方法,雖然它融合了計算串組輸出。我確信這個月的事情可以通過某種計算來解決,但我的大腦現在還沒有做好。 –

+0

這些字符串根本不影響計算。我只是通過形成多個單位名稱並忽略零單位數來美化輸出。 –

0

好的,這就是我一直在尋找的,注意到一旦你開始工作時,它是如何改變的。繼續沿着t1-=的路徑將導致閏年導致時間錯誤。此外,還需要以這種方式計算幾個月來糾正飛躍。雖然我懷疑weeks計算有問題。

var d1=new Date('1/1/1980 00:00:00:000'); 
var d2=new Date('2/8/1981 01:01:01:001'); 
//BUG "1y 1m 1w 1d 23h 59mins 59secs 999ms" should be 0d 
//var d2=new Date('2/7/1981 23:59:59:999'); 

var t1=d2.valueOf() - d1.valueOf(); 
console.log(t1); 
var nYears= parseInt(t1/(1000*60*60*24*365.25)); 
t1-=nYears*(1000*60*60*24*365.25); 
var s=''; 
s+=nYears+'y'; 
var nMonths=d2.getUTCMonth() - d1.getUTCMonth(); 
nMonths=nMonths>0?nMonths:nMonths+12; 
s+=' '+nMonths+'m' 
t1-=nMonths*1000*60*60*24*(365.25/12); 
var nWeeks=parseInt(t1/(1000*60*60*24*7)); 
s+=' '+nWeeks+'w' 
t1-=nWeeks*(1000*60*60*24*7); 
var nDays=parseInt(t1/(1000*60*60*24)); 
s+=' '+nDays+'d' 
t1-=nDays*(1000*60*60*24); 
var nHours=d2.getHours()-d1.getHours(); 
s+=' '+nHours+'h'; 
var nMinutes=d2.getMinutes()-d1.getMinutes(); 
s+=' '+nMinutes+'mins'; 
var nSeconds=d2.getSeconds()-d1.getSeconds(); 
s+=' '+nSeconds+'secs'; 
var nMilliseconds=d2.getMilliseconds()-d1.getMilliseconds(); 
s+=' '+nMilliseconds+'ms'; 
//console.log(d1.getHours()); 
console.log(s); //"1y 1m 1w 1d 1h 1mins 1secs 1ms" 
+0

此代碼不起作用。試用'var d1 = new Date('12/25/1980 10:10:00:000'); var d2 = new Date('2/8/1981 01:01:01:001');' –

+0

修正了它,謝謝 –

+0

仍然不起作用。如果你想使用內置的'get ...()'函數,你必須確保你從過去到未來,從未來到過去。或者你可以避免所有這些,只是使用算術運算,就像我在答案中顯示的那樣。 –