「セール終了後にバナーを自動で消したい」「キャンペーン期間中だけお知らせを表示したい」「公開日を過ぎたら告知ブロックを非表示にしたい」——特定の日時を基準に要素の表示を切り替えるニーズは多くあります。
この記事では new Date() を使った日時比較の基本から、表示開始・終了の期間管理、複数要素への一括適用、タイムゾーン対応、CSS トランジションを使ったスムーズな切り替えまで体系的に解説します。
特定の日時を過ぎたら非表示にする基本実装
new Date() で現在の日時を取得し、目標日時と比較します。JavaScriptの Date オブジェクト同士は > / < で大小比較できます。
// 非表示にしたい期限(日本時間で指定)
const EXPIRE_DATE = new Date('2026-06-30T23:59:59+09:00');
const banner = document.getElementById('campaign-banner');
if (new Date() > EXPIRE_DATE) {
// 期限切れ → 非表示
banner.hidden = true;
} else {
// 期限内 → 表示
banner.hidden = false;
}
hidden 属性 vs display: none:el.hidden = true は display: none と同じ効果で、スクリーンリーダーにも読まれなくなります。アクセシビリティの観点では hidden 属性が推奨されます。CSSで hidden 属性を上書きしている場合は el.style.display = "none" を使うか、CSSの [hidden] { display: none !important; } を確認してください。HTMLに最初から hidden を付けておき、期限内のときだけ表示する書き方の方がより安全です(JavaScriptが無効でも非表示のままになるため)。
<!-- hidden 属性を最初から付けておく(JSが無効でも表示されない) --> <div id="campaign-banner" hidden> <p>夏のビッグセール開催中!</p> </div>
const EXPIRE_DATE = new Date('2026-06-30T23:59:59+09:00');
const banner = document.getElementById('campaign-banner');
// 期限内なら表示(hidden を外す)
if (new Date() <= EXPIRE_DATE) {
banner.hidden = false;
}
// 期限切れのときは何もしない(hidden のまま)
表示開始日時と終了日時の両方を管理する
「○月○日から○月○日まで表示する」という期間管理は、開始日時と終了日時の両方と現在時刻を比較するだけで実現できます。
const START_DATE = new Date('2026-07-01T00:00:00+09:00'); // 表示開始
const EXPIRE_DATE = new Date('2026-08-31T23:59:59+09:00'); // 表示終了
/**
* 要素を期間に応じて表示/非表示にする
* @param {Element} el - 対象要素
* @param {Date} start - 表示開始日時
* @param {Date} end - 表示終了日時
*/
function applySchedule(el, start, end) {
const now = new Date();
const isActive = now >= start && now <= end;
el.hidden = !isActive;
}
applySchedule(
document.getElementById('summer-campaign'),
START_DATE,
EXPIRE_DATE,
);
| 条件 | 現在時刻 | 表示状態 |
|---|---|---|
| 表示前 | now < start |
非表示 |
| 期間内 | start <= now <= end |
表示 |
| 期限切れ | now > end |
非表示 |
タイムゾーン対応:日本時間で期限を確実に指定する
サーバーやユーザーの端末のタイムゾーンに関わらず「日本時間の○月○日23:59」を正確に判定するには、ISO 8601 形式でオフセットを明示することが重要です。
// NG: タイムゾーン不明(実行環境のローカル時刻として解釈される)
const bad1 = new Date('2026-08-31 23:59:59'); // 環境依存
// NG: 日付のみの形式はUTC 00:00:00 として解釈される(JST = UTC+9 なので9時間ずれる)
const bad2 = new Date('2026-08-31'); // UTC 0:00 = JST 9:00 になる
// OK: +09:00 を明示することで日本標準時と確定する
const good = new Date('2026-08-31T23:59:59+09:00');
// OK: UTC で指定(JST 23:59 = UTC 14:59)
const utc = new Date('2026-08-31T14:59:59Z');
console.log(good.getTime() === utc.getTime()); // true(同じ瞬間)
ECMAScript の仕様では、日付のみの形式(
YYYY-MM-DD)は UTC の 00:00:00 として解釈されます。日本(UTC+9)からアクセスすると 9時間進んだ JST の 9:00 が「2026-08-31の開始時刻」になります。意図した時刻を正確に指定するには T00:00:00+09:00 のように時刻とオフセットを必ず付けてください。data属性でHTMLに期限を書いて一括管理する
複数の要素にそれぞれ異なる期限がある場合、JavaScript側に個別に書くより、HTML側の data 属性に期限を持たせて一括処理する方法が管理しやすくなります。
<!-- data-show-from / data-show-until に ISO 8601 形式で日時を書く -->
<div class="scheduled"
data-show-from="2026-07-01T00:00:00+09:00"
data-show-until="2026-08-31T23:59:59+09:00">
夏のキャンペーンバナー
</div>
<div class="scheduled"
data-show-until="2026-09-30T23:59:59+09:00">
秋の新作フェア(開始日時なし=即時表示)
</div>
<div class="scheduled"
data-show-from="2026-10-01T00:00:00+09:00">
冬の予告(終了日時なし=無期限表示)
</div>
function applyAllSchedules() {
const now = new Date();
document.querySelectorAll('.scheduled').forEach(el => {
const fromStr = el.dataset.showFrom;
const untilStr = el.dataset.showUntil;
const from = fromStr ? new Date(fromStr) : null;
const until = untilStr ? new Date(untilStr) : null;
const afterStart = !from || now >= from; // 開始日時前でなければOK
const beforeEnd = !until || now <= until; // 終了日時後でなければOK
el.hidden = !(afterStart && beforeEnd);
});
}
// ページ読み込み時に即時実行
applyAllSchedules();
- HTMLを見るだけで各要素の公開期間がわかる
- JavaScriptを触らずにCMS(WordPressなど)のエディタから期限を管理できる
- 新しい要素を追加するときも
class="scheduled"とdata属性を付けるだけ data-show-fromのみ(開始なし)・data-show-untilのみ(終了なし)どちらも対応可能
setInterval で定期チェックする(長時間ページを開いている場合)
ページを読み込んだ時点では期限内でも、同じページを数時間開き続けると期限切れになる場合があります。setInterval で定期チェックすることで、リロードなしに表示を切り替えられます。
// ページ読み込み時に即時実行
applyAllSchedules();
// その後は1分ごとに再チェック(ミリ秒単位: 60 * 1000 = 60000)
const intervalId = setInterval(() => {
applyAllSchedules();
// 全要素が期限切れになったらタイマーを止める
const hasActive = [...document.querySelectorAll('.scheduled')]
.some(el => !el.hidden);
if (!hasActive) {
clearInterval(intervalId);
}
}, 60_000); // 1分おき
毎秒チェックする必要はほとんどありません。「セールが終わる可能性がある」タイミングに合わせた間隔で十分です。1分おきならユーザー体験を損なわず、CPUへの負荷も最小です。ページが非アクティブなときは
visibilitychange と組み合わせてタイマーを一時停止するとさらに効率的です。CSSトランジションでスムーズに表示・非表示を切り替える
突然消えるのではなくフェードアウトで消したい場合、hidden 属性だけでは使えません。opacity と transition を組み合わせます。
.scheduled {
transition: opacity 0.5s ease;
}
.scheduled.is-hidden {
opacity: 0;
pointer-events: none; /* クリックも無効化 */
}
/* 完全に非表示にするときは transition 終了後に hidden を付ける */
/**
* フェードアウトして非表示にする
* @param {Element} el
* @param {number} durationMs - トランジション時間(CSS と合わせる)
*/
function fadeHide(el, durationMs = 500) {
el.classList.add('is-hidden');
// トランジション完了後に hidden 属性を付ける
setTimeout(() => {
el.hidden = true;
el.classList.remove('is-hidden'); // 次回表示時のために除去
}, durationMs);
}
// 使用例
const EXPIRE_DATE = new Date('2026-06-30T23:59:59+09:00');
const banner = document.getElementById('campaign-banner');
if (new Date() > EXPIRE_DATE) {
fadeHide(banner);
}
完成形:ScheduledDisplay クラス
これまでの実装をまとめた汎用クラスです。data属性での期間管理・定期チェック・フェード対応を含みます。
class ScheduledDisplay {
#intervalId = null;
#selector;
#checkIntervalMs;
/**
* @param {string} selector - 対象要素のCSSセレクタ
* @param {number} checkIntervalMs - 定期チェックの間隔(ms)。0で無効
*/
constructor(selector = '.scheduled', checkIntervalMs = 60_000) {
this.#selector = selector;
this.#checkIntervalMs = checkIntervalMs;
this.#apply();
if (checkIntervalMs > 0) {
this.#startInterval();
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.#stopInterval();
} else {
this.#apply();
this.#startInterval();
}
});
}
}
#apply() {
const now = new Date();
document.querySelectorAll(this.#selector).forEach(el => {
const from = el.dataset.showFrom ? new Date(el.dataset.showFrom) : null;
const until = el.dataset.showUntil ? new Date(el.dataset.showUntil) : null;
const active = (!from || now >= from) && (!until || now <= until);
el.hidden = !active;
});
}
#startInterval() {
if (this.#intervalId) return;
this.#intervalId = setInterval(() => this.#apply(), this.#checkIntervalMs);
}
#stopInterval() {
clearInterval(this.#intervalId);
this.#intervalId = null;
}
/** タイマーを破棄する */
destroy() {
this.#stopInterval();
}
}
// 使用例
document.addEventListener('DOMContentLoaded', () => {
new ScheduledDisplay('.scheduled', 60_000); // 1分おきに再チェック
});
よくある質問(FAQ)
hidden 属性と display: none のどちらを使えばいいですか?hidden 属性が推奨されます。スクリーンリーダーにも読まれなくなり、DOMからも意味的に除外されます。ただし、CSSで [hidden] { display: block !important; } のような上書きをしているテーマやライブラリがある場合は style.display = "none" の方が確実です。hidden を付けておくことでJavaScriptが無効でも要素が非表示になります。セキュリティ上重要な非表示(管理者限定コンテンツなど)はサーバーサイドで出力制御してください。const isActive = new Date() <= expireDate; を状態として持ち {isActive && <Banner />} で条件レンダリングします。定期チェックには useEffect 内で setInterval を使い、クリーンアップ関数で clearInterval を呼びます。Vue 3 なら ref + watchEffect で同様に実装できます。data-show-until="" のように出力する方法が一般的です。この記事の ScheduledDisplay クラスと組み合わせることで、管理画面から期限を設定してJavaScriptで自動制御できます。まとめ
| 要件 | 実装ポイント |
|---|---|
| 期限切れで非表示 | new Date() > expireDate で比較、el.hidden = true |
| 期間内だけ表示 | 開始と終了の両方を比較(now >= from && now <= until) |
| 日本時間で期限指定 | +09:00 オフセット付きISO 8601 形式 |
| 複数要素を一括管理 | data-show-from / data-show-until 属性 + querySelectorAll |
| 長時間閲覧への対応 | setInterval で1分おきに再チェック |
| スムーズな切り替え | CSS opacity + transition でフェードアウト後に hidden |
日付の計算(日時の足し算・引き算)はJavaScriptで日時の計算をマスターしようを、セール終了までのカウントダウン表示を組み合わせたい場合はカウントダウンタイマーの作り方もあわせて参照してください。
