node.jsやReact Nativeで時間を扱う場合は標準のDateオブジェクトでは扱い辛いので痒いところに手が届くMoment.jsをよく利用しています。実際の開発では、APIから受け取ったJSONで、
{
"articles": [
{
...
"publishedAt": "2018-11-30T08:06:19.000+09:00"
},
{
...
},
...
}
のようにISO 8601の文字列の形式で受けとって扱っています。その際、一覧を時間でソートしたいと考えるケースは多いと思いますのでここからmomentを利用するとどんな感じになるかを紹介したいと思います。
目次
スポンサーリンク
momentで文字列をパースする(moment(str))
先ずは文字列パースしないと始まりません。momentは標準でISO 8601をサポートしていますので文字列を直接指定すればmomentオブジェクトにパース可能です。
moment("2018-11-30T08:06:19.000+09:00")
タイムゾーンを省略すればローカル時間として解釈します
moment("2018-11-30T08:06:19")
電子メールで利用するRFC1123の日付形式を利用したい場合はDateオブジェクトを一旦介すとパース出来ます
moment(new Date("Thu, 04 Oct 2014 23:59:45 GMT"))
moment(new Date("Thu, 04 Apr 2014 12:35:20 +0900"))
その他、日付だけ等、規定のフォーマットとならない文字列の場合は時刻フォーマットを自分で定義してください
moment("2018年11月30日", "YYYY年MM月DD日")
momentで時刻の差分を取る(moment.diff)
momentで差分を取るにはdiff
関数を用います。
> moment("2018-11-30 10:00").diff(moment("2018-11-30 09:00"))
3600000
デフォルトの単位はms
です。単位は指定することが出来ます。
> moment("2018-11-30 10:00").diff("2018-11-30 09:00", "minute")
60
ISO8601形式であればdiff引数には直接文字列を指定することが出来ます。
> moment("2018-11-30 10:00").diff("2018-11-30 09:00")
3600000
残念ながらdiffは引数でフォーマットは指定出来ませんので必要があればmomentでパースしてください
> moment("2018年12月1日", "YYYY年MM月DD日").
... diff(moment("2018年11月30日", "YYYY年MM月DD日"), "day")
1
momentオブジェクトの差分は引き算でも可能で、比較演算子も使えます。
> const a = moment("2018-11-30 10:00")
> const b = moment("2018-11-30 09:00")
> a - b
3600000
> a.diff(b)
3600000
> a > b
true
時間文字列からmomentを利用してソートする(Array.sort)
momentで大小を評価出来る様になったので後はsort
関数を用いればソート出来ます
> ["2018-11-30 09:00", "2018-12-01 12:00", "2018-11-30 08:00"].
... sort((a, b) => moment(a).diff(b))
[ '2018-11-30 08:00', '2018-11-30 09:00', '2018-12-01 12:00' ]
sort
はa - b
を評価すると昇順になります。降順はb - a
としてください。
冒頭のJSON例で最新順に記事一覧をソートしたいとなると以下の様なコードになります。
const newerSortedArticles = articles.sort((a, b) => moment(b.publishedAt).diff(a.publishedAt));
(応用)momentで指定文字列が当日かどうかを判定する
実際に実装してみてちょっと躓いた例なので紹介しておきます。
momentでパースするとJSを実行したクライアント側のタイムゾーンになっているので注意
momentは特に指定しないとパースした後のオブジェクトは実行しているシステム設定のタイムゾーンで表記されます。
APIから取得した時刻文字列が例えばUTCだった場合等で、実際に表示される時間と文字列に表示されている時間がずれる場合があります。
> moment("2018-11-30T23:00:00Z").format()
'2018-12-01T08:00:00+09:00'
> moment('2018/11/30').utcOffset('+00:00').format()
'2018-11-29T15:00:00Z' // 日本時間の日付だがクライアントの地域がイギリスだった場合は日付がずれる
当日を判定したい場合はタイムゾーンを指定するのが無難
コードが実行されるのがサーバー側で利用するタイムゾーンが東京固定などの場合は問題ありませんが、React Native等で実際に判定するのはクライアント側の場合といった場合はタイムゾーン(utcOffset)を指定しておくことをおすすめします。
それを踏まえて、日本時間で指定された日付が当日かを判定するコードは以下になります
> const now = moment();
> // trueを指定して時間をずらさずタイムゾーンのみ設定
> const targetDate = moment('2018年11月30日', 'YYYY年MM月DD日').utcOffset('+09:00', true);
> // startOf(), endOf()指定時にutcOffset指定していないと対象地域の当日時間からずれる
> targetDate.startOf('day') <= now && now <= targetDate.endOf('day')
true
momentは便利なので上手く活用しましょう:)