【JavaScript】Dateの比較方法を初心者向けにわかりやすく解説

はじめに

JavaScriptで日付や時間を扱う場面は、Webアプリケーションの開発をしていると非常に多くなります。
たとえば、ある日付が別の日付よりも前か後かを判定したり、締め切りが過ぎているかどうかを確認したりするケースは、実務でも頻繁に登場するでしょう。
しかし、初心者の方が初めてJavaScriptのDateオブジェクトや日付比較の仕組みに触れるとき、意外と操作が複雑に感じることがあります。

日付操作にはさまざまな概念が絡み合います。
たとえば、時差(タイムゾーン)の扱いや、夏時間(サマータイム)がある地域ではどうなるのかといった問題もあって、単純に「文字列を比較すればOK」というわけにはいきません。
正しい比較方法を身につけておかないと、システム上で誤ったロジックによる不具合が起きる可能性もあります。

そこで本記事では、JavaScriptにおけるDateオブジェクトの比較方法に焦点を当てて解説します。
実務でよくあるシチュエーションを例に取りながら、どのように実装すれば正しく比較ができるのかをわかりやすくご紹介します。
初心者の方でも理解しやすいように、ひとつひとつのステップを丁寧に紹介していきますので、ぜひ最後まで読んでみてください。

この記事を読むとわかること

  • JavaScriptのDateオブジェクトに関する基礎知識
  • Dateオブジェクト同士の比較getTime()メソッドを使った比較の方法
  • 日付比較が実務でどのように活用されるか、具体的なシチュエーション
  • 日付操作ライブラリを用いた、より便利な比較方法
  • タイムゾーンやサマータイムなどで注意したいポイント

ここから、JavaScriptで日付を比較するための基本的な考え方や、実際のコード例をいくつか確認していきます。
コードを読むだけでなく、実際に手を動かして理解を深めていただければと思います。

日付と時間の基本概念

JavaScriptで日付や時間を扱う前に、まずは日付と時間そのものがどういうものなのかを簡単に振り返っておきましょう。
といっても難しい話ではありません。
たとえば年・月・日・時・分・秒などが基本となる項目ですね。

しかし「現在日時を取得する」というシンプルな作業だけを考えていても、意外と奥が深いのです。
たとえば、ある国・地域の時刻をそのまま記録してしまうと、別の国・地域からアクセスする人がいるときに、見た目の時刻が異なってしまいます。
こうしたズレをどう補正するかが、アプリケーション開発では非常に重要になります。

JavaScriptにおけるDateオブジェクト

JavaScriptでは、日付や時間を扱うためにDateオブジェクトが用意されています。
new Date() と書くだけで、現在の日時を表すオブジェクトを生成できます。

const now = new Date();
console.log(now); // 現在の日時が表示される

このとき、Dateオブジェクトは内部的には「協定世界時(UTC)」という共通の基準時間からの経過ミリ秒をもとに管理されており、表示の際に利用している環境のタイムゾーンに合わせて変換されます。
JavaScriptでDateを扱うときは、最初に「実際には内部的にUTCの値を持っているんだ」というイメージを押さえておくと理解しやすくなるかもしれません。

実務で遭遇しがちなシチュエーション

実務では、日付や時間を比較する場面が多々あります。
たとえば以下のような例です。

期限切れ判定

会員登録後30日を過ぎているかどうかを調べる

スケジュール管理

イベントの開始日時と現在時刻を比較して、まだ開催前か、すでに終了したかを判定する

ログのソート

ログの記録日時を比較して、新しい順や古い順に並べる

定期的なタスクの実行

ある時間帯に達していれば処理を走らせるかどうかを決める

これらの場面では、単純に「どちらが大きいか、小さいか」を比較したいだけのことが多いです。
しかし、先ほども触れたタイムゾーンの問題や、Dateオブジェクトの作り方によっては予期せぬズレが生じる可能性があるため、正しい方法を理解しておきましょう。

JavaScriptでのDate比較方法

ここからは具体的に、JavaScriptでDateオブジェクトを比較するときの方法を見ていきます。
結論としては、ほとんどの場合において数値として比較できる形にしてから、大小を判定するというやり方が安全でわかりやすいです。
つまり、Dateオブジェクト同士をそのまま比較するよりも、getTime()valueOf()といったメソッドを使って、ミリ秒単位の数値に変換してから比較するのが一般的です。

シンプルな比較方法

実はJavaScriptのDateオブジェクト同士を比較するとき、演算子 <> でも直接比較することはできます。
たとえば次のようなコードで、古い日付が新しい日付よりも小さいと判定することが可能です。

const dateA = new Date('2023-01-01T00:00:00Z');
const dateB = new Date('2023-01-02T00:00:00Z');

// これはtrueになる
console.log(dateA < dateB);

このコードでも意図どおりに大小を判定できます。
実は、Dateオブジェクト同士を比較演算子で比べると、内部的には自動的にミリ秒(数値)に変換されて比較されます。

それなら一見、dateA < dateB で十分じゃないかと思うかもしれません。
確かに単純なケースではこれでも構いませんが、可読性の面で、あらためて数値として比較したほうがわかりやすいという場面が出てくることがよくあります。
特に、数値として厳密に差分を計算したり、ログに出力する情報として「何ミリ秒の差があるか」を知りたい場合などは、getTime()を利用しておくと安心です。

getTime()を使った比較

getTime()は、Dateオブジェクトが表す日時をUTCの1970年1月1日 00:00:00 から数えて何ミリ秒経過しているかを返します。
このメソッドを使って数値を取得すれば、以下のように単純な比較ができます。

const dateA = new Date('2023-01-01T00:00:00Z');
const dateB = new Date('2023-01-02T00:00:00Z');

const timeA = dateA.getTime();
const timeB = dateB.getTime();

// timeAとtimeBはそれぞれミリ秒の数値
if (timeA < timeB) {
  console.log('dateAはdateBよりも前の日時です');
} else {
  console.log('dateAはdateBと同じ日時か、後の日時です');
}

こうすると、「Dateオブジェクト同士を比較している」というよりは、数値同士を比較している」という形になるため、コードを読んだときに意図がはっきりします。
意図的に数値化して比較していることがわかりやすいので、複数の人が関わる開発現場などでは、この方法をよく見かけるかもしれません。

日時の大小比較のコード例

実際の開発でよくあるのは、複数の日時を並べて「一番古いもの」「一番新しいもの」を探すケースでしょう。
たとえば下記のように、配列に格納されたDateオブジェクトをソートして、新しい順や古い順に並べ替えるといった実装が考えられます。

const dates = [
  new Date('2023-05-01T10:00:00'),
  new Date('2023-03-15T15:30:00'),
  new Date('2023-03-15T15:30:00Z'),
  new Date('2023-04-20T12:00:00')
];

// getTime() で比較しながらソート
dates.sort((a, b) => a.getTime() - b.getTime());

// 結果として古い順に並ぶ
dates.forEach(d => {
  console.log(d.toISOString());
});

上記のコードでは、比較用の関数として (a, b) => a.getTime() - b.getTime() を指定しているため、古い日時から順番に整列されます。
もちろん、b.getTime() - a.getTime() にすれば、新しい日時から並べることも簡単です。

なお、このときに気をつけたいのが、日付文字列を '2023-03-15T15:30:00' のように書いた場合、タイムゾーンが省略されると実行環境によってはローカル時間と見なされる場合があることです。
一方 '2023-03-15T15:30:00Z' と書くと、UTCとして解釈されます。
もし意図した時刻と異なる可能性があるなら、タイムゾーンまで明示しておくと安全でしょう。

Date関連の実践的な活用シーン

ここでは、もう少し踏み込んで、実務でどういった形でDate比較が使われるのかを具体的に見ていきましょう。
単に大小比較をするだけでなく、実際に活用するときはどんなポイントを押さえておくとよいのか、いくつかのケースを紹介します。

期限切れチェックの実装

ユーザーが登録してから一定期間を過ぎたらアカウントを停止する、あるいはサンプル版の利用期限が過ぎたら機能をロックする、といった仕組みは、さまざまなアプリケーションに存在します。

たとえば次のようなコードで、特定の日付を境に期限が切れているかどうかをチェックできます。

function isExpired(targetDate, limitDays) {
  // limitDays後の日時
  const limitTime = targetDate.getTime() + limitDays * 24 * 60 * 60 * 1000;
  const now = Date.now(); // 現在のミリ秒
  return now > limitTime;
}

// たとえば、ユーザーが登録した日をdateRegisteredとする
const dateRegistered = new Date('2023-01-01T00:00:00Z');
const expired = isExpired(dateRegistered, 30);

if (expired) {
  console.log('利用期限が切れています');
} else {
  console.log('まだ利用可能です');
}

この例では、特定の日時(dateRegistered)から指定した日数(limitDays)が経過したかどうかを判定しています。
Dateオブジェクトを直接比較するのではなく、やはり内部のミリ秒を取り出して計算することで、使い勝手がよくなっています。

ユーザー登録日からの経過日数の算出

別のケースとして、ユーザーがいつ登録したのかを保存しておき、現在時刻と比較して「何日経過しているか」を求める場面があります。
以下のようにすれば、ミリ秒単位での差分から日数を算出できます。

function daysSinceRegistration(registrationDate) {
  const now = Date.now();
  const diff = now - registrationDate.getTime();
  // 1日 = 24時間 = 86400000ミリ秒
  return Math.floor(diff / (24 * 60 * 60 * 1000));
}

const dateRegistered = new Date('2023-03-01T00:00:00Z');
const days = daysSinceRegistration(dateRegistered);

console.log(`登録から${days}日が経過しました`);

ここでは、1日が24時間であると仮定しています。
実際にはサマータイムが適用される地域などでは1日が24時間ではない日も生じる可能性がありますが、汎用的に使う分にはこれで問題ない場合が多いでしょう。
もしサマータイムなども考慮したい場合には、タイムゾーンの取り扱いを含む別途のロジックが必要になります。

スケジュール管理機能での比較

あるイベントや会議が何時何分に開催されるかを管理する場面でも、Dateオブジェクトの比較は頻繁に使われます。
とくに複数のイベントを時系列順に並べ替えるときには、先ほど紹介した.sort()を活用する方法が大いに役立つでしょう。

const events = [
  { title: '朝会', time: new Date('2023-04-10T09:00:00') },
  { title: 'ランチミーティング', time: new Date('2023-04-10T12:30:00') },
  { title: '報告会', time: new Date('2023-04-10T17:00:00') }
];

// 今後のイベントだけをフィルタして、時刻の早い順にソート
const now = new Date();
const upcoming = events
  .filter(event => event.time.getTime() > now.getTime())
  .sort((a, b) => a.time.getTime() - b.time.getTime());

// upcomingに、これから先のイベントが時系列で格納される
upcoming.forEach(event => {
  console.log(`${event.time.toLocaleString()}: ${event.title}`);
});

このように、フィルタ→ソートという2段階の操作をしてあげるだけで、すぐに「これから開催されるイベントの一覧」を作ることができます。
実務では、イベント予定や会議のリマインダ、期日管理などで頻繁に登場する定番の実装パターンといえるでしょう。

日付操作ライブラリを使った比較

JavaScriptの標準のDateオブジェクトは基本的な機能をカバーしていますが、日付の加減算やフォーマット、タイムゾーンの取り扱いが複雑になる場合もあります。
そこで実務では、date-fnsDay.jsLuxon などのライブラリが活用されることも多いです。

こうしたライブラリを使うと、Dateの扱いに慣れていない方でも読みやすく、扱いやすい形にコードをまとめやすくなります。
いくつか代表的な例を見てみましょう。

date-fnsを使う

たとえばdate-fnsは、シンプルかつ関数型の構造でわかりやすい点が特徴です。
日付比較を行うためのヘルパー関数が複数用意されており、初心者にも使いやすいでしょう。

// date-fnsをインポートしていると仮定
import { isBefore, isAfter, differenceInDays } from 'date-fns';

const dateA = new Date('2023-05-01T00:00:00Z');
const dateB = new Date('2023-05-02T00:00:00Z');

console.log(isBefore(dateA, dateB)); // true
console.log(isAfter(dateB, dateA));  // true

// 日数差を求める
console.log(differenceInDays(dateB, dateA)); // 1

isBeforeisAfter は名前からして機能が明確であり、コードを読む人にも意図が伝わりやすいです。
differenceInDays のように、単に比較するだけでなく日数差を計算するための関数が整っているのも便利な点といえます。

LuxonやDay.jsの場合

他の例としてLuxonDay.jsを使う場合もあります。
これらのライブラリでは、Dateオブジェクトの代わりに独自のラッパーオブジェクトを生成し、そこにメソッドチェーンを通じて各種操作を加えていくスタイルが主流です。

// Day.js の例
import dayjs from 'dayjs';

const dateA = dayjs('2023-05-01T00:00:00Z');
const dateB = dayjs('2023-05-02T00:00:00Z');

// isBeforeやisAfterに相当するメソッド
console.log(dateA.isBefore(dateB)); // true
console.log(dateB.isAfter(dateA));  // true

// 差分を求める
console.log(dateB.diff(dateA, 'day')); // 1

dayjs()で生成したオブジェクトに対してisBeforeisAfterといったメソッドを呼び出せるため、可読性が高いと感じる人もいるでしょう。
さらに日時の加算・減算を簡単に行う関数なども豊富に用意されているため、複雑な日付計算が必要な現場では非常に重宝されています。

これらのライブラリを使うと、長期的にソースコードを保守しやすくなるケースがあります。 しかし、単純な比較処理だけなら標準のDateオブジェクトでも十分なことが多いのも事実です。

カレンダー操作や日付計算で気をつけること

ここまで紹介してきた方法で日付を比較できるようになれば、かなり多くの実装がカバーできます。
ただし、システム開発でカレンダー機能や国際化対応を行う場合などには、タイムゾーンサマータイムうるう秒など、もう少し踏み込んだ注意点が生じます。

タイムゾーンの考慮

たとえば、UTCと日本標準時(JST)だけで運用するならまだシンプルですが、ユーザーがアメリカなど複数の国からアクセスしてくることを想定すると、とたんに扱いが複雑になります。
タイムゾーンによって同じ日時でも表示される時刻が異なるので、「比較」自体はUTCで行いつつ、表示や入力はユーザーのタイムゾーンに合わせるといった方針を決めることが多いでしょう。

// ユーザーのタイムゾーンで表示する(例)
const userTimeString = new Date().toLocaleString('en-US', { timeZone: 'America/New_York' });
console.log(userTimeString);

JavaScriptの標準APIでもtoLocaleString()にオプションを渡すことで、特定のタイムゾーンでの表現を指定できます。
しかし実務では、多言語化・多地域対応を本格的に行うなら、やはり外部ライブラリを利用して制御するほうがベターでしょう。

システム開発での注意点

システム開発の実装では、DBへ保存する時刻はUTCに統一しておいて、ユーザーに見せるときだけタイムゾーン変換を行う、というやり方が一般的です。
この方法なら、日付同士を比較するときに「どのタイムゾーンを基準にするか」で混乱しにくくなります。
ローカルの時刻ではなく常にUTCの値(ミリ秒)で比較すれば、システム内部のロジックはシンプルに保てます。

一方で、「ユーザーが設定したタイムゾーンでアラームを出す」といった処理が必要な場合は、日時を取得してから必要に応じてローカル時刻に変換し、ユーザーの画面に表示するかどうかを判定するといった二段構えの実装になることがあります。
このあたりはプロジェクトやシステムの要件次第ですが、基本的には比較ロジックはUTC基準にしておくという方向は変わらないことが多いです。

タイムゾーンやサマータイムの概念を誤解していると、想定しない時刻のズレが発生しやすいです。 大規模な国際化システムでは、本番運用前に入念なテストを行うのが大切です。

まとめ

JavaScriptで日付を比較するときは、Dateオブジェクトを用いて手軽に実装できます。
特に、getTime()メソッドによるミリ秒単位の数値変換がシンプルかつわかりやすい方法です。

実務で多用される具体例としては、期限切れチェックやスケジュール管理などが挙げられます。
大半のケースでは「UTC基準で時刻を保持しておき、タイムゾーン変換は表示や入力の段階で対応する」という方針を採れば、システム全体をスッキリと保てるでしょう。

さらに、date-fnsDay.jsのようなライブラリを活用すれば、比較やフォーマット、加算・減算といった操作をより明快なコードで書けます。
標準APIだけで充分足りる場合もありますが、将来的に機能拡張が見込まれるなら、最初からライブラリの導入を検討するのも選択肢のひとつでしょう。

最後に、国際化対応やサマータイムのある地域との連携が必要なシステムでは、タイムゾーン周りのロジックが複雑になりがちです。
基本的なDate比較をしっかり押さえたうえで、必要に応じてタイムゾーンの設定やライブラリを活用していくことをおすすめします。

ここまで解説してきた内容を踏まえれば、JavaScriptにおける日付比較の基礎はばっちり理解できたのではないでしょうか。
ぜひ自分のプロジェクトや実習で、コードを書きながら確かめてみてください。

JavaScriptをマスターしよう

この記事で学んだJavaScriptの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。