質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

6回答

12277閲覧

指定日が第何週目かを返したい

webhajime

総合スコア17

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

1クリップ

投稿2018/03/30 02:53

前提・実現したいこと

53週目の追加とうるう年からずれる週を直したい。
たとえば表示週テストにて「console.log(schedule(new Date(2022,1,21)))」にすると、
"2022年2月21日(月)の週は第2週です。第2週は2022年2月21日(月)~2022年2月27日(日)です。"
となってしまいます。うるう年が来るたびに1週ずつずれてしまうのでどうにかしたいです。
一応1週目であるべきものを記載しておきます。とても困ってます。宜しくお願いします。

1週目にしたい日付
2018/2/19
2019/2/18
2020/2/17
2021/2/15 ---ここまでは問題なし
2022/2/21 ---ここから2週目になってしまう
2023/2/20
2024/2/19
2025/2/17
2026/2/16
2027/2/15
2028/2/21 ---ここから3週目になってしまう


発生している問題・エラーメッセージ

2021年までは問題なく表示されるが、うるう年が来るたびにずれが生じる。

該当のソースコード

const referenceDate = new Date(2017, 1, 20) //週起算日 const cycle = 364 //週のサイクル const dateT = ["日","月","火","水","木","金","土"] /** * 日付から週を取得 */ function date2Nweek(date) { let diff = date.getTime() - referenceDate.getTime() let diffDays = Math.floor(diff / (1000*60*60*24)) if (diffDays < 0) { diffDays = (cycle - Math.abs(diffDays) % cycle) % cycle }else if (diffDays >= cycle) { diffDays = diffDays % cycle } let nWeek = Math.floor(diffDays / 7) + 1 let DayOfTheWeek = dateT[date.getDay()] return [nWeek, diffDays] } /** * 指定日の週を取得 * @param date 対象の日付:dateObject * @param nWeek 週数:number * @param diffDays 基準日からの差日数:string */ function nWeek2Period(date, nWeek, diffDays) { let targetWeek = new Date(date) targetWeek.setDate(date.getDate() + ((nWeek-1)*7 - diffDays)) let endTargetWeek = new Date(targetWeek) endTargetWeek.setDate(endTargetWeek.getDate() + 6) return [targetWeek, endTargetWeek] } /** * 逆引き * @param nWeek 対象の週:number * @param flg +-年度:number */ function calcSchedule(nWeek, flg = 0) { let date = new Date() //現在の週を取得 let retNweek = date2Nweek(date) //表示年度の基準日を取得 date.setDate(date.getDate() + (flg*cycle - retNweek[1])) //表示する週の日付を取得 date.setDate(date.getDate() + 7*(nWeek-1)) //表示する日付の週を取得 retNweek = date2Nweek(date) let retPeriod = nWeek2Period(date, retNweek[0], retNweek[1]) let retMessage = `表示週第${retNweek[0]}週は\n` + `${retPeriod[0].getFullYear()}年${retPeriod[0].getMonth()+1}月${retPeriod[0].getDate()}日(${dateT[retPeriod[0].getDay()]})` + `~${retPeriod[1].getFullYear()}年${retPeriod[1].getMonth()+1}月${retPeriod[1].getDate()}日(${dateT[retPeriod[1].getDay()]})です。` return retMessage } /** * 表示週 * @param date 対象の日付:dateObject */ function schedule(date = new Date()) { let retNweek = date2Nweek(date) let retPeriod = nWeek2Period(date, retNweek[0], retNweek[1]) let retMessage = `${date.getFullYear()}年${date.getMonth()+1}月${date.getDate()}日(${dateT[date.getDay()]})の週は第${retNweek[0]}週です。\n` + `第${retNweek[0]}週は` + `${retPeriod[0].getFullYear()}年${retPeriod[0].getMonth()+1}月${retPeriod[0].getDate()}日(${dateT[retPeriod[0].getDay()]})` + `~${retPeriod[1].getFullYear()}年${retPeriod[1].getMonth()+1}月${retPeriod[1].getDate()}日(${dateT[retPeriod[1].getDay()]})です。` return retMessage } /** * Example * */ //表示週テスト // let d = new Date(2019,1,18) console.log(schedule(new Date(2028,1,21))) //逆引き表示週テスト // console.log(calcSchedule(51, 0))
defghi1977👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

x_x

2018/03/30 06:55

現状では364日周期となっていてうるう年でなくてもずれていくと思うのですが、この辺の仕様はどうするのでしょうか?
webhajime

2018/03/30 07:05 編集

52週で割り切れる為の記述になってるんですよね。53週が1週目になってしまうことによりずれてしまいます。53週目を毎年表示させるにはどうすればいいか悩んでいます。
think49

2018/03/30 08:36

一般的な感覚では何周目といえば、1日を1週目として数えますが、本件はそうではないようです。要求仕様を詳しく書いてみてはどうでしょうか。
think49

2018/03/30 08:47

「指定した基準日を1週目とする。基準日と年月が同一なら基準日から何周目か数える。年月が変わっても日付さえ合致するなら1週目とする。」サンプルから推定される仕様です。
guest

回答6

0

ベストアンサー

jQueryUIに$.datepicker.iso8601Week()というメソッドがあります。
ソースコードを転記しますので、参考にされてはいかがでしょうか。

js

1 iso8601Week: function( date ) { 2 var time, 3 checkDate = new Date( date.getTime() ); 4 5 // Find Thursday of this week starting on Monday 6 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 7 8 time = checkDate.getTime(); 9 checkDate.setMonth( 0 ); // Compare with Jan 1 10 checkDate.setDate( 1 ); 11 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 12}

jquery-ui/datepicker.js at 17404ced478a235651513fa7bef3473ef1b039e8 · jquery/jquery-ui · GitHub

追記

おそらく、「2月21日が含まれる週が第1週」という仕様だと思います。

js

1function schedule(date){ 2 3 var getMonday = function(date) { 4 return new Date( date.getTime() - ( date.getDay() - 1 ) * 24 * 60 * 60 * 1000 ); 5 } 6 7 date.setHours(0,0,0); 8 9 var tempDate = new Date( date - 24 * 60 * 60 * 1000 ); 10 var monday = getMonday( tempDate ); 11 var sunday = new Date( monday.getTime() + 6 * 24 * 60 * 60 * 1000 ); 12 13 tempDate = new Date(date); 14 tempDate.setMonth(1,20); 15 firstDate = getMonday( tempDate ); 16 if ( firstDate > date ) { 17 tempDate.setMonth(-11,20); 18 firstDate = getMonday( tempDate ); 19 } 20 21 var weekNumber = Math.floor( ( date - firstDate ) / ( 24 * 60 * 60 * 1000 ) / 7 ) + 1; 22 23 return `${ 24 date.toLocaleDateString('ja',{year:'numeric'}) 25 }${ 26 date.toLocaleDateString('ja',{month:'numeric'}) 27 }${ 28 date.toLocaleDateString('ja',{day:'numeric'}) 29 }(${ 30 date.toLocaleDateString('ja',{weekday:'short'}) 31 })の週は第${weekNumber}週です。第${weekNumber}週は${ 32 monday.toLocaleDateString('ja',{year:'numeric'}) 33 }${ 34 monday.toLocaleDateString('ja',{month:'numeric'}) 35 }${ 36 monday.toLocaleDateString('ja',{day:'numeric'}) 37 }(月)~${ 38 sunday.toLocaleDateString('ja',{year:'numeric'}) 39 }${ 40 sunday.toLocaleDateString('ja',{month:'numeric'}) 41 }${ 42 sunday.toLocaleDateString('ja',{day:'numeric'}) 43 }(日)です。`; 44}

js

1[ 2 [2018,1,18], 3 [2018,1,19], 4 [2019,1,18], 5 [2020,1,17], 6 [2021,1,15], 7 [2022,1,21], 8 [2027,1,14], 9 [2027,1,15], 10 [2028,1,20], 11 [2028,1,21], 12].forEach(function(e){ 13 console.log( schedule(new Date(...e)) ); 14}); 15 16/* 172018年2月18日(日)の週は第52週です。第52週は2018年2月12日(月)~2018年2月18日(日)です。 182018年2月19日(月)の週は第1週です。第1週は2018年2月19日(月)~2018年2月25日(日)です。 192019年2月18日(月)の週は第1週です。第1週は2019年2月18日(月)~2019年2月24日(日)です。 202020年2月17日(月)の週は第1週です。第1週は2020年2月17日(月)~2020年2月23日(日)です。 212021年2月15日(月)の週は第1週です。第1週は2021年2月15日(月)~2021年2月21日(日)です。 222022年2月21日(月)の週は第1週です。第1週は2022年2月21日(月)~2022年2月27日(日)です。 232027年2月14日(日)の週は第52週です。第52週は2027年2月8日(月)~2027年2月14日(日)です。 242027年2月15日(月)の週は第1週です。第1週は2027年2月15日(月)~2027年2月21日(日)です。 252028年2月20日(日)の週は第53週です。第53週は2028年2月14日(月)~2028年2月20日(日)です。 262028年2月21日(月)の週は第1週です。第1週は2028年2月21日(月)~2028年2月27日(日)です。 27*/

思いのほか、しんどかったなあ。
みんな、Moment.js とか使うはずだわ……
勉強させてもらいました。

コメントを受けて追記

逆引きの方が簡単なはず。コードの重複があるから適当にまとめてください。

js

1function calcSchedule(weekNumber, year){ 2 3 var getMonday = function(date) { 4 return new Date( date.getTime() - ( date.getDay() - 1 ) * 24 * 60 * 60 * 1000 ); 5 } 6 7 var tempDate = new Date(year, 1, 20, 0, 0, 0); 8 var firstDate = getMonday( tempDate ); 9 var monday = new Date( firstDate.getTime() + ( weekNumber - 1 ) * 7 * 24 * 60 * 60 * 1000 ); 10 var sunday = new Date( monday.getTime() + 6 * 24 * 60 * 60 * 1000 ); 11 12 return `表示週第第${weekNumber}週は 13${ 14 monday.toLocaleDateString('ja',{year:'numeric'}) 15 }${ 16 monday.toLocaleDateString('ja',{month:'numeric'}) 17 }${ 18 monday.toLocaleDateString('ja',{day:'numeric'}) 19 }(月)~${ 20 sunday.toLocaleDateString('ja',{year:'numeric'}) 21 }${ 22 sunday.toLocaleDateString('ja',{month:'numeric'}) 23 }${ 24 sunday.toLocaleDateString('ja',{day:'numeric'}) 25 }(日)です。`; 26}

投稿2018/03/30 03:44

編集2018/04/02 10:12
Lhankor_Mhy

総合スコア36115

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

webhajime

2018/04/02 03:40

ありがとうございます!まさに仕様通りです。
webhajime

2018/04/02 08:07 編集

以下にて1日引かれている理由が気になったのですが、 日曜が次週にならないようになっているのを理解しました。 var tempDate = new Date( date - 24 * 60 * 60 * 1000 ); var monday = getMonday( tempDate ); var sunday = new Date( monday.getTime() + 6 * 24 * 60 * 60 * 1000 ); こちらの記載にて後の計算で‐1日する必要がなくなりました。 function schedule(date){ var getMonday = function(date) { if (date.getDay() == 0) { return new Date( date.getTime() - 6 * 24 * 60 * 60 * 1000 ); // 日曜日対応 } else { return new Date( date.getTime() - ( date.getDay() - 1 ) * 24 * 60 * 60 * 1000 ); } }
Lhankor_Mhy

2018/04/02 08:44

月曜始まりの週でその日が属する月曜を出すための補正です。 date - date.getDay() * 24 * 60 * 60 * 100 月火水木金土日 ␣␣␣␣␣␣○ ←←←←←←␣ date - ( date.getDay() - 1 ) * 24 * 60 * 60 * 100 月火水木金土日 ␣␣␣␣␣␣→ ○←←←←←␣ となり、日曜日の捌きがよくないのです。 なので、1日ずらして、日曜日をひとつ前の週に属するように調整すると、 date【の1日前】 - ( date【の1日前】.getDay() - 1 ) * 24 * 60 * 60 * 100 月火水木金土日 ␣␣␣␣␣␣␣ ○←←←←←← こうなります。 グラフを右にa移動するときには、関数をy=f(x-a)する、というのを中学校あたりの数学で習ったと思いますが、そんな感じのことです。       よく考えると、これは getMonday 関数に入れるべき内容でしたね。
Lhankor_Mhy

2018/04/02 08:45

おっと、入れ違いに。
webhajime

2018/04/02 09:41

回答ありがとうございます。javascriptの経験が浅いのでとても助かります。 function schedule(date)とvar getMonday = function(date)での(date)は 名前変えてわかりやすくすることにします。被っていても動くんですね・・ あと大変恐縮なんですが逆引きの方もできればお願いしたいです><。
Lhankor_Mhy

2018/04/02 10:07

逆引きは大して難しくないですよね?
webhajime

2018/04/03 02:39

すいません、対応できました。この度はありがとうございます。
webhajime

2018/04/06 07:20 編集

逆引きの導入で0週以下、54週の以上が入力された時、53週がない年はfalseを返すようにしました。 if( week >= 54 ){ return ("1~53を入力してください。"); } else if( week <= 0 ){ return ("1~53を入力してください。"); } else if ( week == 53){ var weekNumber = Math.floor( ( monday - getFirstDate(monday) ) / ( 24 * 60 * 60 * 1000 ) / 7 ) + 1; if (week != weekNumber) { return("53週はありません。") } }
guest

0

仕様が特殊なため利用できるかわかりませんが、input要素を使って週情報を取得する方法です。

JavaScript

1function getWeekInfo(date) { 2 let input = document.createElement('input'); 3 input.type = 'week'; 4 input.valueAsDate = date; 5 let value = input.value; // "2018-W13" 6 return { year: parseInt(value.substring(0, 4), 10), week: parseInt(value.substring(6), 10), start: input.valueAsDate }; 7}

-- 17:05 追記
1月4日が含まれる日が1週目ということのようですので、次のようにしてみてはどうでしょうか?

JavaScript

1// 差分を出しておく。 2let a = new Date(referenceDate); 3a.setMonth(0); 4a.setDate(4); 5let dif = referenceDate - a; 6 7// 確認したい日付。 8var d = new Date(2022, 1, 21); 9console.log(getWeekInfo(new Date(d - dif))); // {year: 2022, week: 1, start: Mon Jan 03 2022 09:00:00 GMT+0900 (東京 (標準時))}

投稿2018/03/30 07:13

編集2018/03/30 08:20
x_x

総合スコア13749

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

x_x

2018/03/30 08:10

含まれる「週」です……
x_x

2018/03/30 08:28

startを使うときは差分を足さないといけません。念のため
guest

0

stackoverflowにも似たような記事がありましたので、情報を共有します.
※とは言え, 本件に応用するには最終週の扱いでいろいろ工夫する必要がありそうです.

参考
https://stackoverflow.com/questions/6117814/get-week-of-year-in-javascript-like-in-php
※ソース内の情報は既にリンク切れ
https://web.archive.org/web/20150907215801/http://www.merlyn.demon.co.uk/weekcalc.htm

JavaScript

1/* For a given date, get the ISO week number 2 * 3 * Based on information at: 4 * 5 * http://www.merlyn.demon.co.uk/weekcalc.htm#WNR 6 * 7 * Algorithm is to find nearest thursday, it's year 8 * is the year of the week number. Then get weeks 9 * between that date and the first day of that year. 10 * 11 * Note that dates in one year can be weeks of previous 12 * or next year, overlap is up to 3 days. 13 * 14 * e.g. 2014/12/29 is Monday in week 1 of 2015 15 * 2012/1/1 is Sunday in week 52 of 2011 16 */ 17function getWeekNumber(d) { 18 // Copy date so don't modify original 19 d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())); 20 // Set to nearest Thursday: current date + 4 - current day number 21 // Make Sunday's day number 7 22 d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7)); 23 // Get first day of year 24 var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1)); 25 // Calculate full weeks to nearest Thursday 26 var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7); 27 // Return array of year and week number 28 return [d.getUTCFullYear(), weekNo]; 29} 30 31[ 32 [2018, 2, 19], 33 [2019, 2, 18], 34 [2020, 2, 17], 35 [2021, 2, 15], 36 [2022, 2, 21], 37 [2023, 2, 20], 38 [2024, 2, 19], 39 [2025, 2, 17], 40 [2026, 2, 16], 41 [2027, 2, 15], 42 [2028, 2, 21] 43].forEach( 44 ([y, m, d]) => console.log( 45 [y, m, d].join("/"), 46 getWeekNumber(new Date(y, m, d))[1] - getWeekNumber(new Date(y, 2, 21))[1] + 1) 47);

text

12018/2/19 1 22019/2/18 1 32020/2/17 1 42021/2/15 1 52022/2/21 1 62023/2/20 1 72024/2/19 1 82025/2/17 1 92026/2/16 1 102027/2/15 1 112028/2/21 1

投稿2018/04/02 08:41

編集2018/04/02 08:57
defghi1977

総合スコア4756

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

投稿2018/04/02 07:58

編集2018/04/02 08:08
webhajime

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

普通に考えれば2022-2-21は第4週目ではないかと思いますが、それはさておき。
referenceDateを2017-1-20に固定せず該当月の1日とするようにすれば問題は解決するのではないでしょうか。

投稿2018/03/30 03:32

KojiDoi

総合スコア13671

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Lhankor_Mhy

2018/03/30 03:49

あ、すみません。誤読していました。失礼致しました。
webhajime

2018/03/31 08:40 編集

referenceDateは締日となっていますので固定になっており、それを基に毎年同じ規則で計算されているようです。(20日〆2017/2/20 月曜 1週目開始)第1週目の日付が毎年変わるのを考えると、毎年2月の中旬の日付からを第1週目として登録しておき、そこから53週目までを毎年表示させたいです。
guest

0

外部ライブラリ使用してもよいのであれば、moment.js のweek関数を使うのではどうでしょうか?
https://momentjs.com/docs/#/get-set/week/

すみません、質問全体読まず知りたい内容と外れてましたので、回答取り下げます。

投稿2018/03/30 03:12

編集2018/03/30 03:25
euledge

総合スコア2404

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

defghi1977

2018/04/02 08:20

直接的な回答となってはいないものの, ヒントとして有益なライブラリの紹介であり, 回答の取り下げまでは必要ないと思います.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問