日付を処理するフィルタを登録する
- 公開日:
- 更新日:
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>