回答編集履歴

3

テキスト修正

2019/12/20 14:42

投稿

jun68ykt
jun68ykt

スコア9058

test CHANGED
@@ -252,7 +252,7 @@
252
252
 
253
253
 
254
254
 
255
- 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処して、`selectStarttime` を得ることを考えます。
255
+ 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処して、`selectStarttime` を得ることを考えます。
256
256
 
257
257
  ```javascript
258
258
 

2

テキスト修正

2019/12/20 14:42

投稿

jun68ykt
jun68ykt

スコア9058

test CHANGED
@@ -196,7 +196,7 @@
196
196
 
197
197
 
198
198
 
199
- 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
199
+ 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、**開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
200
200
 
201
201
 
202
202
 

1

テキスト修正

2019/12/20 14:35

投稿

jun68ykt
jun68ykt

スコア9058

test CHANGED
@@ -109,3 +109,277 @@
109
109
 
110
110
 
111
111
  参考になれば幸いです。
112
+
113
+
114
+
115
+
116
+
117
+ # 追記
118
+
119
+
120
+
121
+ コメントで頂いたコードの意図を把握しましたので、以下の JSON
122
+
123
+ ```json
124
+
125
+ [
126
+
127
+ {
128
+
129
+ "id":"1",
130
+
131
+ "start_time":"2019-11-30 09:00:00",
132
+
133
+ "end_time":"2019-11-30 13:00:00"
134
+
135
+ },
136
+
137
+ {
138
+
139
+ "id":"2",
140
+
141
+ "start_time":"2019-11-30 15:00:00",
142
+
143
+ "end_time":"2019-11-30 17:00:00"
144
+
145
+ }
146
+
147
+ ]
148
+
149
+ ```
150
+
151
+
152
+
153
+ から、 配列`selectStarttime` として、以下
154
+
155
+ ```javascript
156
+
157
+ [ '13:00', '14:00', '17:00', '18:00' ]
158
+
159
+ ```
160
+
161
+ を得るためのコードを、私が書くとしたら、こう書きますというのを挙げておきます。
162
+
163
+
164
+
165
+ なお、以下の手順 **1. 〜 7. **に挙げたコードは
166
+
167
+
168
+
169
+ - **動作確認用CodePen:** [https://codepen.io/jun68ykt/pen/abzJjPL?editors=0012](https://codepen.io/jun68ykt/pen/abzJjPL?editors=0012)
170
+
171
+
172
+
173
+ にも上げています。
174
+
175
+
176
+
177
+ ### 1. フォーマット文字列
178
+
179
+
180
+
181
+ はじめに、moment と文字列との変換のためのフォーマットとして以下の3つを用意しておきます。
182
+
183
+ ```javascript
184
+
185
+ const FORMAT_DATE = 'YYYY-MM-DD';
186
+
187
+ const FORMAT_DATETIME = 'YYYY-MM-DD HH:mm:ss';
188
+
189
+ const FORMAT_TIME = 'HH:mm';
190
+
191
+ ```
192
+
193
+
194
+
195
+ ### 2. 開始と終了の間にある日時を1時間おきに発生するジェネレータ
196
+
197
+
198
+
199
+ 次に、momentで与えられる2つの日時(開始日時と終了日時)との間にある日時を1時間おきに取得する仕組みとして、ジェネレータを使います。発生する日時に、開始は含み、終了は含まない**ものとします。また、引数は、ともにmomentである`start`と`end`プロパティを持つオブジェクトです。
200
+
201
+
202
+
203
+ ```javascript
204
+
205
+ function* range({ start, end }) {
206
+
207
+ let m = start;
208
+
209
+ while (m.isBefore(end)) {
210
+
211
+ yield m;
212
+
213
+ m = moment(m).add(1, 'hour');
214
+
215
+ }
216
+
217
+ }
218
+
219
+ ```
220
+
221
+ 上記を使うと、たとえば `2019-12-20 11:00` から `2019-12-20 16:00` までの1時間おきの時刻の文字列を配列で得るには、以下のようにします。
222
+
223
+
224
+
225
+ ```javascript
226
+
227
+ const sample = {
228
+
229
+ start: moment('2019-12-20 11:00:00', FORMAT_DATETIME),
230
+
231
+ end: moment('2019-12-20 16:00:00', FORMAT_DATETIME)
232
+
233
+ };
234
+
235
+
236
+
237
+ const timeStrings = [...range(sample)].map(m => m.format(FORMAT_TIME));
238
+
239
+
240
+
241
+ // => ["11:00", "12:00", "13:00", "14:00", "15:00"] (※ "16:00" は含まれない)
242
+
243
+ ```
244
+
245
+
246
+
247
+ - 動作確認用CodePen: [https://codepen.io/jun68ykt/pen/PowpBby?editors=0012](https://codepen.io/jun68ykt/pen/PowpBby?editors=0012)
248
+
249
+
250
+
251
+ ### 3.JSONのパース
252
+
253
+
254
+
255
+ 上記1.と2.を用意しておいたうえで、下記のようなJSON文字列を処置して、`selectStarttime` を得ることを考えます。
256
+
257
+ ```javascript
258
+
259
+ const responseJson = `
260
+
261
+ [
262
+
263
+ {
264
+
265
+ "id":"1",
266
+
267
+ "start_time":"2019-11-30 09:00:00",
268
+
269
+ "end_time":"2019-11-30 13:00:00"
270
+
271
+ },
272
+
273
+ {
274
+
275
+ "id":"2",
276
+
277
+ "start_time":"2019-11-30 15:00:00",
278
+
279
+ "end_time":"2019-11-30 17:00:00"
280
+
281
+ }
282
+
283
+ ]
284
+
285
+ `;
286
+
287
+ ```
288
+
289
+
290
+
291
+ 上記の JSONをパースした結果を変数`data` に入れますが、単にパースするだけではなく、配列の各要素の`start_time` と `end_time` の文字列形式の日時を moment に変換したプロパティを持つ要素の配列として、`data` を得るようにします。
292
+
293
+
294
+
295
+ ```javascript
296
+
297
+ const data = JSON.parse(responseJson).map(e => ({
298
+
299
+ start: moment(e.start_time, FORMAT_DATETIME),
300
+
301
+ end: moment(e.end_time, FORMAT_DATETIME)
302
+
303
+ }));
304
+
305
+ ```
306
+
307
+ ここでは、上記のように、`data` の要素には `id` は含めませんでした。これは `selectStarttime` を得るためには不要なためです。もし他の何らかの処理のために必要であれば含めるようにします。
308
+
309
+
310
+
311
+ ### 4.日付部分の文字列の取得
312
+
313
+ 上記で得られた`data` の先頭要素の `start` から日付の文字列を取得します。
314
+
315
+
316
+
317
+ ```javascript
318
+
319
+ // 日付部分の文字列を取得(例: 2019-11-30)
320
+
321
+ const dateStr = data[0].start.format(FORMAT_DATE);
322
+
323
+ ```
324
+
325
+
326
+
327
+ ### 5.営業時間帯の開始と終了を持つオブジェクト
328
+
329
+ 上記4.で得た日付の営業開始日時と終了日時の moment を持つオブジェクトを作成します。
330
+
331
+ ```javascript
332
+
333
+ const businessHours = {
334
+
335
+ start: moment(`${dateStr} 09:00:00`, FORMAT_DATETIME),
336
+
337
+ end: moment(`${dateStr} 19:00:00`, FORMAT_DATETIME)
338
+
339
+ };
340
+
341
+ ```
342
+
343
+
344
+
345
+ ### 6.営業時間帯に含まれる日時の中で、選択可能なものだけを取得
346
+
347
+
348
+
349
+ 上記5.で作成した営業時間帯に含まれる日時の中で、選択可能なものだけを含む配列 `selectableStartMoments` を得ることを考えます。
350
+
351
+
352
+
353
+ 先の2.に書いたジェネレータ関数 `range` を使って、`[...range(businessHours)]`とすると、9時始まりで(19時は含まない)営業時間帯に含まれる、1時間おきのmomentの配列が得られますので、これをfilterします。filter に与える条件は、ある時刻が、`data` のどの要素`e`についても、`e.start`未満の時刻であるか、`e.end`以上の時刻となっていることですので、`selectableStartMoments` は以下のようにして得られます。
354
+
355
+
356
+
357
+ ```javascript
358
+
359
+ const selectableStartMoments = [...range(businessHours)].filter(m =>
360
+
361
+ data.every(e => m.isBefore(e.start) || m.isSameOrAfter(e.end))
362
+
363
+ );
364
+
365
+ ```
366
+
367
+
368
+
369
+ ### 7.文字列に変換して結果を出力
370
+
371
+
372
+
373
+ 上記6.で得られた `selectableStartMoments` の各要素のmomentを、`HH:mm`形式の文字列に変換すれば、目的の `selectStarttime` が得られます。
374
+
375
+
376
+
377
+ ```javascript
378
+
379
+ const selectStarttime = selectableStartMoments.map(m => m.format(FORMAT_TIME));
380
+
381
+
382
+
383
+ console.log(selectStarttime); // => ["13:00", "14:00", "17:00", "18:00"]
384
+
385
+ ```