Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Посчитать количество рабочих дней 
:(
    Опции темы
Gold Dragon
Дата 24.1.2014, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



так это перебор получается?


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
capitan
Дата 24.1.2014, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 27.2.2005
Где: Москва

Репутация: 9
Всего: 13



Цитата(Gold Dragon @ 24.1.2014,  14:38)
так это перебор получается?

А чем не устраивает? У вас где данные лежат по датам договоров и сроках? Если в базе, тогда просто в таблицу добавляем поле, где пишем дату окончания договора. При заполнении, считаем и пишем. Какие проблемы? Зато считаем все точно, учитывая все, что угодно.

Это сообщение отредактировал(а) capitan - 24.1.2014, 14:43
PM MAIL WWW ICQ   Вверх
Gold Dragon
Дата 24.1.2014, 15:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



capitan, так проблем нет  smile просто я хотел что-то типа функции без перебора.. Я просто думаю что перебор всё же будет медленнее..

с перебором я написал для себя это: (вырезал из кода, т.ч. три метода)
Код

class LibDateTime
{
    /**
     * Возвращает конечную дату без учёта выходных
     *
     * @param string $date   : начальная дата
     * @param int    $days   : количество дней
     * @param string $format : формат возвращаемой даты
     *
     * @return string: дата окончания
     */
    public static function getEndDateWorking($date, $days, $format = 'd.m.Y')
    {
        while ($days) {
            $date = self::getDateAdd($date, 'P1D');
            if (self::formatDate($date, 'N') < 6) {
                $days--;
            }
        }
        return self::formatDate($date, $format);
    }

    /**
     * Прибавляет интервал к дате
     *
     * @param string $date     - дата
     * @param string $interval - интервал в формате ISO 8601, например, P5В (5 дней) или P3Y (3 года)
     *                         Y - Количество лет
     *                         M - Количество месяцев
     *                         D - Количество дней
     * @param string $format   - возвращаемый формат (по умолчанию  d.m.Y)
     *
     * @return string - дата в формате $format
     */
    public static function getDateAdd($date, $interval, $format = 'd.m.Y')
    {
        $d1 = new DateTime($date);
        $result = $d1->add(new DateInterval($interval))->format($format);
        return $result;
    }

    /**
     * Преобразует дату в нужный формат
     *
     * @param string $date   - дата
     * @param string $format - возвращаемый формат (по умолчанию  d.m.Y)
     *
     * @return string
     */
    public static function formatDate($date = '00.00.0000', $format = 'd.m.Y')
    {
        $date_obj = new DateTime($date);
        return $date_obj->format($format);
    }
}

 в условие можно и праздники впихнуть смело. Гонял код, вроде всё корректно отдаёт.

PS
Код скорее всего не будет работать PHP 5 < 5.3.0

Это сообщение отредактировал(а) Gold Dragon - 24.1.2014, 15:06


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
capitan
Дата 24.1.2014, 15:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 27.2.2005
Где: Москва

Репутация: 9
Всего: 13



Каждую задачу нужно рассматривать с позиции целесообразности smile Если потом заказчик скажет, давай будем учитывать ещё и праздники, код полетит к чертям собачим. Я бы это учел сразу. Без учета праздников, учитывая только  сб и вск сделать можно и без перебора.
PM MAIL WWW ICQ   Вверх
Gold Dragon
Дата 24.1.2014, 15:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



Цитата(capitan @  24.1.2014,  16:18 Найти цитируемый пост)
Без учета праздников, учитывая только  сб и вск сделать можно и без перебора. 
да вот не смог.. или дни вылетают или конечная дата приходится на выходной..



--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
capitan
Дата 24.1.2014, 16:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 27.2.2005
Где: Москва

Репутация: 9
Всего: 13



Нужно тестить, поидее должно работать:
Код

    $date=date("d.m.Y"); // Сегодня
    echo CheckHolidayBeta($date, 33)."<br/>";

    function CheckHolidayBeta($date, $count) {

        $dayShift = date('N', strtotime($date));
        $count += $dayShift;

        $week_count = floor($count/5);
        $lastWeekDays = $week_count*7 - $dayShift + ($count % 5) + 1;

        $dateEnd = date("d.m.Y", strtotime($date ."+{$lastWeekDays} day"));
        $dateEndName = date('N', strtotime($dateEnd));
        $shiftEnd = ($dateEndName > 5) ? 7 - $dateEndName + 1 : 0;

        if(!empty($shiftEnd)) {
            echo date("d.m.Y", strtotime($dateEnd ."+{$shiftEnd} day"));
        } else {
            echo  $dateEnd;
        }
     }


Это сообщение отредактировал(а) capitan - 24.1.2014, 16:58
PM MAIL WWW ICQ   Вверх
Gold Dragon
Дата 24.1.2014, 19:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



Цитата(capitan @  24.1.2014,  17:52 Найти цитируемый пост)
Нужно тестить, поидее должно работать:

Это 
Код

echo CheckHolidayBeta('03.01.2014', 10);

выдаёт 20.01.2014, хотя должно 17-е

Это сообщение отредактировал(а) Gold Dragon - 24.1.2014, 19:44


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
ksnk
Дата 24.1.2014, 21:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



а так?
Код

<?php
/**
 * class to hold all-around-calendar function
 */
class calendar
{

    /**
     * just a source; key - d/m/Y ; true==holiday, false==workdaay.
     * if absent - use weekday to consider
     * http://www.garant.ru/calendar/buhpravo/
     */
    private static $workdays = array(
//2013
        '01/01/2013' => true,
        '02/01/2013' => true,
        '03/01/2013' => true,
        '04/01/2013' => true,
        '07/01/2013' => true,
        '08/01/2013' => true,
        '08/03/2013' => true,
        '01/05/2013' => true,
        '02/05/2013' => true,
        '03/05/2013' => true,
        '09/05/2013' => true,
        '10/05/2013' => true,
        '12/06/2013' => true,
        '04/11/2013' => true,
// 2014
        '01/01/2014' => true,
        '02/01/2014' => true,
        '03/01/2014' => true,
        '06/01/2014' => true,
        '07/01/2014' => true,
        '08/01/2014' => true,
        '10/03/2014' => true,
        '01/05/2014' => true,
        '02/05/2014' => true,
        '09/05/2014' => true,
        '12/06/2014' => true,
        '03/11/2014' => true,
        '04/11/2014' => true,
    );

    /**
     * return day $workdays days after $day
     * @param string|int $day
     * @param int $workdays
     * @return int|string
     */
    static function addWorkDays($day, $workdays)
    {
        if (is_string($day)) {
            $day = strtotime($day);
        }
        while ($workdays > 0) {
            $day = strtotime('+1 day', $day);
            $key = date('d/m/Y', $day);
            if (isset(self::$workdays[$key])) {
                if (!self::$workdays[$key]) {
                    $workdays--;
                }
            } else {
                switch (date('w', $day)) {
                    case '0':
                    case '6':
                        break;
                    default:
                        $workdays--;
                }
            }
        }
        return $day;
    }
}

/**
 *  so let's test it
 */

echo date('d/m/Y', calendar::addWorkDays('01.01.2014', 10)) . "\n";
echo date('d/m/Y', calendar::addWorkDays('08.01.2014', 10)) . "\n";
echo date('d/m/Y', calendar::addWorkDays('01.01.2014', 8)) . "\n";
echo date('d/m/Y', calendar::addWorkDays('03.01.2014', 7)) . "\n";


P.S. слегка отформатировал и добавил 2013 год

Это сообщение отредактировал(а) ksnk - 24.1.2014, 22:03


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
ksnk
Дата 25.1.2014, 11:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


прохожий
****


Профиль
Группа: Комодератор
Сообщений: 6855
Регистрация: 13.4.2007
Где: СПб

Репутация: 96
Всего: 386



Если в моем коде заменить strtotime('+1 day'... на +=60*60*24, и  поменять ключики массива праздников на их числовые значения с выкидыванием формирования ключа, то работать будет в 4 раза быстрее.

Вообще, о чем такая задача? 
На своей машинке - ноутбук с i3, 1000 200-дневных периодов посчиталось за 7 сек (исходно опубликованный - 30 сек). Как показывает практика - сервера (в моей доступности) решают такие задачи в 5-10 раз быстрее. Может быть и хватит скорости?


--------------------
Человеку свойственно ошибаться, программисту свойственно ошибаться профессионально ! user posted image
PM MAIL WWW Skype   Вверх
capitan
Дата 25.1.2014, 16:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 27.2.2005
Где: Москва

Репутация: 9
Всего: 13



Цитата(Gold Dragon @ 24.1.2014,  19:43)
Цитата(capitan @  24.1.2014,  17:52 Найти цитируемый пост)
Нужно тестить, поидее должно работать:

Это 
Код

echo CheckHolidayBeta('03.01.2014', 10);

выдаёт 20.01.2014, хотя должно 17-е

не учел последние выхи на неделе.
Делаем так:
строку:
Код

       $lastWeekDays = $week_count*7 - $dayShift + ($count % 5) + 1;


меняем на:
Код

        // Fix на последние выходные на неделе
        $fix_end = ( $count % 5 > 0 ) ? 0 : 2;
        $lastWeekDays = $week_count*7 - $dayShift + ($count % 5) - $fix_end;


Теперь должно работать.
PM MAIL WWW ICQ   Вверх
baldina
Дата 28.1.2014, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Gold Dragon, если учитывать все обстоятельства, то как-то так
http://ideone.com/mIyRNv

Добавлено через 1 минуту и 3 секунды
с базой попроще будет ;-)
PM MAIL   Вверх
Gold Dragon
Дата 29.1.2014, 08:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



протестировал малость..

Тест:
Код

$sysstart = microtime(true);
for($i = 0; $i < 250; $i++){
    LibDateTime::getEndDateWorking('12.01.2014', 50);
}
echo round((microtime(true) - $sysstart), 5). '<hr>';



мой код:

250 запросов 50 дней   - 3.78722
250 запросов 100 дней - 7.81845
500 запросов 50 дней   - 7.61444
500 запросов 100 дней - 15.58989

код baldina:

250 запросов 50 дней   - 0.016
250 запросов 100 дней - 0.011
500 запросов 50 дней   - 0.022
500 запросов 100 дней - 0.022

 smile 

Вот вам и проблемы перебора.. Осталось проверить правильность

Добавлено через 12 минут и 41 секунду
baldina, 2014-01-04 10 дней всё таки 17.01 а не 20.01


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
baldina
Дата 29.1.2014, 09:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



Цитата(Gold Dragon @  29.1.2014,  08:19 Найти цитируемый пост)
baldina, 2014-01-04 10 дней всё таки 17.01 а не 20.01 

ну ты уж определись, считать или нет день даты договора
PM MAIL   Вверх
Gold Dragon
Дата 29.1.2014, 09:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



ну вообще-то нет. "Шесть частей, но пять распилов"

   1    2    3   4    5
3---4---5---6---7---8




--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
baldina
Дата 29.1.2014, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 26
Всего: 101



ну тады вычти один день. сможешь? ;-)
PM MAIL   Вверх
Страницы: (3) Все 1 [2] 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0746 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.