teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

テキスト修正

2019/12/20 14:42

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -125,7 +125,7 @@
125
125
 
126
126
  ### 3.JSONのパース
127
127
 
128
- 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処して、`selectStarttime` を得ることを考えます。
128
+ 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処して、`selectStarttime` を得ることを考えます。
129
129
  ```javascript
130
130
  const responseJson = `
131
131
  [

2

テキスト修正

2019/12/20 14:42

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -97,7 +97,7 @@
97
97
 
98
98
  ### 2. 開始と終了の間にある日時を1時間おきに発生するジェネレータ
99
99
 
100
- 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
100
+ 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、**開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
101
101
 
102
102
  ```javascript
103
103
  function* range({ start, end }) {

1

テキスト修正

2019/12/20 14:35

投稿

jun68ykt
jun68ykt

スコア9058

answer CHANGED
@@ -53,4 +53,141 @@
53
53
  - 動作確認用CodePen: [https://codepen.io/jun68ykt/pen/povRjdE?editors=0012](https://codepen.io/jun68ykt/pen/povRjdE?editors=0012)
54
54
 
55
55
 
56
- 参考になれば幸いです。
56
+ 参考になれば幸いです。
57
+
58
+
59
+ # 追記
60
+
61
+ コメントで頂いたコードの意図を把握しましたので、以下の JSON
62
+ ```json
63
+ [
64
+ {
65
+ "id":"1",
66
+ "start_time":"2019-11-30 09:00:00",
67
+ "end_time":"2019-11-30 13:00:00"
68
+ },
69
+ {
70
+ "id":"2",
71
+ "start_time":"2019-11-30 15:00:00",
72
+ "end_time":"2019-11-30 17:00:00"
73
+ }
74
+ ]
75
+ ```
76
+
77
+ から、 配列`selectStarttime` として、以下
78
+ ```javascript
79
+ [ '13:00', '14:00', '17:00', '18:00' ]
80
+ ```
81
+ を得るためのコードを、私が書くとしたら、こう書きますというのを挙げておきます。
82
+
83
+ なお、以下の手順 **1. 〜 7. **に挙げたコードは
84
+
85
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/abzJjPL?editors=0012](https://codepen.io/jun68ykt/pen/abzJjPL?editors=0012)
86
+
87
+ にも上げています。
88
+
89
+ ### 1. フォーマット文字列
90
+
91
+ はじめに、moment と文字列との変換のためのフォーマットとして以下の3つを用意しておきます。
92
+ ```javascript
93
+ const FORMAT_DATE = 'YYYY-MM-DD';
94
+ const FORMAT_DATETIME = 'YYYY-MM-DD HH:mm:ss';
95
+ const FORMAT_TIME = 'HH:mm';
96
+ ```
97
+
98
+ ### 2. 開始と終了の間にある日時を1時間おきに発生するジェネレータ
99
+
100
+ 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
101
+
102
+ ```javascript
103
+ function* range({ start, end }) {
104
+ let m = start;
105
+ while (m.isBefore(end)) {
106
+ yield m;
107
+ m = moment(m).add(1, 'hour');
108
+ }
109
+ }
110
+ ```
111
+ 上記を使うと、たとえば `2019-12-20 11:00` から `2019-12-20 16:00` までの1時間おきの時刻の文字列を配列で得るには、以下のようにします。
112
+
113
+ ```javascript
114
+ const sample = {
115
+ start: moment('2019-12-20 11:00:00', FORMAT_DATETIME),
116
+ end: moment('2019-12-20 16:00:00', FORMAT_DATETIME)
117
+ };
118
+
119
+ const timeStrings = [...range(sample)].map(m => m.format(FORMAT_TIME));
120
+
121
+ // => ["11:00", "12:00", "13:00", "14:00", "15:00"] (※ "16:00" は含まれない)
122
+ ```
123
+
124
+ - 動作確認用CodePen: [https://codepen.io/jun68ykt/pen/PowpBby?editors=0012](https://codepen.io/jun68ykt/pen/PowpBby?editors=0012)
125
+
126
+ ### 3.JSONのパース
127
+
128
+ 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処置して、`selectStarttime` を得ることを考えます。
129
+ ```javascript
130
+ const responseJson = `
131
+ [
132
+ {
133
+ "id":"1",
134
+ "start_time":"2019-11-30 09:00:00",
135
+ "end_time":"2019-11-30 13:00:00"
136
+ },
137
+ {
138
+ "id":"2",
139
+ "start_time":"2019-11-30 15:00:00",
140
+ "end_time":"2019-11-30 17:00:00"
141
+ }
142
+ ]
143
+ `;
144
+ ```
145
+
146
+ 上記の JSONをパースした結果を変数`data` に入れますが、単にパースするだけではなく、配列の各要素の`start_time` と `end_time` の文字列形式の日時を moment に変換したプロパティを持つ要素の配列として、`data` を得るようにします。
147
+
148
+ ```javascript
149
+ const data = JSON.parse(responseJson).map(e => ({
150
+ start: moment(e.start_time, FORMAT_DATETIME),
151
+ end: moment(e.end_time, FORMAT_DATETIME)
152
+ }));
153
+ ```
154
+ ここでは、上記のように、`data` の要素には `id` は含めませんでした。これは `selectStarttime` を得るためには不要なためです。もし他の何らかの処理のために必要であれば含めるようにします。
155
+
156
+ ### 4.日付部分の文字列の取得
157
+ 上記で得られた`data` の先頭要素の `start` から日付の文字列を取得します。
158
+
159
+ ```javascript
160
+ // 日付部分の文字列を取得(例: 2019-11-30)
161
+ const dateStr = data[0].start.format(FORMAT_DATE);
162
+ ```
163
+
164
+ ### 5.営業時間帯の開始と終了を持つオブジェクト
165
+ 上記4.で得た日付の営業開始日時と終了日時の moment を持つオブジェクトを作成します。
166
+ ```javascript
167
+ const businessHours = {
168
+ start: moment(`${dateStr} 09:00:00`, FORMAT_DATETIME),
169
+ end: moment(`${dateStr} 19:00:00`, FORMAT_DATETIME)
170
+ };
171
+ ```
172
+
173
+ ### 6.営業時間帯に含まれる日時の中で、選択可能なものだけを取得
174
+
175
+ 上記5.で作成した営業時間帯に含まれる日時の中で、選択可能なものだけを含む配列 `selectableStartMoments` を得ることを考えます。
176
+
177
+ 先の2.に書いたジェネレータ関数 `range` を使って、`[...range(businessHours)]`とすると、9時始まりで(19時は含まない)営業時間帯に含まれる、1時間おきのmomentの配列が得られますので、これをfilterします。filter に与える条件は、ある時刻が、`data` のどの要素`e`についても、`e.start`未満の時刻であるか、`e.end`以上の時刻となっていることですので、`selectableStartMoments` は以下のようにして得られます。
178
+
179
+ ```javascript
180
+ const selectableStartMoments = [...range(businessHours)].filter(m =>
181
+ data.every(e => m.isBefore(e.start) || m.isSameOrAfter(e.end))
182
+ );
183
+ ```
184
+
185
+ ### 7.文字列に変換して結果を出力
186
+
187
+ 上記6.で得られた `selectableStartMoments` の各要素のmomentを、`HH:mm`形式の文字列に変換すれば、目的の `selectStarttime` が得られます。
188
+
189
+ ```javascript
190
+ const selectStarttime = selectableStartMoments.map(m => m.format(FORMAT_TIME));
191
+
192
+ console.log(selectStarttime); // => ["13:00", "14:00", "17:00", "18:00"]
193
+ ```