やりたいこと
Twitterのように、投稿日付を表示したい。「○分前」「○時間前」「○日前」など、現在時刻からの経過時間をざっくり表示したい。
date-fnsのformatDistanceToNowでできる
date-fnsのformatDistanceToNowを使えば、現在からのざっくりした経過時間を表示することができます。
date-fns - modern JavaScript date utility library
経過時間と表示される時間の対応は以下のようになります。
範囲 | 表示 |
---|---|
30秒未満 | 1分未満 |
30秒以上 1 分30 秒未満 | 1分 |
1分30秒以上 44分30秒未満 | [2..44]分 |
44分30秒以上 89分30秒未満 | 約1時間 |
89分30秒以上 23時間59分30秒未満 | 約[2..24]時間 |
23時間59分30秒以上 41時間59分30秒未満 | 1日 |
41時間59分30秒以上 29日23時間59分30秒未満 | [2..30]日 |
29日23時間59分30秒以上 44日23時間59分30秒未満 | 約1か月 |
44日23時間59分30秒以上 59日23時間59分30秒未満 | 約2か月 |
59日23時間59分30秒以上 1年未満 | [2..12]か月 |
1年以上 1年3か月未満 | 約1年 |
1年3か月以上 1年9か月未満 | 1年以上 |
1年9か月以上 2年未満 | 2年近く |
N年以上 N年3か月未満 | 約N年 |
N年3か月以上 N年9か月未満 | N年以上 |
N年9か月以上 N+1年未満 | N+1年近く |
プログラム例
実際に使用してみます。Reactを使用しています。
import React from 'react'; import formatISO9075 from 'date-fns/formatISO9075' import formatDistanceToNow from 'date-fns/formatDistanceToNow' import { ja } from 'date-fns/locale' function App() { const targetDate = new Date(2019, 11, 8, 10, 13) return ( <div> <div>現在時刻: {formatISO9075(new Date())}</div> <div>対象時間: {formatISO9075(targetDate)}</div> <div>経過時間: {formatDistanceToNow(targetDate, {locale: ja})}</div> </div> ); } export default App;
実行結果です。経過時間が表示されました。(実際にはスタイルを適用しています。)
色々な経過時間での表示を確かめる
色々な経過時間で実際に表示時間を確かめてみました。
デフォルトの設定では、"○分"、"約○時間"のように現在からの差分がどのくらいか表示されます。今回は、optionにaddSuffix: true
を指定して、"○分前"、"約○時間後"と、"前"または"後"を後ろにつけるようにしました。
現在時刻が2019-12-08 22:23:56
のとき
説明 | 日時 | formatDistanceToNow(date, {addSuffix: true, locale: ja}) |
---|---|---|
3秒前 | 2019-12-08 22:23:53 | 約1分前 |
40秒前 | 2019-12-08 22:23:16 | 1分前 |
1分20秒前 | 2019-12-08 22:22:36 | 1分前 |
4分50秒前 | 2019-12-08 22:19:06 | 5分前 |
17分25秒前 | 2019-12-08 22:06:31 | 17分前 |
47分4秒前 | 2019-12-08 21:36:52 | 約1時間前 |
1時間25分56秒前 | 2019-12-08 20:58:00 | 約1時間前 |
1時間37分12秒前 | 2019-12-08 20:46:44 | 約2時間前 |
10時間5分32秒前 | 2019-12-08 12:18:24 | 約10時間前 |
23時間50分15秒前 | 2019-12-07 22:33:41 | 約24時間前 |
1日5分52秒前 | 2019-12-07 22:18:04 | 1日前 |
1日17時間2分47秒前 | 2019-12-07 05:21:09 | 1日前 |
1日18時間11分30秒前 | 2019-12-07 04:12:26 | 2日前 |
3日2時間45分7秒前 | 2019-12-05 19:38:49 | 3日前 |
12日20時間36分3秒前 | 2019-11-26 01:47:53 | 13日前 |
29日10時間46分51秒前 | 2019-11-09 11:37:05 | 29日前 |
30日1時間29分1秒前 | 2019-11-08 20:54:55 | 約1か月前 |
50日6時間27分48秒前 | 2019-10-19 15:56:08 | 約2か月前 |
63日22時間1分55秒前 | 2019-10-06 00:22:01 | 2か月前 |
120日19時間4分6秒前 | 2019-08-10 03:19:50 | 4か月前 |
361日9時間22分29秒前 | 2018-12-12 13:01:27 | 12か月前 |
1年10日15時間32分15秒前 | 2018-11-28 06:51:41 | 約1年前 |
1年120日14時間44分20秒前 | 2018-08-10 07:39:36 | 1年以上前 |
1年300日12時間3分30秒前 | 2018-02-11 10:20:26 | 2年近く前 |
3年36日2時間22分45秒前 | 2016-11-02 20:01:11 | 約3年前 |
3年170日5時間38分33秒前 | 2016-06-21 16:45:23 | 3年以上前 |
3年290日2時間39分10秒前 | 2016-02-22 19:44:46 | 4年近く前 |
10年150日13時間4分2秒前 | 2009-07-11 09:19:54 | 10年以上前 |
30秒未満の場合、suffix("前"や"後")をつけないと、"1分未満"と表示されますが、suffixをつけると"約1分前"になります。"1分未満前"にならないところに細かい気遣いがあります。(ソースコードはこちら→ date-fns/index.js at master · date-fns/date-fns · GitHub )
ソースコード
上記の表を出力するコードです。Reactを使用しています。
# date-fnsのインストール
$ yarn add date-fns
import React from 'react'; import formatISO9075 from 'date-fns/formatISO9075' import formatDistanceToNow from 'date-fns/formatDistanceToNow' import subSeconds from 'date-fns/subSeconds' import subMinutes from 'date-fns/subMinutes' import subHours from 'date-fns/subHours' import subDays from 'date-fns/subDays' import subYears from 'date-fns/subYears' import { ja } from 'date-fns/locale' import './App.css'; const subFromNow = ({years=0, days=0, hours=0, minutes=0, seconds=0}) => { let timeAgo = new Date() let description = ""; if (years) { timeAgo = subYears(timeAgo, years) description += `${years}年` } if (days) { timeAgo = subDays(timeAgo, days) description += `${days}日` } if (hours) { timeAgo = subHours(timeAgo, hours) description += `${hours}時間` } if (minutes) { timeAgo = subMinutes(timeAgo, minutes) description += `${minutes}分` } if (seconds) { timeAgo = subSeconds(timeAgo, seconds) description += `${seconds}秒` } description += "前" return {description, timeAgo} } function App() { const timeAgoArr = [] timeAgoArr.push(subFromNow({seconds:3})) timeAgoArr.push(subFromNow({seconds:40})) timeAgoArr.push(subFromNow({minutes:1, seconds:20})) timeAgoArr.push(subFromNow({minutes:4, seconds:50})) timeAgoArr.push(subFromNow({minutes:17, seconds:25})) timeAgoArr.push(subFromNow({minutes:47, seconds:4})) timeAgoArr.push(subFromNow({hours:1, minutes:25, seconds:56})) timeAgoArr.push(subFromNow({hours:1, minutes:37, seconds:12})) timeAgoArr.push(subFromNow({hours:10, minutes:5, seconds:32})) timeAgoArr.push(subFromNow({hours:23, minutes:50, seconds:15})) timeAgoArr.push(subFromNow({days:1, hours:0, minutes:5, seconds:52})) timeAgoArr.push(subFromNow({days:1, hours:17, minutes:2, seconds:47})) timeAgoArr.push(subFromNow({days:1, hours:18, minutes:11, seconds:30})) timeAgoArr.push(subFromNow({days:3, hours:2, minutes:45, seconds:7})) timeAgoArr.push(subFromNow({days:12, hours:20 , minutes:36, seconds:3})) timeAgoArr.push(subFromNow({days:29, hours:10 , minutes:46, seconds:51})) timeAgoArr.push(subFromNow({days:30, hours:1 , minutes:29, seconds:1})) timeAgoArr.push(subFromNow({days:50, hours:6 , minutes:27, seconds:48})) timeAgoArr.push(subFromNow({days:63, hours:22 , minutes:1, seconds:55})) timeAgoArr.push(subFromNow({days:120, hours:19 , minutes:4, seconds:6})) timeAgoArr.push(subFromNow({days:361, hours:9 , minutes:22, seconds:29})) timeAgoArr.push(subFromNow({years:1, days:10, hours:15, minutes:32, seconds:15})) timeAgoArr.push(subFromNow({years:1, days:120, hours:14, minutes:44, seconds:20})) timeAgoArr.push(subFromNow({years:1, days:300, hours:12, minutes:3, seconds:30})) timeAgoArr.push(subFromNow({years:3, days:36, hours:2, minutes:22, seconds:45})) timeAgoArr.push(subFromNow({years:3, days:170, hours:5, minutes:38, seconds:33})) timeAgoArr.push(subFromNow({years:3, days:290, hours:2, minutes:39, seconds:10})) timeAgoArr.push(subFromNow({years:10, days:150, hours:13, minutes:4, seconds:2})) return ( <div className="fromNowTable"> <div className="currentTime">現在時刻: {formatISO9075(new Date())}</div> <table> <thead> <tr> <th>説明</th><th>日時</th><th>formatDistanceToNow({'{'}addSuffix: true, locale: ja})</th> </tr> </thead> <tbody> {timeAgoArr.map(({description, timeAgo}, index) => ( <tr key={index}> <td className="description">{description}</td> <td>{formatISO9075(timeAgo)}</td> <td>{formatDistanceToNow(timeAgo, {addSuffix: true, locale: ja})}</td> </tr> ))} </tbody> </table> </div> ); } export default App;
date-fnsの他の経過時間を表示する関数
date-fnsには他にも date-fns - modern JavaScript date utility library という関数が用意されています。 こちらもざっくりとした経過時間を表示しますが、 "約"や"以上"などを表示しないのですっきりするかもしれません。 引数は2つとる必要があり、毎回現在時刻を渡す必要があります。
環境
関連記事
moment.jsで同様のことを行なった記事です。dete-fnsのformatDistanceToNowとは少し表示が違います。↓