2つの日付の差分の月数を取得すべく以下のようなコードを作成しました。
Javascript
1function monthDiff(dateFrom, dateTo) { 2 return dateTo.getMonth() - dateFrom.getMonth() + 3 (12 * (dateTo.getFullYear() - dateFrom.getFullYear())) 4} 5console.log(monthDiff(new Date("2021-10-29"),new Date("2021-11-30")))/1
- ここで端数の日数が出る場合、1日でも繰上げて一か月(いわゆる月割の考え方)とカウントしたいのですが、どの容易に対応すれば良いでしょうか?
例えばmonthDiff(new Date("2021-10-29"),new Date("2021-12-1"))
であれば、10月でも端数が出ていて、12月でも端数が出ているので得たい月数は"3"になります。また、monthDiff(new Date("2021-10-29"),new Date("2021-10-30"))
であればどちらも同じ端数月のため得たい月数は1となります。
- また、同様に3か月バージョンも同じ理由で思いつかず悩んでいます。例えば
monthDiff(new Date("2021-8-29"),new Date("2021-12-1"))
であれば8月9月10月で括って1単位で、残りの11月12月は括っても3か月未満ですが、端数単位を繰り上げるので1単位として合計2単位が得たい単位数になります。
getMonth()+1
同士を引けば、1.の月数が得られそうで、そこから3で除するとともに剰余算であまりの有無を確認して+1すれば2.の単位数も得られそうだとも思ったのですが、年跨ぎがあるので、上手くロジックを組み立てられなくなってしまいました。
どなたかアドバイスを頂ければ幸いです。
宜しくお願い申し上げます。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
後は、3で割って切り上げ
js
1function monthDiff (d0, d1) { 2 3 function a (dt, f = false) { 4 let [y, m, d] = ['getFullYear', 'getMonth', 'getDate'].map (fn=> dt[fn]()); 5 let M = y * 12 + m + d / 32; 6 return f ? Math.floor (M): Math.ceil (M); 7 } 8 9 let f = +d0 < +d1; 10 let r = a (d1, !f) - a (d0, f); 11 return r; 12} 13 14console.log (monthDiff(new Date("2021-10-29"), new Date("2021-12-1"))); 15console.log (monthDiff (new Date("2021-12-1"), new Date("2021-10-29")));
小石を重機で・・・
投稿2021/11/26 22:54
総合スコア616
0
ベストアンサー
どなたかアドバイスを頂ければ幸いです。
アドバイスといいますか、自分ならこういった、二つの日付や日時の差分を、何らかの単位(月や日、時間など)で算出する必要があるとき、標準のDateではなくDay.jsを使います。たとえば、ご質問のmonthDiff(dateFrom, dateTo)
を以下のように書けます。
javascript
1// 2// monthDiff(dateFrom, dateTo) 3// 4// 引数 5// dateFrom: YYYY-M-D 形式の文字列 6// dateTo: YYYY-M-D 形式の文字列 7// 8// 返される値: 以下の要素を含む、長さ2の配列 9// 先頭要素: 月数 10// 第2要素: 3ヶ月単位数 11// 12const monthDiff = (dateFrom, dateTo) => { 13 const d1 = dayjs(dateFrom, 'YYYY-M-D').startOf('month'); 14 const d2 = dayjs(dateTo, 'YYYY-M-D').endOf('month').add(1, 'second'); 15 16 const n = d2.diff(d1, 'month'); 17 const m = Math.floor(n / 3) + (n % 3 > 0); 18 return [n, m]; 19}; 20
- ???? 動作確認のサンプル @codepen
または、与えられたYYYY-M-D
形式の文字列の-D
の部分を削除した文字列を、dayjs()
に渡して、YYYY-M
の文字列としてパースしてオブジェクトを作ると、指定された月の月初(1日)の日付を表すものになることを利用して、以下のようにも書けます。
javascript
1const monthDiff = (dateFrom, dateTo) => { 2 [dateFrom, dateTo] = [dateFrom, dateTo].map(dateStr => 3 dayjs(dateStr.replace(/-\d{1,2}$/, ''), 'YYYY-M') 4 ); 5 const n = dateTo.diff(dateFrom, 'month') + 1; 6 const m = Math.floor(n / 3) + (n % 3 > 0); 7 return [n, m]; 8};
- ???? 動作確認のサンプル @codepen
追記
上記のコードで、n
から m
を得る計算は、以下でもできます。
javascript
1const m = Math.floor((n + 2) / 3);
あるいは
javascript
1const m = Math.ceil(n / 3)
追記2
コメントから頂きました、
・・・得たい結果としては1(か月)+14日(剰余日数)となります。
を得るための関数 monthDiff_md(dateFrom, dateTo)
を作ってみました。
・・・もっとdayjsでスマートに行けるのであれば、お知恵を頂きたくご返信させていただきました。
とのことでしたが、スマートなものになっているかは分かりませんが挙げておきます。
javascript
1const monthDiff_md = (dateFrom, dateTo) => { 2 // 引数で与えられた YYYY-M-D 形式の文字列からdayjsオブジェクトを作る 3 const d1 = dayjs(dateFrom, 'YYYY-M-D'); 4 const d2 = dayjs(dateTo,'YYYY-M-D'); 5 6 // d1 と d2 との差分を月単位で得る。その際に小数点以下も取得する。 7 const monthDiff = d2.diff(d1,'month', true); 8 9 // 上記で得た monthDiff の整数部分 n と小数部分 r を取得する。 10 const n = Math.floor(monthDiff); 11 const r = monthDiff - n; 12 13 // d1 に n月 および (n+1)月を加えた日付を作って、d3 および d4 とする。 14 const [d3, d4] = [n, n+1].map(x => d1.add(x, 'month')); 15 16 // d4 と d3 の日数差を計算して m とする。 17 const m = d4.diff(d3, 'day'); 18 19 // m に r を乗じた数を作る。この数の単位は日であり理屈上は整数だが、計算結果は整数にごく近い小数になるのでMath.roundする。 20 const k = Math.round(m * r) 21 22 // n と k を返す 23 return [n, k]; 24}
実行例:
javascript
1const [n, k] = monthDiff_md("2021-6-1","2021-7-15"); 2 3console.log([n, k]);
出力結果:
[ 1, 14 ]
この14
日の算出方法を説明します。
- dayjsのドキュメントでのdiffの説明 に
javascript
1const date1 = dayjs('2019-01-25') 2date1.diff('2018-06-05', 'month', true) // 7.645161290322581
とあるとおり、diff の第三引数に true を渡すと、小数点以下ありの数値が返ってきます。この小数部分を日数に換算することを考えます。
- ご例示の、dateFrom:
"2021-6-1"
と dateTo:"2021-7-15"
であれば、d2.diff(d1,'month', true)
は、私の手元の環境では
1.4516129032258065
という数を返しました。
-
これの小数部分
r
= 0.4516129032258065 を日数に換算するために、この 0.45・・・に何を掛ければよいかというと、上記のソースコードに出てくるd3
とd4
の日数差です。この差は月でいえば一ヶ月ですが、日数換算だとd3
の月の月末が何日なのかによって変わります。また2月だったら年が閏年かも考慮しなければなりませんが、このへんを任せられるのがdayjsの強みですね。 -
d3
とd4
の日数差をm
として得て、m
に先の小数r
= 0.45・・・ を乗じると、欲しい剰余日数が出るはずですが、計算結果としては整数にごく近い小数になると思います。私の手元では、
14.000000000000002
となりました。これの小数を Math.round で切り捨て(または切り上げ)れば、得たい剰余日数の14が得られます。
投稿2021/11/26 17:43
編集2021/11/27 19:44退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2021/11/27 14:34
2021/11/27 15:12
退会済みユーザー
2021/11/27 15:23
0
1.については、pegyさんのコードでほぼ合っています。変更点は最後に+1するところです。例えば同年3月~7月の月数は、7 - 3 + 1 = 5(ヵ月)と求めます。
年を跨ぐ場合も、例えば2020年11月から2021年3月までの月数は、
12 * (2021 - 2020) + (3 - 11) + 1 = 12 * 1 - 8 + 1 = 4 + 1 = 5
のように正しく求められます。
JavaScript
1function monthDiff(dateFrom, dateTo) { 2 return 12 * (dateTo.getFullYear() - dateFrom.getFullYear()) + dateTo.getMonth() - dateFrom.getMonth() + 1; 3} 4 5console.log(monthDiff(new Date("2021-10-29"), new Date("2021-12-31"))); //出力: 3 6console.log(monthDiff(new Date("2020-11-11"), new Date("2021-3-3"))); //出力: 5 7
2.については、月数を3で割った商に、余りが0より大きい場合は1を足す方法と、月数に2を足し、3で割った商を求める方法があります。後者のコードのほうがシンプルです。
JavaScript
1var x = 5; 2 3//方法1 4var a = Math.floor(x / 3); 5if (x % 3 > 0) { 6 a += 1; 7} 8console.log(a); //出力: 2 9 10//方法2 11var b = Math.floor((x + 2) / 3); 12console.log(b); //出力: 2 13
投稿2021/11/26 17:40
編集2021/11/26 17:43総合スコア501
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/11/27 12:11
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/11/27 12:23
2021/11/27 12:28
2021/11/27 12:39
2021/11/27 12:57