シリアル値
エクセルで経過日数を求めるには日付同士を単純に引き算すれば求められます。
エクセルではシリアル値という値を使って日付を管理しているからです。シリアル値は1900年1月1日を「1」、2日を「2」として延々と日数を数えた値です。
例えば、2001年2月18日から2004年1月1日までの経過日数を求めてみます。
2001年2月18日のシリアル値は「36940」で
2004年1月1日のシリアル値は「37987」ですので、引き算して
37987-36940=1047(日)となります。
なお1900年は閏年ではないのですが、Excelでは閏年として設計されていますので、1900年2月29日が存在する前提で計算されることに注意する必要があります。
JavaScriptにおける日付は1970年1月1日午前0時からの経過ミリ秒で管理されています。
したがって、Excelと同様、日付同士を引き算して、24*60*60*1000で割れば経過日数が求められます。
修正ユリウス日
困るのはExcelでは1900年より前の場合、JavaScriptでは1970年より前の場合です。それぞれのシステムの中では経過日数を計算することができません。
ここで使われるのがユリウス日というものです。これは紀元前4713年1月1日正午からの経過日数を表します。ただしこれを使うととても数値が大きくなるので現代では修正したものを使うのが一般的です。これを修正ユリウス日(MJDと略されます)と言います。1858年11月18日では修正ユリウス日は「1」になります。
この修正ユリウス日には公式があります。
VBA、JavaScriptで書いてみると次の通りです。
VBA
Function MJD(y, m, d)
If m < 3 Then
m = m + 12
y = y - 1
End If
MJD = Int(365.25 * y) + Int(y / 400) - Int(y / 100) + Int(30.59 * (m - 2)) + d - 678912
End Function
JavaScript
function mjd(y,m,d){
if(m<3){
m+=12;
y--;
}
return(Math.floor(365.25*y)+Math.floor(y/400)-Math.floor(y/100)+Math.floor(30.59*(m-2))+d-678912);
}
詳しい説明は省きますが、これを使うとExcelやJavaScriptの制限なしに経過日数を計算することができます。
Excelのヘルプ
Excel2007のヘルプにこんなのがあります。
ユリウス日は、現在の年と 1 月 1 日からの通算日数とを組み合わせて日付を表示するときに使用される場合があります。たとえば、2007 年 1 月 1 日は 2007001 と表され、2007 年 12 月 31 日は 2007365 と表されます。この形式はユリウス暦に基づいているわけではないことに注意してください。
Excelでは「2010年3月10日」は「2010069」をユリウス日と呼ぶそうです。何のために使うのでしょうか。わざわざ説明があるということは使う人がいるのでしょう。
また次のようなことも書かれています。
これとは別に、天文学上で一般的に使用されるユリウス暦の日付もあります。これは、紀元前 4713 年 1 月 1 日を起算点とした通日で表す日付システムです。
こちらの方が一般的だと思います。
まとめ
ユリウス日(ユリウス通日)と修正ユリウス日とExcelのシリアル値の関係をまとめておきます。
- ユリウス日=修正ユリウス日+2400000.5
- ユリウス日=シリアル値+2415018.5
- 修正ユリウス日=シリアル値+15018
経過月日の計算の方法は「3月10日から6月20日」のように日数の部分が単純に差で求められる場合は簡単である。
一方、「3月20日から6月10日」のように日数の部分が負になる場合が面倒である。
この場合の計算方法は、いくつか考えられるが一般的なのは次の二つだろう。
- その1
「期始の日から期末の前月の同じ日までの月数」と「残りの日数」を加える方法。
- その2
「期始の日からその月末までの日数」と「期始の属する月の翌月から期末の属する月の前月までの月数」と「期末の月始から期末までの日数」を加える方法。
試しに計算してみる。
なお、ここでは、いわゆる「初日不算入」とする。例えば3月1日から3月5日までは4日間となる。「片端」と呼ぶこともあるようだ。
3月20日から6月10日までの経過月日
その1
3月20日から5月20日まではちょうど2か月間。
5月20日から5月31日までは11日間。
5月31日から6月10日までは10日間。
全部で2か月21日。
その2
3月20日から3月31日までは11日間。
3月31日から5月31日まではちょうど2か月間。
5月31日から6月10日までは10日間。
全部で2か月21日。
同じ結果になる。
12月20日から3月10日までの経過月日
その1
12月20日から2月20日まではちょうど2か月間。
20月20日から2月28日までは8日間。
2月28日から3月10日までは10日間。
合わせて2か月18日。
その2
12月20日から12月31日までは11日間。
12月31日から2月28日まではちょうど2か月間。
2月28日から3月10日までは10日間。
合わせて2か月21日。
どちらが正しいか、はっきりしない。
なお、ExcelのDATEDIF関数の考え方は次の通りだと思われる。
その2に近い。
まず期始の日から31日までの日数を数える。大の月だろうが小の月だろうが2月だろうが31日である。
あとはその2と同じ。正しく計算されるはずがない。
PHPのstrtotimeは例えば「10 September 2000」という日付を表す文字列をタイムスタンプに変換してくれます。
PHP: strtotime – Manual
しかしこのような英文形式の日付は日本人には馴染みません。
またMySQLの日付形式とも違います。
MySQLの日付形式は「2000-09-10」という日本人に馴染みやすい表記です。
実は、PHPのマニュアルには書かれていませんが、「2000-09-10」という形式であってもstrtotimeは正しくタイムスタンプに変換します。
これはとても便利。
Twitterの日付形式をExcelのシリアル値に変換する、VBAのコードです。
Function twitter_dateserial(td)
‘Twitterの日付形式をExcelのシリアル値に変換する。
‘変換前「Tue Jul 21 03:23:04 +0000 2009」
ds = Split(td, ” “)hs = Split(ds(3), “:”)
mstr = (InStr(“JanFebMarAprMayJunJulAugSepOctNovDec”, ds(1)) + 2) / 3
twitter_dateserial = DateSerial(ds(5), mstr, ds(2)) + TimeSerial(hs(0) + 9, hs(1), hs(2))
End Function
Twitterの投稿データをJSONなどで取得すると、日付は「Tue Dec 16 23:48:56 +0000 2008」のようになります。
英語表記なので分かりにくい上、そもそもイギリス時間。
これを「2008年12月17日 8:48:56」のような日本語表記に直すJavaScriptの例です。
function twitterdate(td){
//変換前「Tue Dec 16 23:48:56 +0000 2008」
//変換後「2008年12月17日 8:48:56」
re=/^(.+) (.+) (..) (..):(..):(..) (.+) (.+)$/;
pat=”$2 $3, $8 $4:$5:$6 UTC+0000″;
rep=new Date(td.replace(re,pat));
return(rep.toLocaleString());
}
もっとシンプルにできないものかなあ。
最近のコメント