PluginProbe
Booking Calendar / 11.8
Booking Calendar v11.8
11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 10.11.3 10.11.4 All 201 releases
booking / includes / _capacity / dates_times_support.php

dates_times_support.php in Booking Calendar 11.8, at includes/_capacity/dates_times_support.php

1,619 lines 70.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly // FixIn: 9.8.0.4.
4
5
6 if ( ! defined( 'WPBC_FULL_DAY_TIME_IN' ) ) { define( 'WPBC_FULL_DAY_TIME_IN' , 1 ); } // = +1 sec. '00:00:01'
7 if ( ! defined( 'WPBC_FULL_DAY_TIME_OUT' ) ) { define( 'WPBC_FULL_DAY_TIME_OUT' , 86392 ); } // = 24 * 60 * 60 = 86400 - 10 sec. + 2 sec. '23:59:52'
8
9 // ---------------------------------------------------------------------------------------------------------------------
10 // Intervals
11 // ---------------------------------------------------------------------------------------------------------------------
12
13 /**
14 * Merge several intersected intervals or return not intersected: [[1,3],[2,6],[8,10],[15,18]] -> [[1,6],[8,10],[15,18]]
15 *
16 * @param array $intervals [ [1,3],[2,4],[6,8],[9,10],[3,7] ]
17 *
18 * @return array [ [1,8],[9,10] ]
19 *
20 * Example: wpbc_merge_intersected_intervals( array( array(1,3), array(2,4), array(6,8), array(9,10), array(3,7) ); -> array( array(1,8), array(9,10) )
21 */
22 function wpbc_merge_intersected_intervals( $intervals ){
23
24 if ( empty( $intervals ) ) {
25 return array();
26 }
27
28 $merged = array();
29
30 // Sort array by first value in a list [[8,10],[1,3],[15,18],[2,6]] -> [[1,3],[2,6],[8,10],[15,18]]
31 usort( $intervals, function ( $compare_A, $compare_B ) {
32 if ( $compare_A[0] > $compare_B[0] ) {
33 return 1;
34 } elseif ( $compare_A[0] < $compare_B[0] ) {
35 return - 1;
36 }
37 return 0;
38 } );
39
40
41 $merged_interval = $intervals[0]; // [1,3]
42
43 for ( $i = 1; $i < count( $intervals ); $i ++ ) {
44 $next_element = $intervals[ $i ]; // [2,6]
45
46 if ( $next_element[0] <= $merged_interval[1] ) {
47 $merged_interval[1] = max( $merged_interval[1], $next_element[1] );
48 } else {
49 $merged[] = $merged_interval;
50 $merged_interval = $next_element;
51 }
52 }
53
54 $merged[] = $merged_interval;
55
56 return $merged;
57 }
58
59
60 /**
61 * Is 2 intervals intersected: [36011, 86392] <=> [1, 43192] => true ( intersected )
62 *
63 * Good explanation here https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
64 *
65 * @param array $interval_A array( 36011, 86392 )
66 * @param array $interval_B array( 1, 43192 )
67 *
68 * @return bool
69 */
70 function wpbc_is__intervals__intersected( $interval_A, $interval_B ) {
71
72 if (
73 ( empty( $interval_A ) )
74 || ( empty( $interval_B ) )
75 ){
76 return false;
77 }
78
79 $is_intersected = max( $interval_A[0], $interval_B[0] ) - min( $interval_A[1], $interval_B[1] );
80
81 // if ( 0 == $is_intersected ) {
82 // // Such ranges going one after other, e.g.: [ 12, 15 ] and [ 15, 21 ]
83 // }
84
85 if ( $is_intersected < 0 ) {
86 return true; // INTERSECTED
87 }
88
89 return false; // Not intersected
90 }
91
92
93
94 // ---------------------------------------------------------------------------------------------------------------------
95 // Time - Slots functions
96 // ---------------------------------------------------------------------------------------------------------------------
97
98 /**
99 * Get time in seconds from SQL date format '2024-01-28 12:00:02' -> 1706443192
100 *
101 * @param $sql_date__ymd_his '2024-01-28 12:00:02' Date in SQL format
102 * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec
103 *
104 * @return int
105 *
106 * if $is_apply__check_in_out__10s == true (it's default)
107 *
108 * then apply +10 seconds for check in time it's time, that ended with 1
109 * and apply -10 seconds for check out time it's time, that ended with 2
110
111 */
112 function wpbc_convert__sql_date__to_seconds( $sql_date__ymd_his, $is_apply__check_in_out__10s = true ){
113
114 list( $sql_date_ymd, $sql_time_his ) = explode( ' ', $sql_date__ymd_his ); // '2024-01-28', '12:00:02'
115
116 $date_in_seconds = wpbc_convert__date_ymd__to_seconds( $sql_date_ymd );
117 $time_in_seconds = wpbc_convert__time_his__to_seconds( $sql_time_his, $is_apply__check_in_out__10s );
118
119 $in_seconds = $date_in_seconds + $time_in_seconds;
120
121 return $in_seconds;
122 }
123
124
125 /**
126 * Get date in seconds from SQL only_date format '2024-01-28' -> 1706400000
127 *
128 * @param $sql_date_ymd '2024-01-28'
129 *
130 * @return int
131 */
132 function wpbc_convert__date_ymd__to_seconds( $sql_date_ymd ){
133
134 // DATE
135 $sql_date_time = $sql_date_ymd . ' 00:00:00';
136
137 $in_seconds = strtotime( $sql_date_time );
138
139 return $in_seconds;
140 }
141
142
143 /**
144 * Get time in seconds from SQL time format '12:00:02' -> 43192
145 *
146 * @param string $sql_time_his '12:00:02'
147 * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec
148 *
149 * @return int
150 *
151 * if $is_apply__check_in_out__10s == true (it's default)
152 *
153 * then apply +10 seconds for check in time it's time, that ended with 1
154 * and apply -10 seconds for check out time it's time, that ended with 2
155 */
156 function wpbc_convert__time_his__to_seconds( $sql_time_his, $is_apply__check_in_out__10s = true ){
157
158 // TIME
159 $in_seconds = explode( ':', $sql_time_his );
160
161 $in_seconds = intval( $in_seconds[0] ) * 60 * 60 + intval( $in_seconds[1] ) * 60 + intval( $in_seconds[2] ); // 43202
162
163 if ( $is_apply__check_in_out__10s ) {
164
165 $is_check_in_out__or_full = $in_seconds % 10; // 0, 1, 2
166
167 if ( 1 == $is_check_in_out__or_full ) {
168 $in_seconds += 10;
169 }
170 if ( 2 == $is_check_in_out__or_full ) {
171 $in_seconds -= 10;
172 }
173 }
174
175 $in_seconds = intval( $in_seconds );
176
177 return $in_seconds;
178 }
179
180
181 /**
182 * Get time in SQL time format from seconds 43192 -> '12:00:02'
183 *
184 * @param int $in_seconds 43192
185 * @param bool $is_apply__check_in_out__10s : check_in_time = +10sec check_out_time = -10sec
186 *
187 * @return int
188 *
189 * if $is_apply__check_in_out__10s == true (it's default)
190 *
191 * then apply +10 seconds for check in time it's time, that ended with 1
192 * and apply -10 seconds for check out time it's time, that ended with 2
193 */
194 function wpbc_convert__seconds__to_time_his( $in_seconds, $is_apply__check_in_out__10s = true ){
195
196 //$is_check_in_out__or_full = $seconds__this__booking % 10; // 1, 2 (not 0)
197 $is_check_in_out__or_full = substr( ( (string) $in_seconds ), -1 ); // '1', '2' (not '0')
198
199 if ( '1' == $is_check_in_out__or_full ) {
200 if ( WPBC_FULL_DAY_TIME_IN == $in_seconds ) { // situation: 00:00 e.g. 1 sec.
201 $in_seconds = 0;
202 } else {
203 $in_seconds = $in_seconds - 10 - 1;
204 }
205 }
206 if ( '2' == $is_check_in_out__or_full ) {
207 if ( WPBC_FULL_DAY_TIME_OUT == $in_seconds ) { // situation: 24:00 e.g. 86400 -10 +2 sec.
208 $in_seconds = 86400;
209 } else {
210 $in_seconds = $in_seconds + 10 - 2;
211 }
212 }
213
214 $rest_without_hours_as_seconds = $in_seconds % ( 60 * 60 );
215
216 $in_hours = ( $in_seconds - $rest_without_hours_as_seconds ) / ( 60 * 60 ); // 43200
217 $in_hours = intval( $in_hours ); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN );
218
219 $in_minutes = $rest_without_hours_as_seconds / 60; // 43200
220 $in_minutes = intval( $in_minutes ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1.
221
222 $in_only_seconds = $in_seconds - ( $in_hours * 60 * 60 ) - ( $in_minutes * 60 ); // 43200
223 $in_only_seconds = intval( $in_only_seconds ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1.
224
225 if ( '1' == $is_check_in_out__or_full ) {
226 $in_only_seconds += 1;
227 }
228 if ( '2' == $is_check_in_out__or_full ) {
229 $in_only_seconds += 2;
230 }
231
232
233 $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours;
234 $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes;
235 $in_only_seconds = ( $in_only_seconds < 10 ) ? '0' . $in_only_seconds : $in_only_seconds;
236
237 $sql_time_his = $in_hours . ':' . $in_minutes . ':'. $in_only_seconds;
238
239 return $sql_time_his;
240 }
241
242
243 /**
244 * Convert date timestamp (date in seconds) to SQL date format 1706400000 -> '2024-01-28 00:00:00'
245 *
246 * @param int $in_seconds 1706400000
247 * @param bool $is_apply__check_in_out__10s true : check_in_time = -10sec check_out_time = +10sec
248 * @param string $sql_date_format 'Y-m-d H:i:s' : sometimes need to have ''Y-m-d 00:00:01' or other...
249 *
250 * @return false|string '2024-01-28 00:00:00'
251 */
252 function wpbc_convert__seconds__to_sql_date( $in_seconds, $is_apply__check_in_out__10s = true, $sql_date_format = 'Y-m-d H:i:s' ){
253
254 if ( $is_apply__check_in_out__10s ) {
255
256 $is_check_in_out__or_full = $in_seconds % 10; // 0, 1, 2
257
258 if ( 1 == $is_check_in_out__or_full ) {
259 $in_seconds -= 10;
260 }
261 if ( 2 == $is_check_in_out__or_full ) {
262 $in_seconds += 10;
263 }
264 }
265
266 $sql_date = gmdate( $sql_date_format, $in_seconds );
267
268 return $sql_date;
269 }
270
271 // -----------------------------------------------------------------------------------------------------------------
272
273 /**
274 * Convert usual to seconds time range "10:15 - 12:00" -> "36911 - 43192"
275 *
276 * It's means that "10:15 - 12:00" in seconds "36900 - 43200" and with intersection fix: "(36900 +10 +1) - (43200 -10 +2)" e.g. "36911 - 43192"
277 *
278 * @param string $readable_time_slot "10:15 - 12:00"
279 *
280 * @return string time_range_in_seconds "36911 - 43192"
281 */
282 function wpbc_convert__readable_time_slot__to__time_range_in_seconds( $readable_time_slot ) {
283
284 $rangeA_arr = explode( '-', $readable_time_slot );
285 $rangeA_arr[0] = trim( $rangeA_arr[0] );
286 $rangeA_arr[1] = trim( $rangeA_arr[1] );
287
288 $time_range_in_seconds = array();
289
290 foreach ( $rangeA_arr as $is_end_time => $only_time ) { // $is_end_time = 0 | 1
291
292 $in_seconds = explode( ':', $only_time );
293 $in_seconds = intval( $in_seconds[0] ) * 60 * 60 + intval( $in_seconds[1] ) * 60; // 43200
294
295 if ( ! $is_end_time ) {
296
297 if ( 0 == $in_seconds ) { // situation: 00:00 e.g. 0 sec.
298 $in_seconds = WPBC_FULL_DAY_TIME_IN;
299 } else {
300 $in_seconds = $in_seconds + 10 + 1;
301 }
302
303 } else {
304
305 if ( 86400 == $in_seconds ) { // situation: 24:00 e.g. 86400 sec.
306 $in_seconds = WPBC_FULL_DAY_TIME_OUT;
307 } else {
308 $in_seconds = $in_seconds - 10 + 2;
309 }
310
311 }
312
313 $time_range_in_seconds[] = $in_seconds;
314 }
315
316 $time_range_in_seconds = implode( ' - ', $time_range_in_seconds );
317
318 return $time_range_in_seconds;
319 }
320
321
322 /**
323 * Convert seconds to usual time range: "36911 - 43192" -> "10:15 - 12:00"
324 *
325 * It's means "36911 - 43192" with intersection fix: "(36900 +10 +1) - (43200 -10 +2)" e.g. in seconds "36900 - 43200" is equal to "10:15 - 12:00"
326 *
327 * @param string $time_range_in_seconds "36911 - 43192"
328 *
329 * @return string $time_slot "10:15 - 12:00"
330 */
331 function wpbc_convert__time_range_in_seconds__to__readable_time_slot( $time_range_in_seconds ) {
332
333 $rangeA_arr = explode( '-', $time_range_in_seconds );
334 $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) );
335 $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) );
336
337 $time_slot = array();
338
339 foreach ( $rangeA_arr as $is_end_time => $in_seconds ) { // $is_end_time = 0 | 1
340
341 if ( ! $is_end_time ) {
342
343 if ( WPBC_FULL_DAY_TIME_IN == $in_seconds ) { // situation: 00:00 e.g. 1 sec.
344 $in_seconds = 0;
345 } else {
346 $in_seconds = $in_seconds - 10 - 1;
347 }
348
349 } else {
350
351 if ( WPBC_FULL_DAY_TIME_OUT == $in_seconds ) { // situation: 24:00 e.g. 86400 -10 +2 sec.
352 $in_seconds = 86400;
353 } else {
354 $in_seconds = $in_seconds + 10 - 2;
355 }
356 }
357
358 $just_minutes_as_seconds = $in_seconds % ( 60 * 60 );
359
360 $in_hours = ( $in_seconds - $just_minutes_as_seconds ) / ( 60 * 60 ); // 43200
361 $in_minutes = $just_minutes_as_seconds / 60; // 43200
362
363 $in_hours = intval($in_hours); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN );
364 $in_minutes = intval($in_minutes); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1.
365
366 $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours;
367 $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes;
368
369 $time_slot[] = $in_hours . ':' . $in_minutes;
370 }
371
372 $time_slot = implode( ' - ', $time_slot );
373
374 return $time_slot;
375 }
376
377
378 /**
379 * Get SQL TIME from SECONDS 43211 -> '12:00:11'
380 *
381 * @param int $in_seconds 43201
382 *
383 * @return string '10:00:02'
384 */
385 function wpbc_transform__seconds__in__24_hours_his( $in_seconds ){
386
387 $rest_without_hours_as_seconds = $in_seconds % ( 60 * 60 );
388
389 $in_hours = ( $in_seconds - $rest_without_hours_as_seconds ) / ( 60 * 60 ); // 12
390 $in_hours = intval( $in_hours ); // from 20.99 hours get 20 // round( $in_hours, 0, PHP_ROUND_HALF_DOWN );
391
392 $in_minutes = $rest_without_hours_as_seconds / 60; // 43200
393 $in_minutes = intval( $in_minutes ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1.
394
395 $in_only_seconds = $in_seconds - ( $in_hours * 60 * 60 ) - ( $in_minutes * 60 ); // 43200
396 $in_only_seconds = intval( $in_only_seconds ); // from 55.99 minutes get 55 // round( $in_minutes, 0, PHP_ROUND_HALF_DOWN ); // making 1.5 into 1 and -1.5 into -1.
397
398
399 $in_hours = ( $in_hours < 10 ) ? '0' . $in_hours : $in_hours;
400 $in_minutes = ( $in_minutes < 10 ) ? '0' . $in_minutes : $in_minutes;
401 $in_only_seconds = ( $in_only_seconds < 10 ) ? '0' . $in_only_seconds : $in_only_seconds;
402
403 $sql_time_his = $in_hours . ':' . $in_minutes . ':'. $in_only_seconds;
404
405 return $sql_time_his;
406 }
407
408
409 /**
410 * Get time in seconds from SQL time format '12:00:02' -> 43192
411 *
412 * @param string $sql_time_his '12:00:02'
413 *
414 * @return int
415 */
416 function wpbc_transform__24_hours_his__in__seconds( $in_24_hours_his ) {
417
418 $is_apply__check_in_out__10s = false;
419
420 return wpbc_convert__time_his__to_seconds( $in_24_hours_his, $is_apply__check_in_out__10s );
421 }
422
423 /**
424 * Get AM/PM or 24 hour TIME from SECONDS 43211 -> '12:00 PM' | 86400 -> '12:00 AM'
425 *
426 * @param int $in_seconds 43201
427 * @param string $time_format '' (optional) time format, like 'H:i:s' otherwise get from Booking > Settings General
428 *
429 * @return string '10:00:02' | '10:00 AM'
430 */
431 function wpbc_transform__seconds__in__formated_hours( $in_seconds, $time_format = '' ) {
432
433 if ( empty( $time_format ) ) {
434 $time_format = get_bk_option( 'booking_time_format' ); // get from Booking Calendar
435 if ( empty( $time_format ) ) {
436 $time_format = get_option( 'time_format' ); // Get WordPress default
437 }
438 }
439
440 if ( $in_seconds >= 86400 ) {
441 // if we have 24:00 then instead of 00:00 show 24:00 ... Please check more here https://www.php.net/manual/en/datetime.format.php
442 $time_format = str_replace( array( 'H', 'G' ), '24', $time_format );
443 //$in_seconds--; // It will decrees time on 1 second and show time as 11:59PM instead of 12:00AM
444 }
445
446 $s_tm = date_i18n( $time_format, $in_seconds );
447
448 return $s_tm;
449 }
450
451 // -----------------------------------------------------------------------------------------------------------------
452
453
454 /**
455 * Union 2 time-slot ranges: "100 - 900" & "500 - 3500" -> [ "100 - 3500" ] OR "10 - 70" & "100 - 500" -> [ "10 - 70", "100 - 500" ]
456 *
457 * @param $timeslot_A_in_range_seconds '36011 - 86392' it is means: "'Start time1 in seconds' - 'End time1 in seconds'" e.g. "10:00 - 24:00"
458 * @param $timeslot_B_in_range_seconds '1 - 43192' it is means: "'Start time2 in seconds' - 'End time2 in seconds'" e.g. "00:00 - 12:00"
459 *
460 * @return array [ "1 - 86392" ] one or two ranges
461 *
462 */
463 function wpbc_union__timeslots_seconds( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) {
464
465 if ( ! wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) ) {
466 return array( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds );
467 }
468
469 if ( ( '0' == $timeslot_A_in_range_seconds ) || ( '0' == $timeslot_B_in_range_seconds ) ) {
470 return array( '0 - 86400' ); // Old Full day booking, it is means always intersect.
471 }
472
473 $rangeA_arr = explode( '-', $timeslot_A_in_range_seconds );
474 $rangeB_arr = explode( '-', $timeslot_B_in_range_seconds );
475
476 $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) );
477 $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) );
478 $rangeB_arr[0] = intval( trim( $rangeB_arr[0] ) );
479 $rangeB_arr[1] = intval( trim( $rangeB_arr[1] ) );
480
481 $start = min( $rangeA_arr[0], $rangeB_arr[0] );
482 $end = max( $rangeA_arr[1], $rangeB_arr[1] );
483 $result = array( $start . ' - ' . $end );
484
485 return $result;
486 }
487
488
489 /**
490 * Is 2 time-slots ranges intersected: "36011 - 86392" <=> "1 - 43192" = true ( intersected )
491 *
492 * Good explanation here https://stackoverflow.com/questions/3269434/whats-the-most-efficient-way-to-test-if-two-ranges-overlap
493 *
494 * @param $timeslot_A_in_range_seconds '36011 - 86392' it is means: "'Start time1 in seconds' - 'End time1 in seconds'" e.g. "10:00 - 24:00"
495 * @param $timeslot_B_in_range_seconds '1 - 43192' it is means: "'Start time2 in seconds' - 'End time2 in seconds'" e.g. "00:00 - 12:00"
496 *
497 * @return bool
498 *
499 *
500 * Some exceptions:
501 * if range = '0' - it is means Full day booking, it's always intersected !
502 * all start times ended with "1" second and previously was added +10 seconds, that's why 36011 is means 36011 - 10 - 1 = 36000 e.g. = 10:00
503 * all end times ended with "2" second and previously was -10 seconds, that's why 43192 is means 43192 + 10 - 2 = 43200 e.g. = 12:00
504 *
505 * When in some date we have ONLY start time or end time, it's means that this time start from 00:00 or end at 24:00 (because usually such bookings for SEVERAL days)
506 * and we autofill such times by adding start time or end time:
507 * Autofilled start time is always 1 = 0 +1 - 00:01
508 * Autofilled end time is always 86392 = 86400 -10 +2 - 23:59:58
509 */
510 function wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds ) {
511
512 // Full day booking, it is means always intersect.
513 if ( ( '0' == $timeslot_A_in_range_seconds ) || ( '0' == $timeslot_B_in_range_seconds ) ) {
514 return true; // Time ranges INTERSECTED
515 }
516
517 $rangeA_arr = explode( '-', $timeslot_A_in_range_seconds );
518 $rangeB_arr = explode( '-', $timeslot_B_in_range_seconds );
519
520 $rangeA_arr[0] = intval( trim( $rangeA_arr[0] ) );
521 $rangeA_arr[1] = intval( trim( $rangeA_arr[1] ) );
522 $rangeB_arr[0] = intval( trim( $rangeB_arr[0] ) );
523 $rangeB_arr[1] = intval( trim( $rangeB_arr[1] ) );
524
525
526 $is_intersected = max( $rangeA_arr[0], $rangeB_arr[0] ) - min( $rangeA_arr[1], $rangeB_arr[1] );
527
528 // if ( 0 == $is_intersected ) {
529 // // Such ranges going one after other, e.g.: "12:00 - 15:00" and "15:00 - 21:00"
530 // }
531
532 if ( $is_intersected < 0 ) {
533 return true; // Time ranges INTERSECTED
534 }
535
536 return false; // Otherwise time slot not intersected
537 }
538
539
540 /**
541 * Is 2 time-slots ranges intersected: "10:00 - 24:00" <=> "00:00 - 12:00" = true ( intersected )
542 *
543 *
544 * @param $timeslot_A_readable '10:00 - 24:00'
545 * @param $timeslot_B_readable '00:00 - 12:00'
546 *
547 * @return bool
548 *
549 *
550 * See more here: wpbc_is__timeslots_seconds__intersected()
551 */
552 function wpbc_is__timeslots_readable__intersected( $timeslot_A_readable, $timeslot_B_readable ) {
553
554 // Full day booking, it is means always intersect.
555 if ( ( '0' == $timeslot_A_readable ) || ( '0' == $timeslot_B_readable ) ) {
556 return true; // Time ranges INTERSECTED
557 }
558
559 $timeslot_A_in_range_seconds = wpbc_convert__readable_time_slot__to__time_range_in_seconds( $timeslot_A_readable );
560 $timeslot_B_in_range_seconds = wpbc_convert__readable_time_slot__to__time_range_in_seconds( $timeslot_B_readable );
561
562 return wpbc_is__timeslots_seconds__intersected( $timeslot_A_in_range_seconds, $timeslot_B_in_range_seconds );
563 }
564
565
566 // -----------------------------------------------------------------------------------------------------------------
567
568 /**
569 * Check if BOOKING_FORM time-slots available and not intersect with booked time slots from bookings
570 *
571 *
572 * @param array $checking__timerange_sec__arr [ '36011 - 43192', '56011 - 86392' ]
573 * @param array $booked__timerange_sec__arr [ '36011 - 43192' ]
574 *
575 * @return bool true | false
576 *
577 *
578 * if $checking__timerange_sec__arr EMPTY then TRUE
579 *
580 */
581 function wpbc_is_some_timeslot__available__in_arr( $checking__timerange_sec__arr, $booked__timerange_sec__arr ) {
582
583 if ( empty( $checking__timerange_sec__arr ) ) {
584 return true;
585 }
586
587 $is_available__timeslots__arr = array();
588
589 // Available_Form time-slots: [ "10:00 - 12:00", "12:00 - 14:00", "14:00 - 16:00" ]
590 foreach ( $checking__timerange_sec__arr as $checking__timeslot__key => $checking__timeslot__value ) {
591
592 $is_available__timeslots__arr[ $checking__timeslot__key ] = true;
593
594 // Booked time-slots: [ "12:00 - 14:00", "14:00 - 16:00" ]
595 foreach ( $booked__timerange_sec__arr as $booked__timeslot_value ) {
596
597 $is_time_intersected = wpbc_is__timeslots_seconds__intersected( $booked__timeslot_value, $checking__timeslot__value ); // '36011 - 43192', '56011 - 86392'
598 if ( $is_time_intersected ) {
599 $is_available__timeslots__arr[ $checking__timeslot__key ] = false;
600 break;
601 }
602 }
603 }
604
605 // If at least one time slot available then day still available
606 $is_some_timeslot_available = false;
607 foreach ( $is_available__timeslots__arr as $is__timeslot_available ) {
608 if ( $is__timeslot_available ) {
609 $is_some_timeslot_available = true;
610 break;
611 }
612 }
613
614 return $is_some_timeslot_available;
615 }
616
617 // -----------------------------------------------------------------------------------------------------------------
618
619 /**
620 * '43211 - 86392' into [43201, 86400]
621 *
622 * @param string $booked_times__key_arr
623 * @param bool $is_apply_end_time_correction
624 *
625 * @return array|string[]
626 */
627 function wpbc_transform_timerange__s_range__in__seconds_arr( $booked_times__key_arr, $is_apply_end_time_correction = true ){
628
629 $booked_times__key_arr = explode( ' - ', $booked_times__key_arr );
630
631 $booked_times__key_arr[0] = intval( trim( $booked_times__key_arr[0] ) );
632 $booked_times__key_arr[1] = intval( trim( $booked_times__key_arr[1] ) );
633
634 if ( $is_apply_end_time_correction ) {
635
636 // Fix when we have 10:00:11 seconds, and we need to show the 14:00:02
637 if ( '1' == substr( (string) $booked_times__key_arr[0], - 1 ) ) {
638 $booked_times__key_arr[0] = $booked_times__key_arr[0] - 10;
639 }
640 $booked_times__key_arr[0] = ( $booked_times__key_arr[0] < 0 ) ? 1 : $booked_times__key_arr[0];
641
642 // Fix when we have 13:59:52 seconds, and we need to show the 14:00:02
643 if ( '2' == substr( (string) $booked_times__key_arr[1], - 1 ) ) {
644 $booked_times__key_arr[1] = $booked_times__key_arr[1] + 10;
645 }
646
647 $booked_times__key_arr[1] = ( $booked_times__key_arr[1] > 86400 ) ? 86400 : $booked_times__key_arr[1];
648 }
649
650 return $booked_times__key_arr;
651 }
652
653
654 /**
655 * [43211, 86400] -> '12:00:11 - 24:00:00'
656 *
657 * @param $booked_times__key_arr
658 *
659 * @return string
660 */
661 function wpbc_transform_timerange__seconds_arr__in__24_hours_range( $booked_times__key_arr ){
662
663 $readable_time_slot_formatted = wpbc_transform__seconds__in__24_hours_his( $booked_times__key_arr[0] )
664 . ' - '
665 . wpbc_transform__seconds__in__24_hours_his( $booked_times__key_arr[1] ) ;
666
667 return $readable_time_slot_formatted;
668 }
669
670
671 /**
672 * [43211, 86400] -> '12:00 PM - 12:00 AM' - transform time-range in General Settings - Time Format
673 *
674 * @param $booked_times__key_arr
675 *
676 * @return string
677 */
678 function wpbc_transform_timerange__seconds_arr__in__formated_hours( $booked_times__key_arr ){
679
680 $readable_time_slot_formatted = wpbc_transform__seconds__in__formated_hours( $booked_times__key_arr[0] )
681 . ' - '
682 . wpbc_transform__seconds__in__formated_hours( $booked_times__key_arr[1] ) ;
683
684 return $readable_time_slot_formatted;
685 }
686
687
688 /**
689 * Converts a period of time in seconds into a human-readable format representing the interval.
690 *
691 * @param int $time_interval_in_seconds : 90 - A period of time in seconds.
692 *
693 * @return string : '1 minute 30 seconds'
694 *
695 * Example:
696 *
697 * echo wpbc_get_readable_time_interval( 90 ); <- 1 minute 30 seconds
698 *
699 */
700 function wpbc_get_readable_time_interval( $time_interval_in_seconds ) {
701
702 // Array of time period chunks.
703 $chunks = array(
704 /* translators: 1: The number of years in an interval of time. */
705 array( 60 * 60 * 24 * 365, _n_noop( '%s year', '%s years', 'booking' ) ),
706 /* translators: 1: The number of months in an interval of time. */
707 array( 60 * 60 * 24 * 30, _n_noop( '%s month', '%s months', 'booking' ) ),
708 /* translators: 1: The number of weeks in an interval of time. */
709 array( 60 * 60 * 24 * 7, _n_noop( '%s week', '%s weeks', 'booking' ) ),
710 /* translators: 1: The number of days in an interval of time. */
711 array( 60 * 60 * 24, _n_noop( '%s day', '%s days', 'booking' ) ),
712 /* translators: 1: The number of hours in an interval of time. */
713 array( 60 * 60, _n_noop( '%s hour', '%s hours', 'booking' ) ),
714 /* translators: 1: The number of minutes in an interval of time. */
715 array( 60, _n_noop( '%s minute', '%s minutes', 'booking' ) ),
716 /* translators: 1: The number of seconds in an interval of time. */
717 array( 1, _n_noop( '%s second', '%s seconds', 'booking' ) ),
718 );
719
720 if ( ( $time_interval_in_seconds <= 0 ) || ( ! is_int( $time_interval_in_seconds ) ) ) {
721 return __( 'now', 'booking' );
722 }
723
724 /**
725 * We only want to output two chunks of time here, eg:
726 * x years, xx months
727 * x days, xx hours
728 * so there's only two bits of calculation below:
729 */
730 $j = count( $chunks );
731
732 // Step one: the first chunk.
733 for ( $i = 0; $i < $j; $i++ ) {
734 $seconds = $chunks[ $i ][0];
735 $name = $chunks[ $i ][1];
736
737 // Finding the biggest chunk (if the chunk fits, break).
738 $count = floor( $time_interval_in_seconds / $seconds );
739 if ( $count ) {
740 break;
741 }
742 }
743
744 // Set output var.
745 $output = sprintf( translate_nooped_plural( $name, $count, 'booking' ), $count );
746
747 // Step two: the second chunk.
748 if ( $i + 1 < $j ) {
749 $seconds2 = $chunks[ $i + 1 ][0];
750 $name2 = $chunks[ $i + 1 ][1];
751 $count2 = floor( ( $time_interval_in_seconds - ( $seconds * $count ) ) / $seconds2 );
752 if ( $count2 ) {
753 // Add to output var.
754 $output .= ' ' . sprintf( translate_nooped_plural( $name2, $count2, 'booking' ), $count2 );
755 }
756 }
757
758 return $output;
759 }
760
761
762 // =====================================================================================================================
763 // == D A T E S M a i n l y ===
764 // =====================================================================================================================
765
766
767 /**
768 * Conception: - Time-Slots A - B '10:00:01 - 12:00:02' '10:00:01 - 12:00:02'
769 *
770 * - Check in A - ... '14:00:01 - ... ' '14:00:01 - 24:00:00'
771 * - Check out ... - B ' ... - 12:00:02' '00:00:00 - 12:00:02'
772 *
773 * - Full day ... - ... ' ... - ... ' '00:00:00 - 24:00:00'
774 *
775 * - Full IN ..1 - ... '00:00:01 - ... ' '00:00:01 - 24:00:00'
776 * - Full OUT ... - ..2 ' ... - 24:00:02' '00:00:00 - 24:00:02'
777 *
778 *
779 * 1) Always in one specific date, can be start & end times.
780 * 2) Such start end times can define
781 *
782 */
783
784 // ---------------------------------------------------------------------------------------------------------------------
785 // Support Transformation functions for dates arrays
786 // ---------------------------------------------------------------------------------------------------------------------
787
788 /**
789 * From SQL dates array generate new Extended Dates Array: [ > resource_id < ][ > booking_id < ] => Obj( 'sql__booking_dates__arr':[
790 * [ >seconds< ] => > SQL DATE <
791 * [1693303211] => 2023-08-29 10:00:01
792 * [1693353600] => 2023-08-30 00:00:00
793 * [1693483192] => 2023-08-31 12:00:02
794 * ]
795 * , ... )
796 * @param array $params = array [
797 'sql_dates_arr' = [
798 [0] => stdClass Object (
799 [booking_date] => 2023-08-08 10:00:01
800 [approved] => 1
801 [date_res_type] =>
802 [booking_id] => 45
803 [form] => selectbox-one^rangetime2^10:00 - 12:00~text^...
804 [parent] => 0
805 [prioritet] => 20
806 [type] => 2
807 )
808 [1] => stdClass Object (
809 [booking_date] => 2023-08-08 10:00:01
810 [approved] => 0
811 [date_res_type] =>
812 [booking_id] => 46
813 [form] => selectbox-one^rangetime10^10:00 - 12:00~text^...
814 [parent] => 2
815 [prioritet] => 1
816 [type] => 10
817 ), ...
818 , ...]
819 , 'is_sort__dates_arr' => true
820 , 'is_apply__check_in_out__10s' => true
821 ]
822 *
823 * @return array = [ > resource_id < ][ > booking_id < ] => obj( ... )
824
825 Example:
826 [
827 [3] = [
828 [64] = obj{
829 booking_date = "2023-09-26 14:00:01"
830 approved = "0"
831 date_res_type = null
832 booking_id = "64"
833 form = "text^selected_short_dates_hint3^...
834 parent = "0"
835 prioritet = "30"
836 type = "3"
837 __summary__booking = [
838 sql__booking_dates__arr = [ 1695736811 = "2023-09-26 14:00:01"
839 1695772800 = "2023-09-27 00:00:00"
840 1695902392 = "2023-09-28 12:00:02"
841 ]
842 ]
843 }
844 [47] => stdClass Object(...)
845 ...
846 ]
847 ...
848 ]
849 *
850 *
851 * Each such booking is date object with additional property: -> __summary__booking[ 'sql__booking_dates__arr' ]
852 * It is array of ALL Dates (in SQL date format) for specific booking
853 * Then if needed, we extend booked dates on specific number of times or hours/minutes
854 *
855 *
856 * Relative this: ['__summary__booking']['sql__booking_dates__arr'] = [
857 1695736811 = "2023-09-26 14:00:01"
858 1695772800 = "2023-09-27 00:00:00"
859 1695902392 = "2023-09-28 12:00:02"
860 ]
861 * '1695736811' - timestamp of check in/out dates on 10 seconds less/higher than SQL date '2023-09-26 14:00:01'
862 *
863 */
864 function wpbc_support__transform__into__resource_booking_dates__arr( $params ){
865
866 $defaults = array(
867 'sql_dates_arr' => array()
868 , 'is_sort__dates_arr' => true
869 , 'is_apply__check_in_out__10s' => true
870 );
871 $params = wp_parse_args( $params, $defaults );
872
873
874 $result_arr = array();
875
876 foreach ( $params['sql_dates_arr'] as $date_object ) {
877
878 $booking_id = $date_object->booking_id; // '43'
879 $resource_id = ( ! empty( $date_object->date_res_type ) ) ? $date_object->date_res_type : $date_object->type; // '12'
880
881 if ( empty( $result_arr[ $resource_id ] ) ) { $result_arr[ $resource_id ] = array(); }
882 if ( empty( $result_arr[ $resource_id ][$booking_id] ) ) {
883
884 $result_arr[ $resource_id ][$booking_id] = $date_object;
885 $result_arr[ $resource_id ][$booking_id]->__summary__booking = array( 'sql__booking_dates__arr' => array() ); // New '__summary__booking' property
886 }
887
888 // Get seconds timestamp
889 $in_seconds = wpbc_convert__sql_date__to_seconds( $date_object->booking_date, $params['is_apply__check_in_out__10s'] );
890
891 $result_arr[ $resource_id ][ $booking_id ]->__summary__booking[ 'sql__booking_dates__arr' ][ $in_seconds ] = $date_object->booking_date;
892
893
894 // Sort new array with dates
895 if ( $params['is_sort__dates_arr'] ) {
896 ksort( $result_arr[ $resource_id ][ $booking_id ]->__summary__booking[ 'sql__booking_dates__arr' ] );
897 }
898 }
899
900 return $result_arr;
901 }
902
903
904 /**
905 * Transform Into: ['2024-01-28'][ > resource_id < ][ > booking_id < ][ > only_time_seconds_int < ] => obj( booking_date: "2024-01-28 10:00:01", ... )
906 *
907 * @param array $params = [
908 * 'is_apply__check_in_out__10s' => true
909 * 'resource_booking_dates_arr' => array = [ > resource_id < ][ > booking_id < ] => obj( ... )
910 * ]
911 *
912 * Example:
913 *
914 * $params['resource_booking_dates_arr'] = [
915 * [3] = [
916 * [64] = obj{
917 * booking_date = "2023-09-26 14:00:01"
918 * approved = "0"
919 * date_res_type = null
920 * booking_id = "64"
921 * form = "text^selected_short_dates_hint3^...
922 * parent = "0"
923 * prioritet = "30"
924 * type = "3"
925 * __summary__booking = [
926 * sql__booking_dates__arr = [ 1695736811 = "2023-09-26 14:00:01"
927 * 1695772800 = "2023-09-27 00:00:00"
928 * 1695902392 = "2023-09-28 12:00:02"
929 * ]
930 * ]
931 * }
932 * [47] => stdClass Object(...)
933 * ...
934 * ]
935 * ...
936 * ]
937 *
938 * @return array - ['2024-01-28'][ > resource_id < ][ > booking_id < ][ > only_time_seconds < ] => obj( booking_date: "2024-01-28 10:00:01", ... )
939 *
940 * Example:
941 * result = [
942 * 2023-08-01 = [
943 * 3 = [
944 * 62 = [
945 * 36011 = {stdClass}
946 * 43192 = {
947 * booking_date = "2023-08-01 12:00:02"
948 * approved = "0"
949 * date_res_type = null
950 * booking_id = "62"
951 * form = "selectbox-multiple^rangetime3[]^10:00 - 12:00~...
952 * parent = "0"
953 * prioritet = "30"
954 * type = "3"
955 * __summary__booking = [
956 * sql__booking_dates__arr = [
957 * 1690884011 = "2023-08-01 10:00:01"
958 * 1690891192 = "2023-08-01 12:00:02"
959 * ]
960 * ]
961 * }
962 * ]
963 * ]
964 * ]
965 * 2023-08-05 = [ ... ]
966 * ]
967 */
968 function wpbc_support__transform__into__date_resource_booking_timesec__arr( $params ){
969
970 $defaults = array(
971 'resource_booking_dates_arr' => array()
972 , 'is_apply__check_in_out__10s' => true
973 );
974 $params = wp_parse_args( $params, $defaults );
975
976
977 $result__arr = array();
978 foreach ( $params['resource_booking_dates_arr'] as $resource_id => $bookings_arr ) {
979
980 foreach ( $bookings_arr as $booking_id => $booking_obj ) {
981
982 $extended_dates_arr = ( isset( $booking_obj->__summary__booking['sql__booking_dates__arr__extended'] ) )
983 ? $booking_obj->__summary__booking['sql__booking_dates__arr__extended']
984 : $booking_obj->__summary__booking['sql__booking_dates__arr'];
985
986 foreach ( $extended_dates_arr as $extended_date_time_stamp => $extended_date_sql ) {
987
988 $new_extended_date_obj = wpbc_clone_array_of_objects( $booking_obj );
989 $new_extended_date_obj->booking_date = $extended_date_sql;
990
991 list( $date_without_time, $only_time ) = explode( ' ', $new_extended_date_obj->booking_date ); // '2024-01-28', '12:00:02'
992 $seconds_int = wpbc_convert__time_his__to_seconds( $only_time, $params['is_apply__check_in_out__10s'] ); // 43202
993
994 if ( ! isset( $result__arr[ $date_without_time ] ) ) { $result__arr[ $date_without_time ] = array(); }
995 if ( ! isset( $result__arr[ $date_without_time ][ $resource_id ] ) ) { $result__arr[ $date_without_time ][ $resource_id ] = array(); }
996 if ( ! isset( $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ] ) ) { $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ] = array(); }
997
998 $result__arr[ $date_without_time ][ $resource_id ][ $booking_id ][ $seconds_int ] = $new_extended_date_obj;
999 }
1000 }
1001 }
1002
1003 return $result__arr;
1004 /**
1005 2024-01-28 = [ > resource_id <
1006 12 => [ > booking_id <
1007 43 => [ > seconds <
1008 36001 => Obj[
1009 booking_date = "2024-01-28 10:00:01"
1010 date_res_type = null
1011 booking_id = "43"
1012 approved = "0"
1013 form = "selectbox-one^rangetime12^10:00 - 12:00~text^..."
1014 parent = "2"
1015 type = "12"
1016 ...
1017 ]
1018 43202 => Obj[
1019 type = "12"
1020 */
1021 }
1022
1023
1024 /**
1025 * Transform Into: ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ...
1026 *
1027 * @param array $params [
1028 * 'is_apply__check_in_out__10s' => true
1029 * 'date_resource_booking_timesec_arr' => [
1030 * 2023-08-01 = [
1031 * 3 = [
1032 * 62 = [
1033 * 36011 = {stdClass}
1034 * 43192 = {
1035 * booking_date = "2023-08-01 12:00:02"
1036 * approved = "0"
1037 * date_res_type = null
1038 * booking_id = "62"
1039 * form = "selectbox-multiple^rangetime3[]^10:00 - 12:00~...
1040 * parent = "0"
1041 * prioritet = "30"
1042 * type = "3"
1043 * __summary__booking = [
1044 * sql__booking_dates__arr = [
1045 * 1690884011 = "2023-08-01 10:00:01"
1046 * 1690891192 = "2023-08-01 12:00:02"
1047 * ]
1048 * ]
1049 * }
1050 * ]
1051 * ]
1052 * ]
1053 * 2023-08-05 = [ ... ]
1054 * ]
1055 *
1056 * @return array = ['2023-08-30'][ > resource_id < ][ > time_seconds_range < ] => booking_date_obj[ booking_id:45, approved:1, ...
1057 *
1058 * Example: [
1059 [2023-08-08] => [
1060 [2] => [
1061 [36011 - 86392] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 , .... )
1062 ]
1063 [10] => [
1064 [36011 - 86392] => stdClass Object ( [booking_date] => 2023-08-08 10:00:01 , .... )
1065 ]
1066 ]
1067 [2023-08-09] => [
1068 [2] => [
1069 [0] => stdClass Object ( [booking_date] => 2023-08-09 00:00:00, .... )
1070 ]
1071 [10] => [
1072 [36011 - 43192] => stdClass Object ( [booking_date] => 2023-08-30 12:00:02
1073 , ....
1074 __summary__booking = [
1075 sql__booking_dates__arr = [
1076 1690884011 = "2023-08-01 10:00:01"
1077 1690891192 = "2023-08-01 12:00:02"
1078 ]
1079 ]
1080 )
1081 ]
1082 ]
1083 ]
1084
1085 */
1086 function wpbc_support__transform__into__date_resource_timesec_range__arr( $params ){
1087
1088 $defaults = array(
1089 'date_resource_booking_timesec_arr' => array()
1090 , 'is_apply__check_in_out__10s' => true
1091 );
1092 $params = wp_parse_args( $params, $defaults );
1093
1094
1095 $result__arr = array();
1096
1097 foreach ( $params[ 'date_resource_booking_timesec_arr' ] as $a_only_date => $a_resources_arr ) { // '2023-07-25' => array( resource_id => bookings_arr )
1098
1099 foreach ( $a_resources_arr as $a_resource_id => $a_bookings_arr ) { // 1 => array( booking_id => times_arr )
1100
1101 foreach ( $a_bookings_arr as $a_booking_id => $a_seconds_arr_in_1_booking ) { // 10 => array ( second => stdObj( booking_date obj from DB )
1102
1103 if ( ! isset( $result__arr[ $a_only_date ] ) ) { $result__arr[ $a_only_date ] = array(); }
1104 if ( ! isset( $result__arr[ $a_only_date ][ $a_resource_id ] ) ) { $result__arr[ $a_only_date ][ $a_resource_id ] = array(); }
1105
1106 // Check all TIMES for SAME booking:
1107 $all_seconds_for_this_booking_arr = array();
1108
1109 foreach ( $a_seconds_arr_in_1_booking as $a_second => $a_booking_obj ) { // 0 => stdObj( booking_date obj from DB )
1110 $all_seconds_for_this_booking_arr[] = $a_second;
1111 }
1112
1113 /**
1114 * [ 36011 ] -> '36011 - 86392' | [36011, 43192] -> '36011 - 43192'
1115 *
1116 * In case if we have only start time or end time for specific SAME Booking, then we need to fill times: .. - 10:00 or 14:00 - ..
1117 */
1118 $all_seconds__key__time_range = wpbc__get_time_range__from_times_arr( $all_seconds_for_this_booking_arr );
1119
1120
1121 // For debugging only ! -------------------------------------------------------------------------------
1122 $test_unexpected = explode( '-', $all_seconds__key__time_range );
1123 if ( count( $test_unexpected ) > 2 ) {
1124 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1125 echo "WPBC. Unexpected situation. We have more than 2 times for the booking {$a_booking_id}: {$all_seconds__key__time_range}";
1126 debuge( '$a_only_date, $a_resource_id, $a_booking_id, $all_seconds_for_this_booking_arr', $a_only_date, $a_resource_id, $a_booking_id, $all_seconds_for_this_booking_arr, __FILE__, __LINE__ );
1127 }
1128 // For debugging only ! -------------------------------------------------------------------------------
1129
1130 $result__arr[ $a_only_date ][ $a_resource_id ][ $all_seconds__key__time_range ] = $a_booking_obj;
1131 }
1132 }
1133 }
1134
1135 return $result__arr;
1136 }
1137
1138
1139 /**
1140 * Transform [ 36011 ] -> '36011 - 86392' | [36011, 43192] -> '36011 - 43192'
1141 *
1142 * @param array $all_seconds_for_this_booking_arr [ 36011 ] [36011, 43192]
1143 *
1144 * @return string '36011 - 86392' '36011 - 43192'
1145 */
1146 function wpbc__get_time_range__from_times_arr( $all_seconds_for_this_booking_arr ){
1147
1148 // In case if we have only start time or end time for specific SAME Booking, then we need to fill times: .. - 10:00 or 14:00 - ..
1149 if ( 1 == count( $all_seconds_for_this_booking_arr ) ) {
1150
1151 $seconds__this__booking = $all_seconds_for_this_booking_arr[0];
1152 //$is_check_in_out__or_full = $seconds__this__booking % 10; // 1, 2 (not 0)
1153
1154 $is_check_in_out__or_full = substr( ( (string) $seconds__this__booking ), -1 ); // '1', '2' (not '0')
1155
1156 if ( '1' == $is_check_in_out__or_full ) {
1157 $all_seconds_for_this_booking_arr = array( $seconds__this__booking, WPBC_FULL_DAY_TIME_OUT ); // 24 hours - 10 seconds + 2 seconds (2 sec. - because check out)
1158 }
1159 if ( '2' == $is_check_in_out__or_full ) {
1160 $all_seconds_for_this_booking_arr = array( WPBC_FULL_DAY_TIME_IN, $seconds__this__booking ); // + 1 second (1 sex. - because check in)
1161 }
1162 }
1163
1164 if ( count( $all_seconds_for_this_booking_arr ) > 2 ) {
1165 // Non standard situation ??? !!!
1166 }
1167
1168 $all_seconds__key__time_range = implode( ' - ', $all_seconds_for_this_booking_arr );
1169
1170 return $all_seconds__key__time_range;
1171 }
1172
1173
1174
1175 // ---------------------------------------------------------------------------------------------------------------------
1176 // Get READABLE_DATES_ARR & create WPBC_BOOKING_DATE for each bookings in [ > resource_id < ][ > booking_id < ][ ... ]
1177 // ---------------------------------------------------------------------------------------------------------------------
1178
1179 // GOOD
1180 /**
1181 * Loop all Resources / Bookings to set 'WPBC_BOOKING_DATE' Objects: [ > resource_id < ][ > booking_id < ] => ['__summary__booking']['sql__booking_dates__arr']['_readable_dates'] = [ 2023-09-01: [ 0: "00:00:01 - 24:00:00" ] , ... ]
1182 *
1183 * @param $resources__booking_id__obj = [ > resource_id < ][ > booking_id < ] => obj( ... )
1184 *
1185 * @return $resources__booking_id__obj = [
1186 * 3 = [
1187 * 62 = {stdClass}
1188 * 63 = {
1189 * booking_date = "2023-09-01 00:00:00"
1190 * approved = "0"
1191 * date_res_type = null
1192 * booking_id = "63"
1193 * form = "text^selected_short_dates_hint3^September 1, 2023...
1194 * parent = "0"
1195 * prioritet = "30"
1196 * type = "3"
1197 * __summary__booking = [
1198 * sql__booking_dates__arr = [
1199 *
1200 * ....
1201 */
1202 function wpbc__in_all_bookings__create_WPBC_BOOKING_DATE( $resources__booking_id__obj ){
1203
1204
1205 // [ > resource_id < ][ > booking_id < ] => obj( ['__summary__booking']['sql__booking_dates__arr'] [ ... , [ ' >seconds< '] => ' > SQL DATE < ' , ... ] )
1206 foreach ( $resources__booking_id__obj as $resource_id => $bookings_arr ) {
1207
1208 foreach ( $bookings_arr as $booking_id => $booking_obj ) {
1209
1210 $readable_datestimeslots_arr = wpbc__get__readable_dates_arr__from_timestamp_arr( $booking_obj->__summary__booking[ 'sql__booking_dates__arr' ] );
1211
1212 // New Dates Object - for this booking ID
1213 $boking_dates_obj = new WPBC_BOOKING_DATE( $readable_datestimeslots_arr );
1214
1215 $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj' ] = $boking_dates_obj;
1216
1217 if ( $boking_dates_obj->is_debug ) {
1218 $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__24_hour_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_24_hour_arr' );
1219 $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__seconds_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_seconds_arr' );
1220 $resources__booking_id__obj[$resource_id][$booking_id]->__summary__booking[ '__dates_obj__timestamps_arr' ] = $boking_dates_obj->loop_all_dates( 'get_times__as_timestamps_arr' );
1221 }
1222
1223 }
1224 }
1225
1226 return $resources__booking_id__obj;
1227 }
1228
1229
1230 // =====================================================================================================================
1231 // Transform SQL dates INTO Readable time-slots by Dates
1232 //
1233 // All these below 5 functions required for transformation booked SQL dates: [ 1690884011 : "2023-08-01 10:00:01", ... ]
1234 // Into readable time slots by dates: [ '2023-08-01': [ "10:00:01 - 12:00:02" ], '2023-08-05': [ "10:00:01 - 12:00:02" ] ]
1235 // =====================================================================================================================
1236
1237 // GOOD
1238 /**
1239 * Transform SQL dates INTO Readable time-slots by Dates. Transform linear [ 1690884011 = "2023-08-01 10:00:01" , ... ] -> [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...]
1240 *
1241 * @param array $sql_dates_arr [
1242 * 1690884011 = "2023-08-01 10:00:01"
1243 * 1690891192 = "2023-08-01 12:00:02"
1244 * ...
1245 * ]
1246 *
1247 * @return array
1248 * [
1249 * 2023-08-01 = [ 0 = "10:00:01 - 12:00:02" ]
1250 * 2023-08-05 = [ 0 = "10:00:01 - 12:00:02" ]
1251 * ]
1252 * OR
1253 * [
1254 * 2023-09-01 = [ 0 = "00:00:01 - 24:00:00" ]
1255 * 2023-09-03 = [ 0 = "00:00:00 - 24:00:00" ]
1256 * 2023-09-14 = [ 0 = "00:00:00 - 24:00:02" ]
1257 * ]
1258 *
1259 */
1260 function wpbc__get__readable_dates_arr__from_timestamp_arr( $sql_dates_arr ){
1261
1262 // Full Dates
1263 $is_all_dates_full = wpbc_is_all__fulldays__in_dates_arr( $sql_dates_arr );
1264 if ( $is_all_dates_full ) {
1265 $sql_dates_arr = wpbc__add_to__fulldays__check_in_out( $sql_dates_arr );
1266 }
1267
1268 /**
1269 * Convert timestamps to -> [ '2023-08-01' : [ 36011 = "10:00:01", 43192 = "12:00:02" ] , '2023-08-05' : [...] ... ]
1270 */
1271 $times_arr___by_dates = wpbc__transform__timestamp_arr__in__times_by_dates__arr( $sql_dates_arr );
1272
1273 /**
1274 * Convert to our concept times: -> [ '2023-08-01' : [ 0 = "10:00:01 - 12:00:02" ], '2023-08-05' : [ 0 = "10:00:01 - 12:00:02" ] ]
1275 */
1276 $times_arr___by_dates = wpbc__transform__times_by_dates__in__readable_dates_arr( $times_arr___by_dates );
1277
1278 return $times_arr___by_dates;
1279 }
1280
1281
1282 // GOOD
1283 /**
1284 * Convert times by dates: [ '2023-08-01': [ 36011: "10:00:01", ... ] ... ] -> [ '2023-08-01': [ 0: "10:00:01 - 12:00:02" ], '2023-08-05': [ 0:"10:00:01 - 12:00:02" ] ...]
1285 *
1286 * @param $times_arr___by_dates = [
1287 * 2023-08-01 = [
1288 * 36001 = "10:00:01"
1289 * 43202 = "12:00:02"
1290 * ]
1291 * 2023-08-05 = [
1292 * 36001 = "10:00:01"
1293 * 43202 = "12:00:02"
1294 * ]
1295 * ]
1296 *
1297 * @return array
1298 * [
1299 * 2023-08-01 = [ 0 = "10:00:01 - 12:00:02" ]
1300 * 2023-08-05 = [ 0 = "10:00:01 - 12:00:02" ]
1301 * ]
1302 * OR
1303 * [
1304 * 2023-09-01 = [ 0 = "00:00:01 - 24:00:00" ]
1305 * 2023-09-03 = [ 0 = "00:00:00 - 24:00:00" ]
1306 * 2023-09-14 = [ 0 = "00:00:00 - 24:00:02" ]
1307 * ]
1308 *
1309 *
1310 *
1311 *
1312 * from this:
1313 *
1314 * $times_arr___by_dates = [
1315 * 2023-09-01 = [
1316 * 1 = "00:00:01"
1317 * ]
1318 * 2023-09-03 = [
1319 * 0 = "00:00:00"
1320 * ]
1321 * 2023-09-14 = [
1322 * 86402 = "24:00:02"
1323 * ]
1324 * ]
1325 * OR this:
1326 * [
1327 * 2023-08-01 = [
1328 * 36001 = "10:00:01"
1329 * 43202 = "12:00:02"
1330 * ]
1331 * 2023-08-05 = [
1332 * 36001 = "10:00:01"
1333 * 43202 = "12:00:02"
1334 * ]
1335 * ]
1336 * OR
1337 * [
1338 * 2023-09-26 = [
1339 * 50401 = "14:00:01"
1340 * ]
1341 * 2023-09-27 = [
1342 * 0 = "00:00:00"
1343 * ]
1344 * 2023-09-28 = [
1345 * 43202 = "12:00:02"
1346 * ]
1347 * ]
1348 * INTO
1349 *
1350 * - Time-Slots A - B '10:00:01 - 12:00:02'
1351 *
1352 * - Check in A - ... '14:00:01 - 24:00:00'
1353 * - Check out ... - B '00:00:00 - 12:00:02'
1354 *
1355 * - Full day ... - ... '00:00:00 - 24:00:00'
1356 *
1357 * - Full IN ..1 - ... '00:00:01 - 24:00:00'
1358 * - Full OUT ... - ..2 '00:00:00 - 24:00:02'
1359 *
1360 */
1361 function wpbc__transform__times_by_dates__in__readable_dates_arr( $times_arr___by_dates ) {
1362
1363
1364 foreach ( $times_arr___by_dates as $only_date_key => $times_arr ) {
1365
1366 /**
1367 * Because it's dates_times from 1 booking, then in each date we have only 1 or 2 times.
1368 */
1369
1370 if ( 1 == count( $times_arr___by_dates[ $only_date_key ] ) ) {
1371
1372 // One Loop only, to get the $time_only_24hours value
1373 foreach ( $times_arr___by_dates[ $only_date_key ] as $time_only_seconds => $time_only_24hours ) {
1374
1375 if ( '00:00:00' == $time_only_24hours ) { // Full Day
1376
1377 $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', '24:00:00' );
1378
1379 } else if( '00:00:01' == $time_only_24hours ) { // Check In ___ full day
1380
1381 $times_arr___by_dates[ $only_date_key ] = array( '00:00:01', '24:00:00' );
1382
1383 } else if( '24:00:02' == $time_only_24hours ) { // Check Out ___ full day
1384
1385 $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', '24:00:02' );
1386 } else {
1387
1388 // Check in / out
1389 $is_check_in_out__or_full = substr( $time_only_24hours, -1 ); // '1', '2' (not '0')
1390
1391 if ( '1' == $is_check_in_out__or_full ) { // Check In
1392
1393 $times_arr___by_dates[ $only_date_key ] = array( $time_only_24hours, '24:00:00' );
1394
1395 } else if ( '2' == $is_check_in_out__or_full ) { // Check Out
1396
1397 $times_arr___by_dates[ $only_date_key ] = array( '00:00:00', $time_only_24hours );
1398
1399 } else { // Unexpected ?
1400 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1401 echo "WPBC. Unexpected data value: {$time_only_24hours} Timestamp ended with value different than: 1|2 for the day {$only_date_key} in one booking ";
1402 }
1403
1404 }
1405 }
1406 }
1407
1408
1409 if ( 2 == count( $times_arr___by_dates[ $only_date_key ] ) ) {
1410
1411 // Time slots or already defined check in / out times
1412 $times_his_values = implode( ' - ', $times_arr___by_dates[ $only_date_key ] );
1413
1414 $times_arr___by_dates[ $only_date_key ] = array();
1415 $times_arr___by_dates[ $only_date_key ][] = $times_his_values;
1416
1417 } else {
1418
1419 // Something wrong ???? Check it.
1420 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1421 echo "WPBC. Unexpected data value. We have more than 2 time slots for single day {$only_date_key} in one booking ";
1422 debuge( $times_arr___by_dates, __FILE__, __LINE__ );
1423 }
1424 }
1425
1426 return $times_arr___by_dates;
1427 }
1428
1429
1430 // GOOD
1431 /**
1432 * Transform linear [ 1690884011 = "2023-08-01 10:00:01" , ... ] -> [ '2023-08-01' : [ 36011 = "10:00:01", 43192 = "12:00:02", ... ] , '2023-08-05' : [...] ... ]
1433 *
1434 * @param array $datetimestamps_datesql_arr [
1435 * 1690884011 = "2023-08-01 10:00:01"
1436 * 1690891192 = "2023-08-01 12:00:02"
1437 * 1691229611 = "2023-08-05 10:00:01"
1438 * 1691236792 = "2023-08-05 12:00:02"
1439 * ]
1440 *
1441 * @return array [
1442 * 2023-08-01 = [
1443 * 36011 = "10:00:01"
1444 * 43192 = "12:00:02"
1445 * 2023-08-05 = [
1446 * 36011 = "10:00:01"
1447 * 43192 = "12:00:02"
1448 * ]
1449 */
1450 function wpbc__transform__timestamp_arr__in__times_by_dates__arr( $datetimestamps_datesql_arr ) {
1451
1452 ksort( $datetimestamps_datesql_arr );
1453
1454 $by_dates__timestamp_datesql__arr = array();
1455
1456 foreach ( $datetimestamps_datesql_arr as $this_datetime_stamp => $this_date_sql ) {
1457
1458 // '2023-08-01' '10:00:01'
1459 list( $only_day_sql, $only_time_sql ) = explode( ' ', $this_date_sql );
1460
1461 $only_day_sql = trim( $only_day_sql ); // '2023-08-01'
1462 $only_time_sql = trim( $only_time_sql ); // '10:00:01'
1463
1464 if ( ! isset( $by_dates__timestamp_datesql__arr[ $only_day_sql ] ) ) {
1465 $by_dates__timestamp_datesql__arr[ $only_day_sql ] = array(); // [ '2023-08-01': [] ]
1466 }
1467
1468 $only_time_in_sec = wpbc_convert__time_his__to_seconds( $only_time_sql, false ); // 36001, false <- $is_apply__check_in_out__10s
1469
1470 // '2023-08-01' 36001 '10:00:01'
1471 $by_dates__timestamp_datesql__arr[ $only_day_sql ][ $only_time_in_sec ] = $only_time_sql;
1472 }
1473
1474 return $by_dates__timestamp_datesql__arr;
1475 }
1476
1477
1478 // GOOD
1479 /**
1480 * Add to the first and last dates the check in/out times
1481 *
1482 * @param array $sql_dates_arr
1483 *
1484 * @return array $sql_dates_arr
1485 */
1486 function wpbc__add_to__fulldays__check_in_out( $sql_dates_arr ){
1487
1488 // Add check in/out to first and last dates !
1489 $is_apply__check_in_out__10s = false;
1490
1491 // EVEN if we have only 1 day, it has to work! from
1492 $all_timestamps_arr = array_keys( $sql_dates_arr );
1493
1494
1495 // CHECK_IN date, - lowest timestamp: -------------------------------------------------------------------
1496 $check_in_timestamp = min( $all_timestamps_arr );
1497 // Remove this date
1498 if ( isset( $sql_dates_arr[ $check_in_timestamp ] ) ) { unset( $sql_dates_arr[ $check_in_timestamp ] ); }
1499
1500 // Add new date: see definition of WPBC_FULL_DAY_TIME_IN <- 00:00:01
1501 $real__check_in__date_sql = gmdate( 'Y-m-d', $check_in_timestamp ) . ' 00:00:01';
1502 $real__check_in_timestamp_new = wpbc_convert__sql_date__to_seconds( gmdate( 'Y-m-d', $check_in_timestamp ) . ' 00:00:01', $is_apply__check_in_out__10s );
1503 $sql_dates_arr[ $real__check_in_timestamp_new ] = $real__check_in__date_sql;
1504
1505
1506 // CHECK_OUT date, - highest timestamp: ------------------------------------------------------------------
1507 $check_out_timestamp = max( $all_timestamps_arr );
1508 // Remove this date
1509 if ( isset( $sql_dates_arr[ $check_out_timestamp ] ) ) {
1510 unset( $sql_dates_arr[ $check_out_timestamp ] );
1511 }
1512 // Add new date: see definition of WPBC_FULL_DAY_TIME_OUT <- 23:59:52
1513 $real__check_out__date_sql = gmdate( 'Y-m-d', $check_out_timestamp ) . ' 24:00:02';
1514 $real__check_out_timestamp_new = wpbc_convert__sql_date__to_seconds( gmdate( 'Y-m-d', $check_out_timestamp ) . ' 23:59:52', $is_apply__check_in_out__10s );
1515 $sql_dates_arr[ $real__check_out_timestamp_new ] = $real__check_out__date_sql;
1516
1517 // Sort such dates again, because we changed the order ---------------------------------------------------
1518 ksort( $sql_dates_arr );
1519
1520 return $sql_dates_arr;
1521 }
1522
1523
1524 // GOOD
1525 /**
1526 * Check if all dates in array it is full dates e.g. 2023-07-25 00:00:00
1527 * and not the check in/out, such as 2023-07-25 12:00:02
1528 *
1529 * @param array $booking_sqldates_arr [
1530 * 1690884011 = "2023-08-01 10:00:01"
1531 * 1690891192 = "2023-08-01 12:00:02"
1532 * ...
1533 * ]
1534 *
1535 * @return bool
1536 */
1537 function wpbc_is_all__fulldays__in_dates_arr( $booking_sqldates_arr ) {
1538
1539 $is_all_dates_full = true;
1540
1541 foreach ( $booking_sqldates_arr as $date_sql ) {
1542
1543 $is_check_in_out__or_full = (string) $date_sql;
1544 $is_check_in_out__or_full = substr( $is_check_in_out__or_full, - 1 ); // '0', '1', '2' from "2023-08-01 12:00:02"
1545 if ( '0' !== $is_check_in_out__or_full ) {
1546 $is_all_dates_full = false;
1547 break;
1548 }
1549 }
1550
1551 return $is_all_dates_full;
1552 }
1553
1554 // =====================================================================================================================
1555
1556
1557 /**
1558 * Convert [ "2023-10-20", "2023-10-25", "2023-11-23" ] -> [ '20.10.2023', '25.10.2023', '23.11.2023' ]
1559 *
1560 * @param $dates_arr__yyyy_mm_dd [ "2023-10-20", "2023-10-25", "2023-11-23" ]
1561 *
1562 * @return [] [ '20.10.2023', '25.10.2023', '23.11.2023' ]
1563 */
1564 function wpbc_convert_dates_arr__yyyy_mm_dd__to__dd_mm_yyyy( $dates_arr__yyyy_mm_dd ) {
1565
1566 $dates_arr__dd_mm_yyyy = array_map( function ( $value ) {
1567 $value_arr = explode( '-', $value );
1568 return ( count( $value_arr ) > 2 )
1569 ? $value_arr[2] . '.' . $value_arr[1] . '.' . $value_arr[0]
1570 : '';
1571 }
1572 , $dates_arr__yyyy_mm_dd ); // [ "2023-10-20", "2023-10-25", "2023-11-23" ]
1573
1574 $dates_arr__dd_mm_yyyy = array_filter( $dates_arr__dd_mm_yyyy ); // All entries of array equal to FALSE (0, '', '0' ) will be removed.
1575 return $dates_arr__dd_mm_yyyy;
1576 }
1577
1578
1579 /**
1580 * Convert '20.10.2023, 25.10.2023, 23.10.2023' -> '2023-10-20,2023-10-23,2023-10-25'
1581 *
1582 * or even: '20.10.2023 - 23.10.2023' -> '2023-10-20,2023-10-21,2023-10-22,2023-10-23'
1583 *
1584 * @param $str_dates__dd_mm_yyyy '20.10.2023, 25.10.2023, 23.10.2023'
1585 *
1586 * @return string '2023-10-20,2023-10-23,2023-10-25'
1587 */
1588 function wpbc_convert_dates_str__dd_mm_yyyy__to__yyyy_mm_dd( $str_dates__dd_mm_yyyy ) {
1589
1590 $str_dates__dd_mm_yyyy = str_replace( '|', ',', $str_dates__dd_mm_yyyy ); // Check this for some old versions of plugin
1591
1592 if ( strpos( $str_dates__dd_mm_yyyy, ' - ' ) !== false ) { // Recheck for any type of Range Days Formats
1593 $arr_check_in_out_dates = explode( ' - ', $str_dates__dd_mm_yyyy );
1594 $str_dates__dd_mm_yyyy = wpbc_get_comma_seprated_dates_from_to_day( $arr_check_in_out_dates[0], $arr_check_in_out_dates[1] );
1595 }
1596
1597 $dates_arr__dd_mm_yyyy = explode( ',', $str_dates__dd_mm_yyyy ); // Create dates Array
1598
1599 $dates_arr__yyyy_mm_dd = array_map( function ( $value ) {
1600 $value = trim( $value );
1601 $value_arr = explode( '.', $value );
1602 return ( count( $value_arr ) > 2 )
1603 ? $value_arr[2] . '-' . $value_arr[1] . '-' . $value_arr[0]
1604 : '';
1605 }
1606 , $dates_arr__dd_mm_yyyy ); // [ '20.10.2023', '25.10.2023', '23.11.2023' ]
1607 $dates_arr__yyyy_mm_dd = array_filter( $dates_arr__yyyy_mm_dd ); // All entries of array equal to FALSE (0, '', '0' ) will be removed.
1608 // Remove duplicates
1609 $dates_arr__yyyy_mm_dd = array_unique( $dates_arr__yyyy_mm_dd );
1610
1611 // Sort Dates
1612 sort( $dates_arr__yyyy_mm_dd );
1613
1614 $dates_str__yyyy_mm_dd = implode( ',', $dates_arr__yyyy_mm_dd );
1615
1616 return $dates_str__yyyy_mm_dd; // '2023-10-20,2023-10-23,2023-10-25'
1617 }
1618
1619