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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 22.07.2009, 14:57   #1  
koraman is offline
koraman
Участник
 
41 / 11 (1) +
Регистрация: 12.02.2008
Адрес: Казань
Как учесть только рабочие часы?
Вот уверен, что я не один с этим сталкивался, но на форуме почему-то не нашёл. Есть у меня дата1, время1, дата2, время2. Можно ли каким-нибудь классиком определить, сколько времени прошло с дата1, время1 по дата2, время2, если необходимо учитывать только рабочие часы (например, с 8.00 по 17.00)?
__________________
I believe!
Старый 22.07.2009, 15:30   #2  
Prof is offline
Prof
Участник
 
732 / 64 (4) ++++
Регистрация: 18.10.2002
Адрес: Москва
Маловероятно что такой класс есть
Старый 22.07.2009, 15:36   #3  
kashperuk is offline
kashperuk
Участник
Аватар для kashperuk
MCBMSS
Соотечественники
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,361 / 2084 (78) +++++++++
Регистрация: 30.05.2004
Адрес: Atlanta, GA, USA
Посмотрите вот эту тему - там много всего было, возможно и свое найдете.
по датам
Старый 22.07.2009, 18:56   #4  
sukhanchik is offline
sukhanchik
Administrator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,323 / 3547 (125) ++++++++++
Регистрация: 13.06.2004
Адрес: Москва
Есть очень классный календарь в los-слое с зарплатой. Находится он в \Расчеты с персоналом\Учет рабочего времени\Календарь\Календари. В нем задаются календарь, шаблон (5 дней для обычной рабочей недели) и самое главное - в нем можно задавать вручную все выходные дни, не попадающие на субботу/воскресенье или рабочие дни, наоборот попадающие на субботу/воскресенье. Т.е. задать фактически только исключения из общего правила, что сб, вс выходные, а остальные дни рабочие.
Также там можно по кнопке Расписания создать времена и указать любой диапазон времени.

В коде сей механизм вызывается через статические методы, расположенные на таблице RPayCalendarTable, в частности для Вас интересен метод periodWorkDays

А вот такой код - Вам поможет получить дату, ближайшую в будущем после заданной Вами, которая является рабочим днем:
X++:
#Define.MyDate(systemdateget())
rPayCalendarId = RPayCalendarTable::findCalendarType(RpayCalendarType::FiveDay).CalendarId;
    select firstonly rPaycalendarDate
        where rPaycalendarDate.TransDate > #MyDate &&
              rPaycalendarDate.CalendarId == rPayCalendarId   &&
              rPaycalendarDate.PayDayType == RPayDayType::WorkDay;
Конечно сей календарь надо вести. Но зато и расчет будет точным
__________________
Возможно сделать все. Вопрос времени
Старый 23.07.2009, 02:00   #5  
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   #6  
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, время: 13:59.