AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 23.07.2009, 02:00   #1  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Образец, требует лишь минимальной доработки в плане даты:

\Data Dictionary\Tables\WorkCalendarDate\Methods\calcDefinedSeconds
X++:
server static Seconds calcDefinedSeconds(
    CalendarId    _calendar,
    TransDate     _transDate,
    Seconds       _fromTime         = maxint(),
    Seconds       _toTime           = 0,
    boolean       _useEffectivity   = true,
//sp1
    boolean       _throwIfError     = true
    )
{
    WorkCalendarDateLine    workCalendarDateLine;
    Seconds                 seconds;
    ;

    while select workCalendarDateLine
        index hint CalendarDateFromIdx
//sp1
        where workCalendarDateLine.CalendarId   == WorkCalendar::defined(_calendar,_transDate,_throwIfError)  &&
              workCalendarDateLine.TransDate    == _transDate
    {
        workCalendarDateLine.FromTime  = workCalendarDateLine.FromTime < _fromTime
            ? _fromTime
            : workCalendarDateLine.FromTime;
        workCalendarDateLine.ToTime    = workCalendarDateLine.ToTime   > _toTime
            ? _toTime
            : workCalendarDateLine.ToTime;

        if (workCalendarDateLine.FromTime < workCalendarDateLine.ToTime)
             seconds += workCalendarDateLine.capacity(100,_useEffectivity);
    }

    return seconds;
}
За это сообщение автора поблагодарили: sukhanchik (2).
Старый 23.07.2009, 14:09   #2  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Как обычно, обожаю подобные задачки. Вечерком прикинул алгоритм (под спилберговские "Челюсти" по НТВ), сегодня неспешно воплотил в перерывах основной работы. Видел, что в теме уже что-то появилось от sukhanchik'а и EVGL'а, но заставил себя не смотреть раньше времени, чтобы увиденное не влияло на мой плотницкий вариант.

Вначале я хотел вообще обойтись одним SELECT'ом классического SQL. Но крыша начала немного коситься (а тут еще и акулы по телеку плавали!), и я свернул на дорожку перебора дат, входящих в диапазон, с отбором диапазонов рабочего времени в map и последующим вычислением общей суммы рабочих часов. Диапазоны представлены 2-х элементными контейнерами [дата/время начала, дата/время окончания]. Дата/время - real, в котором целая часть - дни, а дробная - доля суток.

Элементы рабочего календаря имитируются встроенной функцией, в которой реализован конкретный график работы. График работы взял из своего личного жЫзненного опыта - 4 дня с 8-30 до 17-30, в пятницу - до 16-30. Обед - 48 минут (а не час), и за счет ежедневных "переработок" в 12 минут к пятнице набегает час, на который и можно уйти пораньше. Наверное, многим знаком подобный прием. Обед в джобе учтён!
X++:
#define.secondsOf24hrs( 86400 )

static void KKu_demoCountWorkHoursForPeriod(Args _args)
{
    // ИСХОДНЫЕ ДАННЫЕ -------------------------
    // дата/время начала и дата/время окончания
    date        dateBeg = 01\06\2009;
    timeOfDay   timeBeg = str2time('07:00:00');

    date        dateEnd = 30\06\2009;
    timeOfDay   timeEnd = str2time('24:00:00');
    // -----------------------------------------

    real        dateTimeBeg = date2num(dateBeg) + timeBeg/#secondsOf24hrs;
    real        dateTimeEnd = date2num(dateEnd) + timeEnd/#secondsOf24hrs;

    real        start, finish, workHours;
    int         i, elemCount;

    Map         allDaysRanges   = new Map(Types::Integer, Types::Container);
    Set         oneDayRanges    = new Set(Types::Container);

    SetEnumerator   setEnumr;
    MapEnumerator   mapEnumr;

    // встроенная функция имитирует рабочий календарь ------------------------------------
    // для одного дня возвращает два периода, с учетом обеденного перерыва
    // для простоты примера не учитывает праздники и связанные с ними переносы
    Set workdayRanges(date _date)
    {
        Set     setRanges = new Set(Types::Container);
        ;
        switch (dayOfWk(_date))
        {
            case 1,2,3,4 :  // c 8-30 до 17-30 (обед 48 минут)
                // до обеда
                setRanges.add([date2num(_date) + str2time('08:30:00')/#secondsOf24hrs,
                               date2num(_date) + str2time('13:00:00')/#secondsOf24hrs]);
                // после обеда
                setRanges.add([date2num(_date) + str2time('13:48:00')/#secondsOf24hrs,
                               date2num(_date) + str2time('17:30:00')/#secondsOf24hrs]);
                break;

            case 5 : // ПЯТНИЦО! - на час меньше! c 8-30 до 16-30 (обед 48 минут)
                // до обеда
                setRanges.add([date2num(_date) + str2time('08:30:00')/#secondsOf24hrs,
                               date2num(_date) + str2time('13:00:00')/#secondsOf24hrs]);
                // после обеда
                setRanges.add([date2num(_date) + str2time('13:48:00')/#secondsOf24hrs,
                               date2num(_date) + str2time('16:30:00')/#secondsOf24hrs]);
                break;

            case 6,7 :
                // ничего -> Have a nice weekend! ))
                break;
        }
        return setRanges;
    }
    // -----------------------------------------------------------------------------------
    ;

    if (dateTimeEnd < dateTimeBeg)
    {
        box::stop('Дата/время окончания меньше даты/времени начала!\nВыполнение прервано.');
        return;
    }

    // заполнение map циклом между крайними датами периода
    for (i=date2num(dateBeg); i<=date2num(dateEnd)+1; i++)
    {
        oneDayRanges = workdayRanges( num2date(i) );
        if (! oneDayRanges.empty())
        {
            setEnumr = oneDayRanges.getEnumerator();
            while (setEnumr.moveNext())
            {
                [start, finish] = setEnumr.current();
                if ( ((start  >= dateTimeBeg) && (start  <= dateTimeEnd)) || // start between Beg and End
                     ((finish >= dateTimeBeg) && (finish <= dateTimeEnd)) || // finish between Beg and End
                     ((start  <= dateTimeBeg) && (finish >= dateTimeEnd)) )  // на случай внутри одного диапазона
                {
                    elemCount++;
                    allDaysRanges.insert(elemCount, [start, finish]);
                }
            }
        }
    }

    if (! allDaysRanges.empty())
    {
        // коррекция первого диапазона
        [start, finish] = allDaysRanges.lookup(1);
        start = max(start, dateTimeBeg);
        allDaysRanges.insert(1, [start, finish]);

        // коррекция последнего диапазона
        [start, finish] = allDaysRanges.lookup(elemCount);
        finish = min(finish, dateTimeEnd);
        allDaysRanges.insert(elemCount, [start, finish]);
    }

    // подсчет рабочих часов за период
    mapEnumr = allDaysRanges.getEnumerator();
    while (mapEnumr.moveNext())
    {
        [start, finish] = mapEnumr.currentValue();
        workHours += (finish - start) * 24;
    }
    box::info( strFmt('Кол-во рабочих часов = %1', workHours));
}
Теги
расчеты с персоналом

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
добавление только чисел fialka DAX: Программирование 5 15.03.2007 15:18
Как учесть срок поставки Клиенту при планировании? KIV DAX: Функционал 6 07.11.2005 12:54
Печать только четных или нечетных страниц отчета Yury DAX: Программирование 9 07.02.2003 15:37
Можно ли имея только название(имя) таблицы добавить в неё запись? Yuri Safronov DAX: Программирование 8 03.10.2002 11:41
Хочу видеть только итоги AKIS DAX: Функционал 1 19.08.2002 11:49
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра
Комбинированный вид Комбинированный вид

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 02:45.