Igor Zaika Igor Zaika - 6 months ago 33
PHP Question

Parse Schema.org 'openingHours' string in PHP

I want to convert strings like this:


Mo,Tu,We,Th,Fr 12:00-18:00, Sa 12:00-16:00


to text like this:

Monday 12:00-18:00
Tuesday 12:00-18:00
Wednesday 12:00-18:00
Thursday 12:00-18:00
Friday 12:00-18:00
Saturday 12:00-16:00


Renaming days and adding linebrakes is not a problem, but how to add hours for each day in the group?

I did only this thing:
str_replace('0,', '0<br>', $opening_hours)
, I have no idea what else should be done to make required format of this text.

Answer

// test inputs
// $input = 'Mo,Tu 05:30-22:00, We,Th 06:00-22:00, Fr 06:00-20:00, Sa, Su 10:00-17:30';
// $input = 'Mo 8-18,Tu 8-18, We 8-18, Th 8 -18 ,Fr 8-18, Sa 10-16';
// $input = 'Mo ; Tu,We,Th,Fr,Sa 012:00-12:00';

$input = 'Mo,Tu,We,Th,Fr10:00-21:00,            Sa,Su13:00-19:00';


function parseOpeningHours($input)
{
    // normilize
    $weekdays = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

    $weekdayoptions = implode('|', array_unique($weekdays));

    $unwrapped_input = preg_replace_callback('/\b(' . $weekdayoptions . ')-(' . $weekdayoptions . ')/', function ($matches) use ($weekdays) {
        list (, $from, $to) = $matches;

        $from_idx = array_search($from, $weekdays);

        $to_idx = array_search($to, array_slice($weekdays, $from_idx));

        $unwrapped_range = implode(',', array_slice($weekdays, $from_idx, $to_idx + 1));
        return $unwrapped_range;

    }, $input);

    // find time range for each day of the week
    $result = [
        'Mo' => null,
        'Tu' => null,
        'We' => null,
        'Th' => null,
        'Fr' => null,
        'Sa' => null,
        'Su' => null,
    ];
    $offset = 0;
    while (preg_match('/\b(' . $weekdayoptions . ').*?(\d{1,2})(?::(\d{1,2}))?\s*-\s*(\d{1,2})(?::(\d{1,2}))?/', $unwrapped_input, $matches, PREG_OFFSET_CAPTURE, $offset)) {


        @list (, list ($weekday, $offset), list ($from_hh), list ($from_mm), list ($to_hh), list ($to_mm)) = $matches;

        // normalize the time range
        if ($from_mm == '') $from_mm = '00';
        if ($to_mm == '') $to_mm = '00';
        $time_range = "$from_hh:$from_mm-$to_hh:$to_mm";

        $result[$weekday] = $time_range;
        $offset += strlen($weekday);
    }

    return $result;
}

var_dump(parseOpeningHours($input));

test output:

xxxxxxxxx@xxxxxxxxx:~/xxxxxxxxx$ php test.php 
/xxxxxxxxx/test.php:55:
array(7) {
  'Mo' =>
  string(11) "10:00-21:00"
  'Tu' =>
  string(11) "10:00-21:00"
  'We' =>
  string(11) "10:00-21:00"
  'Th' =>
  string(11) "10:00-21:00"
  'Fr' =>
  string(11) "10:00-21:00"
  'Sa' =>
  string(11) "13:00-19:00"
  'Su' =>
  string(11) "13:00-19:00"
}