Вычисление количества дней, которые попадают между предварительно определенными диапазонами дат - PullRequest
2 голосов
/ 23 февраля 2011

это сложная ситуация. У меня есть система бронирования номеров.

Дело в том, что цены за номера не сохраняются как одно значение, а основаны на периоде. Как и в комнате, может быть одна дневная ставка в период с сентября по декабрь и дополнительная ставка с марта по август, в то время как базовая ставка может быть другой.

Таблица ставок выглядит так:

ROOMID | RATE | PERIOD_START | PERIOD_END

Предположим, что стоимость номера за период с 1 марта по 31 марта составляет 20 долларов в день, а стоимость номера за тот же номер с 15 апреля по 30 мая - 30 долларов, за исключением того, что ставка является фиксированной ставкой в ​​15 долларов. /день.

Если этот номер забронирован одним клиентом в период с 15 марта по 10 мая, общая стоимость составит:

15th March - 31st march charged at 20 Dollars/day = 16x20
1st April - 14th April charged at 15 Dollars/day = 14x15
15th April - 10th May charged at 30 Dollars/day = 25x30

Теперь, как я могу вычислить это значение в коде, мне нужно будет вычислить количество дней на основе периодов тарифов, если таковые имеются, иначе использовать для них базовую ставку. Это сложно, но так оно и есть. Я использую php MySQL

Ответы [ 5 ]

2 голосов
/ 24 февраля 2011

это возможный алгоритм решения:

  1. найти все периоды тарифов, которые имеют непустое пересечение с периодом бронирования
  2. для каждого периода тарифа, найденного в (1),вычислите количество дней в его пересечении с периодом бронирования и умножьте на курс периода
  3. оставшееся количество дней (т. е. продолжительность периода бронирования в днях за вычетом суммы всех дней, найденных в (2), равнадни базовой ставки

Re (1), чтобы определить, какие периоды тарифов пересекаются с периодом бронирования, обратите внимание, что 2 интервала (A,B) и (C,D) имеют пустое пересечение, если D < A or C > B, поэтомуВы можете просто отрицать это условие. Должно выглядеть примерно так:

SELECT * FROM rates 
   WHERE NOT (booking_end < period_start OR 
              booking_start > period_end)

Re (2), вам просто нужно найти количество дней между max(booking_start, period_start) и min(booking_end, period_end) включительно. Я уверен, что естьэто утилиты для работы с датами, но в худшем случае вы можете просто пройти через них.

Извините, но я не мастер SQL / php для написания реального кода ...:)

1 голос
/ 28 февраля 2011

В PHP вы можете использовать DateTime до для вычисления разницы интервал между двумя датами.

1 голос
/ 24 февраля 2011

Здесь только полусерьезный ответ.

Если вам нужен один SQL-запрос, вы можете сделать это:

SELECT SUM(IF(ISNULL(r.rate), 10, r.rate))
FROM days AS d
LEFT JOIN rates AS r ON d.d BETWEEN r.start AND r.end
  WHERE d.d BETWEEN '2011-03-15' and '2011-05-10';

Хитрость в том, что вам нужна таблица с именем "days"", который имеет одно поле даты d.Предварительно заполняйте эту таблицу, чтобы включать каждый день с этого момента и до вечности.Просто сделать с помощью скрипта;вам нужно только сохранить будущие бронируемые даты.

Обратите внимание, что вы должны быть осторожны при выборе даты начала и окончания.Например, если вы бронируете номер в период с 31 марта по 1 апреля, что именно это означает?

Это один день в 20 долларов и один день в 10 долларов?Или только один $ 20 в день?Или один день за 10 долларов?

Это само по себе не влияет на этот ответ, но влияет на то, как вы строите таблицу ставок и какие дни вы используете в качестве начала и конца.

Также в этой версии предполагается, что в поле ставок используется полный формат ГГГГ-ММ-ДД.Это не абсолютное требование, но если это всего лишь MM-DD, то вам нужно немного изменить соединение.

Лично я бы так не поступил.Вместо этого я просто перебрал бы дни в коде PHP, используя класс DateInterval, и запросил цену таким образом.

1 голос
/ 23 февраля 2011

Попробуйте это.

Это циклически повторяет каждый день в забронированном периоде, находит соответствующую таблицу из таблицы, а затем добавляет ее к общей сумме.

$Day="2011-03-15";
$End="2011-05-10";
$Periods=array(); // Filled with the Mysql rows - mysql_fetch_assoc()
$Total=0;

РЕДАКТИРОВАТЬ

Более оптимизировано.

foreach($Periods as $Period) {
    if($Day>=$Period['PERIOD_START']&&$Day<=$Period['PERIOD_END']) {
        while($Day<=$End&&$Day<=$Period['PERIOD_END']) {
            $Total+=$Period['RATE'];
            $Day=date('Y-m-d',strtotime("$Day +1 day"));
        }
    }
}
1 голос
/ 23 февраля 2011

Одним из возможных решений является создание таблицы с именем price_periods с датой начала, даты окончания и ценой и ссылкой на комнату.

Таким образом, таблица SQL будет выглядеть следующим образом.

PRICE_PERIODS

PPID | ROOM_ID | PP_START_DATE | PP_END_DATE | PP_PRICE
-------------------------------------------------------
1      2         09-20           10-20         15
2      2         10-21           11-20         20

Затем вы просто подсчитаете, на какие даты было сделано бронирование, поэтому предположим, что Лицо А хочет снять комнату с 10-11 до 10-25, ему придется заплатитьдля PRICE_PERIOD с идентификатором 1 до появления PP_END_DATE, а затем оплатить PRICE_PERIOD с идентификатором 2 до завершения бронирования.Так что дело в том, что у вас, вероятно, будет больше двух дат для работы в любое время.

Полагаю, ваша таблица бронирования выглядит примерно так:

БРОНИРОВАНИЕ

B_ID | ROOM_ID | USER_ID | START_DATE | END_DATE
------------------------------------------------
1      2         4         10-11        10-25

Вы должны будете сделать вычисления, но есть начало, которое, вероятно, сработает.

...