日付・時刻

【JavaScript】 経過時間や日数を取得し処理時間などを計測

更新日:2023/04/11

 

現在の時間を取得する

プログラム中の処理にかかった時間を知りたいなど、タイマー的な経過時間を知りたいときはDate.now()で現在の時間を取得します。


const nowtime = Date.now();

Date.now()はタイムスタンプを返します。
タイムスタンプは、UTCでの1970年1月1日0時0分0秒から現在までの経過時間をミリ秒単位で表したものです。

例えば2021年4月28日の12時30分25秒にDate.now()を実行すると、次の値が返ってきます。

1619580625000

この値はミリ秒なので秒にすると、1,619,580,625.000秒です。
分にするには60で割るので、26,993,010.41666667分。
時間はさらに60で割って、449,883.5069444444時間。
日数は24で割って、18,745.14612268519日。
年数は365で割って、51.35656471968544年となり、1970年から51年経過しているのがわかります。

年数はうるう年があるので365で割るのは正確ではありません。
正確な年を求めるには、次のようにDateコンストラクターでインスタンスを作成して、getFullYear()を呼び出します。


new Date(1619580625000).getFullYear();
// 2021

1970年からの経過年数は、この結果から1970を引いて求めます。

ちなみに時間についての操作で1970年1月1日0時0分0秒を気にする必要はありません。
JavaScriptの標準オブジェクト側で上手くやってくれます。

詳しくは次のページを読んでみてください。

関連記事:
【JavaScript】 今日の日付を取得・表示するサンプルコード
【JavaScript】 日時と時刻を取得して表示してみる
【JavaScript】 Dateオブジェクトから和暦を取得する
【JavaScript】 うるう年判定の一番簡単な方法

 

起点となる日時のタイムスタンプを取得する

誕生日から現在の経過時間を知りたいなど起点となる日時をもとに計算したいときは、Dateのインスタンスを作成してgetTime()を呼び出します。


const  myBirthDayTime = new Date("2010/4/1").getTime();

Dateコンストラクターの引数は、上の例のように年月日で指定する他に、いくつかの方法があります。
方法は次のページを読んでみてください。
【JavaScript】 日時と時刻を取得して表示してみる

コンストラクターから作成されたインスタンスのgetTime()を実行すると、Date.now()で解説したタイムスタンプが返ってきます。

上の例では、次の値が返ってきます。

1270047600000

経過日数の求めかたを紹介した記事で、2つのDateオブジェクトを引き算しているケースがあります。


const  date1 = new Date("2010/4/1");
const  date2 = new Date("2011/4/1");

 // 経過ミリ秒を表示
console.log( date2 - date1 );

この結果は31536000000となり、経過ミリ秒の計算ができています。

しかし、加算するとうまくいきません。


 // ミリ秒を加算
console.log( date2 + date1 );

この結果は、次のようになります。

Fri Apr 01 2011 00:00:00 GMT+0900 (日本標準時)Thu Apr 01 2010 00:00:00 GMT+0900 (日本標準時)

つまり、文字表記に変換されています。

Dateオブジェクトの演算は演算子により結果が変わってしまうため、getTime()を使用することをおすすめします。

 

経過時間を求める

現在時刻または起点となる日時のタイムスタンプを取得できたら、比較する時刻のタイムスタンプを取得します。

そのタイムスタンプから、以前取得したタイムスタンプを引き算すれば経過時間を求めることができます。

タイマー的な経過時間を取得する

次のように開始時刻のタイムスタンプを変数に取得し、時間経過後のタイムスタンプから引き算をすることでタイマー的な経過時間を取得できます。


const startTime = Date.now();

// 処理時間を計測したいコード
for( let i = 0; i < 100000 ; i++ ) {}  

// 経過時間をミリ秒で取得
const elapsedTime = Date.now() - startTime;

上のコードから汎用的な処理時間計測関数を作成してみます。


const timer = function (){
    let startTime = null;
    let stopTime = null;
    const wrap = [];
    const isStart = ()=>startTime!==null && stopTime===null;

    return {
        start:()=>{startTime = Date.now();wrap.length = 0;stopTime=null;},
        wrap:( message = "")=>{if(isStart()) wrap.push( [Date.now(),message] )},
        stop:()=>{if(isStart()) stopTime = Date.now();},
        result:()=>{
            if( startTime === null ||  stopTime === null ) return null;
            return {
                time: stopTime - startTime,
                wrap: wrap.map( e=>[e[0]-startTime,e[1]] )
            }
        }
    }
}

const t = timer();
t.start();

for( let i = 0 ; i < 10000 ; i ++);

t.wrap("10000回ループ");

for( let i = 0 ; i < 1000000 ; i ++);

t.wrap("1000000回ループ");
t.stop();

const result = t.result().wrap;
result.forEach(e=>console.log( e[1] + ":" + e[0] + "ミリ秒"));

基本的に、Date.now()の結果を保存しているだけです。
考え方はとても簡単ですね。

別の記事で時間経過取得を利用したストップウォッチを作成しています。
興味がある方はご覧ください。
【JavaScript】 サクッとストップウォッチを作ってみる

特定の日時から現在までの経過時間を取得する

例えば生まれた日から現在までの年数と日数を求めるとき、生まれた日からDateオブジェクトを作成してタイムスタンプを取得し、現在のタイムスタンプから差し引きます。


// 起点となる日時のタイムスタンプを取得
const  myBirthDayTime = new Date("2010/4/1").getTime();

// 現在までの経過時間をミリ秒で取得
const elapsedTime = Date.now() - myBirthDayTime;

特定の日時から特定の日時までの経過時間を取得する

ある日時から、ある日時までの経過時間を取得したいときは、各々のDateオブジェクトを作成してタイムスタンプを取得し、引き算します。


// 起点となる日時のタイムスタンプを取得
const  myBirthDayTime = new Date("2010/4/1").getTime();

// 経過後となる日時のタイムスタンプを取得
const  myBirthDayTime = new Date("2020/4/1").getTime();

// 現在までの経過時間をミリ秒で取得
const elapsedTime = myBirthDayTime - myBirthDayTime;

 

タイムスタンプを年・月・日・時・分・秒に変換する

タイムスタンプを見ただけでは実際の経過時間がわかりにくいので、わかりやすい形に加工する必要があります。

一つの案として、次のような方法があります。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

const timeString = `${timeStamp.getFullYear() - 1970 }${timeStamp.getMonth() } か月 ${timeStamp.getDate() -1 } 日経過`;

上の例は、経過時間からDateオブジェクトを作成することで、1970年1月1日0時0分0秒からのカレンダー上の日時に変換しています。

しかし、getFullYear() などのメソッドはうるう年が考慮されるのですが、1970年からの積み重ねとなるため、実際の経過年数とは異なってしまいます。この方法は、正確な経過年数を知りたい場合は使用しない方がよさそうです。

getHours()などのメソッドは、次のページを読んでみてください。
【JavaScript】 今日の日付を取得・表示するサンプルコード

ちなみに` `は、テンプレートリテラルです。

では、常套手段としての経過時間変換をいくつか挙げてみます。

なお、ここで定義されている関数において、引数で与えられた値の妥当性チェックなどはおこなっていません。
必要に応じて追加してください。

経過秒を表示する

これは簡単ですね。
タイムスタンプを1000で割れば秒に変換できます。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

 // タイムスタンプ(ミリ秒)を秒に変換
const elapsedSeconds = Math.floor( timeStamp / 1000 );

console.log( elapsedSeconds );

経過分を表示する

タイムスタンプを 1000(ミリ秒) × 60(秒) = 60000 で割れば分に変換できます。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

 // タイムスタンプ(ミリ秒)を分に変換
const elapsedMinutes  = Math.floor( timeStamp / 60000 );

console.log( elapsedMinutes );

経過時間を表示する

タイムスタンプを 1000(ミリ秒) × 60(秒) × 60(分) = 3600000 で割れば時間に変換できます。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

 // タイムスタンプ(ミリ秒)を時間に変換
const elapsedHour  = Math.floor( timeStamp / 3600000 );

console.log( elapsedHour );

経過日数を表示する

タイムスタンプを 1000(ミリ秒) × 60(秒) × 60(分) × 24(時間) = 86400000 で割れば日数に変換できます。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

 // タイムスタンプ(ミリ秒)を日数に変換
const elapsedDay  = Math.floor( timeStamp / 86400000 );

console.log( elapsedDay );

経過月数を表示する

経過月数は月数の定義をどうすかで算出方法が変わってきます。

平均日数で計算する

まずは常套手段は、一年365日を12で割った値をひと月の日数として計算する方法です。


  // ひと月の日数を求める
const daysMonth = 365 /12;

const timeStamp = Date.now() - new Date("2010/4/1").getTime();

 // タイムスタンプ(ミリ秒)を月数に変換
const elapsedMonths   = Math.floor( timeStamp / ( 86400000 * daysMonth ));

console.log( elapsedMonths );

カレンダー上での月数で計算する

カレンダー上での経過月数を求めたいときは、これまでのタイムスタンプは使用せずにDateオブジェクトのメソッドを使用します。


const startTime = new Date("1970/4/1");

const calcElapsedMonth = ( s , e )=>e.getFullYear() === s.getFullYear() 
            ? e.getMonth() - s.getMonth()
            : (e.getFullYear() - s.getFullYear() -1 ) * 12
                + ( 12 - s.getMonth() - 1 ) + ( e.getMonth() + 1 );

console.log( calcElapsedMonth( startTime , new Date() ) ); // 480

elapsedMonth関数に与えられた引数が同じ年なら、月を引き算します。
異なるなら、開始と終了を含まない年数に12を掛けて、終了年の月数と開始年の12月までの月数を足します。

この関数は、開始月の日数を切り捨てて、終了月は無条件に一か月経過としています。
つまり開始日が月の最初の日でもその月は経過月に含まれません。
その逆で、終了日が最初の日でも経過月に含まれます。

そこで、端数の日数も算出してみます。


const startTime = new Date("1970/4/1");

const calcElapsedMonth = ( s , e )=>e.getFullYear() === s.getFullYear()
            ? calcElapsedDaySameYear( s , e )
            : [ (e.getFullYear() - s.getFullYear() -1 ) * 12
                + ( 12 - s.getMonth() -1 ) + ( e.getMonth() ) ,
                getLastDay(s) - s.getDate() + e.getDate()
            ];

  // 月の最終日を求める
const getLastDay = time => [31,30,29,28].find(
        e => new Date(new Date( time ).setDate(e)).getMonth() === time.getMonth()
);

 // 開始と終了の年と月が同じとき、[ 月数 , 端数の日数 ]を返す
const calcElapsedDaySameYear  = ( s , e ) =>s.getMonth() === e.getMonth()
            ? [0 , e.getDate() - s.getDate() ]
            : [ e.getMonth() - s.getMonth() -1 , getLastDay(s) - s.getDate() + e.getDate()];

const [month,day] = calcElapsedMonth( startTime , new Date() );
console.log(  `${ month }か月${ day }日経過`);

初月の日数を求めるために、月の最終日を求めています。
こちらについては別記事で紹介しているので、参考にしてみてください。
【JavaScript】月の最終日を求める

半端な日数を取得できましたが、ここで大きな問題があります。
期間によっては半端な日数が60日など、ひと月を大きく超えるケースが考えられます。

30日でひと月にするのか、そのまま気にせず日数表示するのか、この点は実装する側で判断する必要があります。

なお実際に同等の処理を組み込む場合は、初日初月および末日末月の扱い方をしっかりと定義する必要があります。定義によってはこのコードが使用できないこともあります。

経過年数を表示する

経過年数も月と同様に、年数の定義をどうすかで算出方法が変わってきます。

平均日数で計算する

一年を365日として年数計算する方法です。


const timeStamp = Date.now() - new Date("2010/4/1").getTime();

// タイムスタンプ(ミリ秒)を年数に変換
const elapsedYears   = Math.floor( timeStamp / ( 86400000 * 365 ));

console.log( elapsedYears );

カレンダー上での年数で計算する

うるう年は366日になるため、上のコードでは誤差がでます。
そこで今度は、カレンダー上での年数で計算してみます。

月数でのケースと同じように、タイムスタンプは使用せずにDateオブジェクトのメソッドを使用します。


const startTime = new Date("1970/4/1");

const calcElapsedYear = ( s , e )=>e.getFullYear() === s.getFullYear()
    ? 0
    : (e.getFullYear() - s.getFullYear() -1 )
    + ( (( 12 - s.getMonth()  ) + ( e.getMonth() + 1 ) >= 13 ) ? 1 : 0);

console.log( calcElapsedYear( startTime , new Date() ) ); // 40

開始と終了が同じ年度なら年数は0になります。
異なるなら、終了年の月数と開始年の12月までの月数を足し、13以上ならば一年とします。
その値に、開始と終了を含まない年数を足しています。

13以上を一年としたのは、経過月数と同様に、開始月を含んでいないからです。

関連記事:
【JavaScript】 生年月日から年齢を求めるいくつかの方法

 

経過日数を年月日で表示する

最後に、経過日数を『●年●か月●日経過』という形式で表示します。

こちらは異なる二つの方法を挙げてみます。

平均的な日数を年月に当てはめて求める

これまで紹介してきたタイムスタンプを年月日に変換する方法を使用して、経過年月日を取得してみます。


const daysMonth = 365 /12;
const daysYear = 365;

const timeStamp = Date.now() - new Date("2019/4/12").getTime();

  // タイムスタンプ(ミリ秒)を日数に変換
let elapsedDay  = Math.floor( timeStamp / 86400000 );

  // 経過年数を計算
const elapsedYear =  Math.floor( elapsedDay / daysYear );
  // 日数から年に相当する日数を減算
eapsedDay -= eapsedYear * 365;
  // 経過月数を計算
const elapsedMonth = Math.floor( elapsedDay / daysMonth );
  // 日数から月に相当する日数を減算
elapsedDay -= Math.floor(elapsedMonth * daysMonth);

console.log( `${elapsedYear}${elapsedMonth}か月 ${elapsedDay}日経過` );

このコードは計算する順番が重要です。

まず期間中の総日数を取得します。
次に総日数から年数を計算し、総日数から年に相当する日数を減算します。
次に減算された日数から月数を計算し、総日数から月に相当する日数を減算します。

これで経過年月日を取得できます。

カレンダー上での経過年月日数で表示する

カレンダー上での経過年月日数を取得してみます。


const startTime = new Date("2019/4/12");

const calcElapsedMonth = ( s , e )=>e.getFullYear() === s.getFullYear()
    ? calcElapsedDaySameYear( s , e )
    : [ (e.getFullYear() - s.getFullYear() -1 ) * 12
    + ( 12 - s.getMonth() -1 ) + ( e.getMonth() ) ,
        getLastDay(s) - s.getDate() + e.getDate()
    ];

// 月の最終日を求める
const getLastDay = time => [31,30,29,28].find(
    e => new Date(new Date( time ).setDate(e)).getMonth() === time.getMonth()
);

// 開始と終了の年と月が同じとき、[ 月数 , 端数の日数 ]を返す
const calcElapsedDaySameYear  = ( s , e ) =>s.getMonth() === e.getMonth()
    ? [0 , e.getDate() - s.getDate() ]
    : [ e.getMonth() - s.getMonth() -1 , getLastDay(s) - s.getDate() + e.getDate()];

const [months,elapsedDay] = calcElapsedMonth( startTime , new Date() );

  // 年数を求める
const elapsedYear = Math.floor( months / 12 );
  // 月数を求める
const elapsedMonth = Math.floor( months % 12 );

console.log( `${elapsedYear}${elapsedMonth}か月 ${elapsedDay}日経過` );

異なるのは最後の3行のみで、ほぼ、経過月数表示のカレンダー上での月数で計算するで紹介したコードと同じです。

上記のリンク先で言及していますが、経過日数が31日を超えることがあります。
理由はリンク先を確認してみてください。

更新日:2023/04/11

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。