日付の操作が楽になる!Moment.jsの使い方
今回はJavaScriptでの日付の操作を楽にしてくれるライブラリ「Moment.js」の使い方を紹介したいと思います。
ライブラリ?
プログラミングをするのに役立つ便利ツールと思っていただいてよろしいかと思います。
世の中には優秀なプログラマーがおりまして、その方々がみんなの開発作業を楽にしてほしいという思いで出来上がったソースコードを配布してます。
ライブラリにはグラフを作ってくれるもの、カレンダーを表示してくれるもの、PDFを作ってくれるもの、郵便番号から住所を探してくれるものなどいろいろあります。
それらライブラリを自分のプロジェクトに取り込むことで、わざわざ自前で作らなくてもやりたいことができるという便利なものです。
今回紹介するMoment.jsというライブラリは日付の計算やフォーマットを楽にしてくれます。
インストール
公式サイトからダウンロードするかCDNで読み込みます。
以下はCDNで読み込む例です。(現時点で2.29.1が最新バージョンのようです。)
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
とりあえず以下のように書いてみてください。
JavaScript
moment().format('YYYY/MM/DD HH:mm:ss')
これで現在日時が「2021/06/01 01:01:01」のようにフォーマットされた文字列を取得できます。
うまく動かずブラウザのコンソールにエラーが出てる場合はMoment.jsがうまく読み込めていない可能性があります。上記のscriptタグをもう一度確認してください。
src属性に書いてあるURLにアクセスしてページが見れるかどうか、ダウンロードして自分のプロジェクト内にmoment.jsを置いている場合はファイルパスが間違ってないかなどです。
Moment.jsって何が便利なの?
ライブラリを使わなくても素のJavaScriptで日付の計算、フォーマットはすることができます。
が、Moment.jsを使ったほうがコードの記述量が少なくて済みます。
例えば、「2021/06/01 02:03:04」に対して1年 1ヶ月 1日 1時間 1分 1秒足した日付を取りたいとしましょう。
素のJavaScriptでは以下のように書けます。
JavaScript
const date = new Date('202/06/01 02:03:04') // Dateオブジェクトを作る
date.setFullYear(date.getFullYear()+1) // 1年足す
date.setMonth(date.getMonth()+2) // 1ヶ月足す 0始まりなので余計に+1
date.setDate(date.getDate()+1) // 1日足す
date.setHours(date.getHours()+1) // 1時間足す
date.setMinutes(date.getMinutes()+1) // 1分足す
date.setSeconds(date.getSeconds()+1) // 1秒足す
// 以下0埋め作業(例えば1を01にします)
const month = ('00' + date.getMonth()).slice(-2)
const day = ('00' + date.getDate()).slice(-2)
const hour = ('00' + date.getHours()).slice(-2)
const minute = ('00' + date.getMinutes()).slice(-2)
const second = ('00' + date.getSeconds()).slice(-2)
// 計算後フォーマットした日付
const newDate = date.getFullYear() + '/' + month + '/' + day + ' ' + hour + ':' + minute + ':' + second
これがMoment.jsを使うと以下のように書けます
JavaScript
const newDate = moment('2021-06-01 02:03:04').add(1, 'y').add(1, 'M').add(1, 'd').add(1, 'h').add(1, 'm').add(1, 's').format('YYYY/MM/DD HH:mm:ss')
すっきりしましたね!
例えば秒を足す場合、
・DateオブジェクトのgetSeconds()で秒を取得
・取得した秒に「+1」で1秒足した後にsetSeconds()でDateオブジェクトにセットし直す
・getSeconds()では1〜9秒だった場合に0埋めされないので('00' + date.getSeconds()).slice(-2)
で0埋め
のような手順を踏まなければできませんでしたが、
Moment.jsを使うとadd(1, ‘s’)をするだけです。
0埋めなどはformat関数の「ss」の部分でやってくれています。「s」にすると0埋めされない形になります。
コード量が減ることもさることながら見栄えも直感的でわかりやすいです。
では具体的に使い方を見ていきましょう!
Momentオブジェクトを作る
Moment.jsを使うには、とにもかくにもMomentオブジェクトを作らなければなりません。
素のJavaScriptでいうDateオブジェクトにあたるものです。
作るといっても難しいことはなく以下のように書くだけです。
JavaScript
// 現在日時でMomentオブジェクト生成
const date1 = moment()
// 指定の日付でMomentオブジェクト生成
const date2 = moment('2021-06-01')
// 指定の日時でMomentオブジェクト生成
const date3 = moment('2021-06-01 02:03:04')
フォーマットする
Momentオブジェクトをそのまま出力しようとするとこんな感じになります。
Thu Jun 17 2021 15:46:08 GMT+0900
でも表示したいのはもうちょっと日付っぽいフォーマットの情報ですよね。
Moment.jsではフォーマットも簡単です。前段でもちょっと使いましたがformat関数を使います。
以下にフォーマット例を示します。
JavaScript
// 2021/6/7 8:2:3
moment('2021-06-07 20:02:03').format('YYYY/M/D h:m:s')
// 2021/06/07 08:02:03
moment('2021-06-07 20:02:03').format('YYYY/MM/DD hh:mm:ss')
// 2021/06/07 20:02:03
moment('2021-06-07 20:02:03').format('YYYY/MM/DD HH:mm:ss')
// 2021年06月07日 20時02分03秒
moment('2021-06-07 20:02:03').format('YYYY年MM月DD日 HH時mm分ss秒')
// 2021年06月07日 20時02分03秒(Mon)
moment('2021-06-07 20:02:03').format('YYYY年MM月DD日 HH時mm分ss秒(ddd)')
// 2021年06月07日 20時02分03秒(Monday)
moment('2021-06-07 20:02:03').format('YYYY年MM月DD日 HH時mm分ss秒(dddd)')
上記の例でなんとなくわかったかもしれませんが、format関数の引数にフォーマット文字列を渡すだけです。
YとかMとかは実際の年や月が入る部分で、よく使われる部分を以下にまとめます。
入力 | 意味 | 例 |
---|---|---|
YYYY | 年(西暦4桁) | 2021 |
YY | 年(西暦下2桁) | 21 |
M | 月(0埋めなし) | 1 |
MM | 月(0埋めあり) | 01 |
D | 日(0埋めなし) | 1 |
DD | 日(0埋めあり) | 01 |
H | 時(24時間表記(0〜23時)、0埋めなし) | 1 |
HH | 時(24時間表記(0〜23時)、0埋めあり) | 01 |
h | 時(12時間表記(1〜12時)、0埋めなし) | 1 |
hh | 時(12時間表記(1〜12時)、0埋めあり) | 01 |
k | 時(24時間表記(1〜24時)、0埋めなし) | 1 |
kk | 時(24時間表記(1〜24時)、0埋めあり) | 01 |
m | 分(0埋めなし) | 1 |
mm | 分(0埋めあり) | 01 |
s | 秒(0埋めなし) | 1 |
ss | 秒(0埋めあり) | 01 |
ddd | 曜日(略称) | Mon |
dddd | 曜日(フル) | Monday |
みなさん気になるのは曜日の部分かもしれません。
上記の例のとおり、デフォルトでは英語表記になってしまいます。
日本語で表示したいですよね?
できます。
事前に以下のようにMomentオブジェクトにlocaleを設定してください。
JavaScript
moment.locale('ja', {
weekdays: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'],
weekdaysShort: ['日','月','火','水','木','金','土']
})
weekdaysには「dddd」が指定された時に表示する曜日(フル)を列挙し、weekdaysShortには「ddd」が指定された時に表示する曜日(略称)を列挙します。一般的な漢字で書きましたが、ひらがなでもなんでもOKです。
localeに日本語表記の曜日を指定しておくと以下のように表示できます。
JavaScript
// 2021年06月07日 20時02分03秒(月)
moment('2021-06-07 20:02:03').format('YYYY年MM月DD日 HH時mm分ss秒(ddd)')
// 2021年06月07日 20時02分03秒(月曜日)
moment('2021-06-07 20:02:03').format('YYYY年MM月DD日 HH時mm分ss秒(dddd)')
日時の加算
上記の例ですでにちょっと触れましたが、日付や時間を足すにはadd関数を使います。
JavaScript
// Momentオブジェクト生成
const date = moment()
// 2日後の日付にする
date.add(2, 'd')
add関数の第一引数にはどれくらい加算するかを数値で設定します。第二引数には何を加算するかを文字列で設定します。(Moment.jsではキーと呼んでいます。)
上記の場合は日を2日足すという意味です。第二引数の文字列はMoment.jsで決められています。
下記をご覧ください。
キー | 省略形 | 意味 |
---|---|---|
years | y | 年 |
quarters | Q | 3ヶ月(1年の1/4) |
months | M | 月 |
weeks | w | 週 |
days | d | 日 |
hours | h | 時 |
minutes | m | 分 |
seconds | s | 秒 |
milliseconds | ms | ミリ秒 |
日時の減算
逆に日付や時間を引きたい場合はsubtract関数を使います。
JavaScript
// Momentオブジェクト生成
const date = moment()
// 2日前の日付にする
date.subtract(2, 'd')
基本的にはaddをsubtractに置き換えるだけで、使い方はadd関数と変わりません。
ちなみに第一引数の数値にはマイナスも使えます。
moment().add(-1, ‘d’)とmoment.subtract(1, ‘d’)はどちらも1日前という意味になります。
日時の差分が知りたい
2つの日付や日時を比較してどれくらいの差があるかを計算することもできます。
diff関数を使います。
第一引数に比較対象の日時、
第二引数に差分の単位(日時の加算で紹介した表を参照)、
第三引数に小数点以下を表示するかどうか。しない場合はfalse。
を設定します。
JavaScript
const date1 = moment('2021-06-07 20:02:03')
const date2 = moment('2022-07-07 20:02:03')
// 1.0833333333333333
date2.diff(date1, 'y', true)
// 13
date2.diff(date1, 'M', true)
// 395
date2.diff(date1, 'd', true)
// 9480
date2.diff(date1, 'h', true)
// 568800
date2.diff(date1, 'm', true)
// 34128000
date2.diff(date1, 's', true)
日時を比較する
どっちが大きいかを判定することができます。
関数名 | 意味 |
---|---|
isAfter | 比較対象より未来かどうか |
isBefore | 比較対象より過去かどうか |
isSame | 比較対象と同じかどうか |
isSameOrAfter | 比較対象と同じもしくは未来かどうか |
isSameOrBefore | 比較対象と同じもしくは過去かどうか |
isBetween | 比較対象の間にあるかどうか |
例えば2021/01/01が2021/01/02より過去かどうかという比較をしたいときは以下のようになります。
JavaScript
if (moment('2021/01/01').isBefore(moment('2021/01/02'))) {
// 1/1は1/2より過去です。絶対ここを通ります。
}
else {
// 1/1は1/2より未来です。ありえません。
}
以下はサンプルです。
JavaScript
const date1 = moment('2021-06-07 20:02:03')
const date2 = moment('2021-06-07 20:02:04')
const date3 = moment('2021-06-07 20:02:05')
// true
date2.isAfter(date1)
// false
date1.isAfter(date2)
// true
date1.isBefore(date2)
// false
date2.isBefore(date1)
// true
date1.isSame(date1)
// false
date1.isSame(date2)
// true
date2.isSameOrAfter(date1)
// true
date2.isSameOrAfter(date2)
// false
date2.isSameOrAfter(date3)
// true
date2.isSameOrBefore(date3)
// true
date2.isSameOrBefore(date2)
// false
date2.isSameOrBefore(date1)
// true
date2.isBetween(date1, date3)
// false
date1.isBetween(date2, date3)
なんか警告が出るんですけど?
「ああ、動いた動いた」と思ってブラウザのコンソールを開いたら「あれ、なんか警告出てる」みたいなことがあります。
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
↑こんなやつですね。
これは日付や日時を渡してMomentオブジェクトを作る際に起きる警告です。
警告メッセージは何を言っているかというと「引数に指定された日付はRFC2822やISOで定められたフォーマットじゃないよ。うまくいくかもしれないけど、すべてのブラウザやバージョンで動作を保証することができないからおすすめしないよ。」というようなことを言ってます。
どうもISOで決められたフォーマットというのが「20210601」とか「2021-06-01」の形式で、「2021/06/01」とか「2021.06.01」とかは違うようです。スラッシュ区切りの場合、日本だと「年/月/日」ですが、海外とかだと「日/月/年」で表現されたりするので、こういう曖昧な区切りは使わないでねということなのでしょう。
なので区切りはハイフンにして渡してあげれば警告は消えます。
ただ、お作りのプログラムによっては「いやあ、前の処理でスラッシュ区切りの日付が来ちゃってるんだよなー」ってこともあるかと思います。
その場合はMomentオブジェクトを作るときにスラッシュをハイフンに変換してあげましょう。
JavaScript
// 2021/06/01→2021-06-01
moment('2021/06/01'.replace(/\//g, '-'))
まとめ
いかがだったでしょうか。
個人的には日時のフォーマットのしやすさで重宝するライブラリかなと思います。
本当なら素のJavaScriptもこれくらいスマートに書くことができれば苦労はないのですが、残念ながら現時点ではちょっと面倒な書き方しかできません。
Web開発作業では日付操作はよく出てくることと思うので、Moment.jsのようなライブラリを駆使してちょっとでも楽に作りたいですね。
したっけ!
- Moment.jsは日付操作を楽にしてくれるJavaScriptのライブラリ
- フォーマットするにはmoment().format(‘フォーマット文字列’)
- 日付を加算するにはmoment().add(加算量, ‘加算対象キー’)
- 日付を減算するにはmoment().subtract(減算量, ‘減算対象キー’)
- diff関数、isAfter関数などで比較もできるよ
- 日付を指定するときはフォーマットに気をつけて!
本格的にプログラミングを学びたいですか?ITのエンジニアになりたいですか?
IT業界は万年人手不足であり、ニーズがあります。
パソコンとインターネットがあれば場所を問わず仕事ができるので、リモートワークが普及しつつある現代にマッチした職種と言えると思いますし、
物理的に必要なものはパソコンぐらいなので初期投資にかかる費用も少なく、人並みに仕事ができればフリーランスになって会社依存を脱却することもできます。
身につけた技術は一生モノです。
もし本腰を入れて勉強したいという方はスクールに入るのも一つの手です。
いくつか紹介しますので、興味があればサイトを覗いてみてください。
TechAcademy
最短4週間で未経験からプロを育てるオンライン完結のスクールです。 どこかに通う必要なく、自宅でもプログラミングやアプリ開発を学ぶことができます。
TechAcademyのサイトへWant to learn programming in earnest? Want to be an IT engineer?
The IT industry is understaffed for many years and has needs.
If you have a computer and the Internet, you can work anywhere,
so I think it can be said that it is a job type that matches the present age when remote work is becoming widespread.
The initial investment cost is low, and if you can work like a normal person, you can become freelance and get rid of your dependence on the company.
The skills that you have acquired is something that will last a lifetime.
If you want to study in earnest, you can go to school.
I will introduce some of them, so if you are interested, please take a look at the site.
DMM WEBCAMP
This is a programming school for those who are serious about changing jobs. guarantee a job change, so it is recommended for those who are inexperienced and are looking for a job change in the IT industry!
move to DMM WEBCAMPTechAcademy
It is an online school that trains professionals from inexperienced in a minimum of 4 weeks. You can learn programming and app development at home without having to go anywhere.
move to TechAcademy