Setting up information about the operating hours of 1C-Bitrix stores

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1212
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    815
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    565
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    980

Setting up store hours information in 1C-Bitrix

A user sees "Pickup" button and navigates to the list of points. Beside each address — nothing about hours, or worse: static text "Mon-Fri 9:00-18:00" that's accurate until the first change, but nobody knows which file to edit. Task — store hours in structured form and show actual "open/closed" status in real time.

Schedule storage structure

Standard table b_sale_store contains field SCHEDULE type TEXT — arbitrary string without structure. This doesn't work for machine processing.

Right approach: store schedule as JSON. Either add custom field to pickup point (via CUserTypeEntity with ENTITY_ID = 'SALE_STORE'), or create separate table:

CREATE TABLE bl_store_schedule (
    id          SERIAL PRIMARY KEY,
    store_id    INT NOT NULL REFERENCES b_sale_store(ID) ON DELETE CASCADE,
    day_of_week SMALLINT NOT NULL,  -- 1=Mon, 7=Sun
    open_time   TIME,               -- NULL = closed that day
    close_time  TIME,
    is_closed   BOOLEAN DEFAULT FALSE,
    UNIQUE (store_id, day_of_week)
);

This structure allows storing different schedule for each day of week and explicitly marking closed days via is_closed = TRUE.

Exceptions: holidays and temporary changes

Besides standard schedule you need exceptions table:

CREATE TABLE bl_store_schedule_exception (
    id         SERIAL PRIMARY KEY,
    store_id   INT NOT NULL,
    date       DATE NOT NULL,
    open_time  TIME,
    close_time TIME,
    is_closed  BOOLEAN DEFAULT FALSE,
    note       VARCHAR(255),
    UNIQUE (store_id, date)
);

When calculating "open/closed" status, first check bl_store_schedule_exception for today's date, and only if no exception take data from bl_store_schedule by day of week number.

Calculating current status

function getStoreStatus(int $storeId): array
{
    $connection = \Bitrix\Main\Application::getConnection();
    $now  = new \DateTime('now', new \DateTimeZone('Europe/Minsk'));
    $date = $now->format('Y-m-d');
    $time = $now->format('H:i:s');
    $dow  = (int)$now->format('N'); // 1=Mon, 7=Sun

    // First check exception for today
    $exception = $connection->query(
        "SELECT * FROM bl_store_schedule_exception
         WHERE store_id = {$storeId} AND date = '{$date}'"
    )->fetch();

    $schedule = $exception ?: $connection->query(
        "SELECT * FROM bl_store_schedule
         WHERE store_id = {$storeId} AND day_of_week = {$dow}"
    )->fetch();

    if (!$schedule || $schedule['is_closed']) {
        return ['status' => 'closed', 'label' => 'Closed'];
    }

    $isOpen = $time >= $schedule['open_time'] && $time < $schedule['close_time'];

    return [
        'status' => $isOpen ? 'open' : 'closed',
        'label'  => $isOpen
            ? 'Open until ' . substr($schedule['close_time'], 0, 5)
            : 'Opens at ' . substr($schedule['open_time'], 0, 5),
        'open'   => $schedule['open_time'],
        'close'  => $schedule['close_time'],
    ];
}

Time zones for multi-location chains

If the chain spans multiple time zones — add timezone field to b_sale_store (custom field or extension). When calculating status create DateTime with correct DateTimeZone for each store. Storing schedule in UTC and converting for display is a common mistake that breaks during daylight saving time transitions.

Display in component and caching

Store list component bitrix:sale.store.list is extended via result_modifier.php. In it call getStoreStatus() for each point and add data to $arResult. Caching: "open/closed" status changes twice a day (opening and closing), so cache TTL — no more than 30 minutes. You can use tag cache with tag store_{$storeId}_schedule and invalidate it when updating schedule in admin.

What we configure

  • Tables bl_store_schedule and bl_store_schedule_exception
  • Administrative interface for editing schedule (update agent or form in admin section)
  • Status calculation function with time zone support
  • Extension of bitrix:sale.store.list component via result_modifier.php
  • Caching with TTL 30 minutes and invalidation on schedule change