日付を処理するフィルタを登録する

Nuxt.js
公開日:
更新日:

ISO 8601 書式の日時を表す文字列(2021-01-23T12:34:56.789Z など)は、Date.parse() を使ってタイムスタンプに変換できます。

日付として不正な場合は NaN が返されるので、Date インスタンスを作る前に判別することができます。new Date() に直に不正な値を渡すと Invalid Date となってしまいます。

Date を使うフィルターを登録する

Date.parse() の結果が NaN でなければ、new Date() で Date に変換します。Date.parse() の返り値は数値であり、NaN は何と比較しても false になるので、!== で比較することで、NaN であるかどうかを判別できます。

// plugins/filters.js
import Vue from 'vue'

Vue.filter('dateYnjHi'dateStr => {
  const timestamp = Date.parse(dateStr)
  if (timestamp !== timestamp /* isNaN */return ''

  const d = new Date(timestamp)
  return `${d.getFullYear()}${d.getMonth() + 1}${d.getDate()}日 ${d.getHours()}:${('0' + d.getMinutes()).slice(-2)}`
})

JavaScript の Date の注意点として、getMonth() メソッドで得られる月は 0 から数えます。実際の月を表示する際は 1 を足します。

また、getMinutes()getSeconds() など、get で始まるメソッドはすべて数値を返すので、2桁に固定したい場合は、文字列の '0' に足してから slice(-2) するなどします。

// getMinutes() が 2 の場合
('0' + 2) // => '02'
'02'.slice(-2) // => '02'

// getMinutes() が 23 の場合
('0' + 23) // => '023'
'023'.slice(-2) // => '23'

フィルタが書けたら、nuxt.config.js の plugins プロパティに追加します。

// nuxt.config.js
export default {
  //...
  plugins: [
    '~/plugins/filters.js',
  ],
  //...
}

Vue テンプレートで使うときは、Mustache の中でパイプを使って指定します。v-text では動きません。

<time :datetime="post.publishedAt">{{ post.publishedAt | dateYnjHi }}</time>

Intl.DateTimeFormat を使う

Intl.DateTimeFormat を使うと、タイムスタンプや Date オブジェクトを言語に応じた書式に変換することができます。

const timestamp = Date.parse('2021-12-31T15:00:00.000Z')
const dateFormat = new Intl.DateTimeFormat('ja-JP', {
  year: 'numeric', // 年の表現。'2-digit' => 22(下二桁のみ)
  month: '2-digit', day: '2-digit',
  weekday: 'short', // 曜日の表現。'long' => 土曜日
  hour12: false, // 12時間表示か。true => 午前0:00
  hour: 'numeric', minute: '2-digit',
})
dateFormat.format(timestamp) // => 2022/01/01(土) 0:00

こちらは日付単位ではなく、フォーマット単位でインスタンスを作成するので、アプリケーション全体で日付のフォーマットが同じであれば、一つのインスタンスを使い回せます。また、月が 0 から始まるなどのややこしい問題も起こりません。

欠点としては、フォーマット結果が実装依存となってしまうことです。上記のオプションであれば Chrome, Firefox, Safari, Edge で同じ結果が得られるのを確認しています。IE 11 では、weekday'short', 'narrow' どちらも括弧なしの表示になってしまうようです。

関数として共通化する

最新の Vue 3 では、パイプを使ってフィルタを指定する独自の構文を排するため、フィルタ機能は削除されています。Nuxt.js は Vue 2 を使用しているためフィルタ機能は使えますが、移行しやすさのため Nuxt.js の inject 機能を使って共通化してみます。

// plugins/formatDate.js
// export 外で定義すると nuxt generate でも使い回せる
const dateFormat = new Intl.DateTimeFormat('ja-JP', {
  year: 'numeric', month: '2-digit', day: '2-digit', weekday: 'short',
  hour12: false, hour: 'numeric', minute: '2-digit',
})

export default (_ctx, inject) => {
  inject('formatDate', dateStr => {
    const timestamp = Date.parse(dateStr)
    return timestamp !== timestamp /* isNaN */
      ? ''
      : dateFormat.format(timestamp)
  })
}

nuxt.config.js でプラグインを登録します。

// nuxt.config.js
export default {
  //...
  plugins: [
    '~/plugins/formatDate.js',
  ],
  //...
}

テンプレート内では、$formatDate() を呼び出して使います。Mustache でも v-text でも使えます。

<time :datetime="post.publishedAt">{{ $formatDate(post.publishedAt) }}</time>
<time :datetime="post.revisedAt" v-text="$formatDate(post.revisedAt)"></time>