Алгоритм расчета даты комплексного управления занятием - PullRequest
0 голосов
/ 16 мая 2018

Здравствуйте, переполнение стека,

У меня есть ситуация, когда мне нужна помощь в выборе лучшего способа заставить алгоритм работать, цель состоит в том, чтобы управлять занятостью ресурса (давайте рассмотрим ресурс A), чтобы иметь несколько задач, и где каждая задача занимает указанное количество времени для завершения. На этом первом этапе я не хочу задействовать несколько переменных, поэтому давайте сохраним это простым способом, давайте рассмотрим, у него есть только график рабочих дней.

Например:

1 - у нас есть 1 ресурс, ресурс A

2 - Ресурс А работает с 8:00 до 16:00, с понедельника по пятницу, если говорить проще, сейчас у него нет обеда, поэтому 8 часов работы в день.

3 - Ресурс А должен выполнить 5 задач, чтобы избежать сложности на этом уровне, давайте предположим, что для выполнения каждой из них потребуется ровно 10 часов.

4 - Ресурс А начнет работу над этими задачами в 2018-05-16, ровно в 2 часа дня.

Проблема: Теперь все, что мне нужно знать, это правильная дата окончания всех 5 заданий, но с учетом всех предыдущих ограничений.

В этом случае у него есть 6 рабочих дней и дополнительно 2 часа 7-го дня. Ожидаемый результат, который я хочу получить: 2018-05-24 (в 4 часа дня).

Реализация: Я подумал о двух вариантах и ​​хотел бы получить отзывы об этих или других параметрах, которые я мог бы не рассмотреть.

Алгоритм 1

1 - Создать список «слотов», где каждый «слот» будет представлять 1 час для x дней.

2 - Скрестите этот список слотов с часовым расписанием ресурса, чтобы удалить все слоты, где ресурса нет. Это вернет список со слотами, с которыми он действительно может работать.

3 - Занять оставшиеся слоты с заданиями, которые у меня есть для него.

4 - Finnaly, проверьте дату / час последнего занятого слота.

Недостаток: Я думаю, что это может быть излишним решением, учитывая, что я не хочу рассматривать его профессию на будущее, все, что я хочу, это знать, когда будут выполнены задачи.

Алгоритм 2

1 - Добавьте часы задачи (50 часов) к дате начала, получая ожидаемую конечную дату окончания. (Будет ожидаемымFinishDate = 2018-05-18 (в 16:00))

2 - Переведите часы между датой начала и ожидаемой конечной датой и расписанием, чтобы получить количество часов, в течение которых он не будет работать. (в основном получит недоступные часы, 16 часов в день, что приведет к оставшемуся часу ForCalc = 32 часа).

3 - рассчитать новую ожидаемую конечную дату с недоступными часами, добавив эти 32 часа к предыдущему 2018-05-18 (в 16:00).

4 - Повторите пункты 2 и 3 с новой ожидаемой конечной датой до оставшихся часовForCalc = 0.

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

Что бы вы предложили? Есть ли другой вариант, который я мог бы не рассмотреть, который сделал бы это проще? Или вы думаете, что есть способ улучшить любой из этих двух алгоритмов, чтобы он работал?

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Улучшенная версия:

import java.util.Calendar;
import java.util.Date;

public class Main {

public static void main(String args[]) throws Exception
{

    Date d=new Date();
    System.out.println(d);
    d.setMinutes(0);
    d.setSeconds(0);
    d.setHours(13);


    Calendar c=Calendar.getInstance();
    c.setTime(d);
    c.set(Calendar.YEAR, 2018);
    c.set(Calendar.MONTH, Calendar.MAY);
    c.set(Calendar.DAY_OF_MONTH, 17);

    //c.add(Calendar.HOUR, -24-5);
    d=c.getTime();
    //int workHours=11;
    int hoursArray[] = {1,2,3,4,5, 10,11,12, 19,20, 40};
    for(int workHours : hoursArray)
    {
        try
        {
            Date end=getEndOfTask(d, workHours);
            System.out.println("a task starting at "+d+" and lasting "+workHours
                + " hours will end at " +end);
        }
        catch(Exception e)
        {
            System.out.println(e.getMessage());
        }
    }

}

public static Date getEndOfTask(Date startOfTask, int workingHours) throws Exception
{
    int totalHours=0;//including non-working hours
    //startOfTask +totalHours =endOfTask
    int startHour=startOfTask.getHours();
    if(startHour<8 || startHour>16)
        throw new Exception("a task cannot start outside the working hours interval");
    System.out.println("startHour="+startHour);
    int startDayOfWeek=startOfTask.getDay();//start date's day of week; Wednesday=3
    System.out.println("startDayOfWeek="+startDayOfWeek);
    if(startDayOfWeek==6 || startDayOfWeek==0)
        throw new Exception("a task cannot start on Saturdays on Sundays");
    int remainingHoursUntilDayEnd=16-startHour;
    System.out.println("remainingHoursUntilDayEnd="+remainingHoursUntilDayEnd);
    /*some discussion here: if task starts at 12:30, we have 3h30min 
     * until the end of the program; however, getHours() will return 12, which
     * substracted from 16 will give 4h. It will work fine if task starts at 12:00,
     * or, generally, at the begining of the hour; let's assume a task will start at HH:00*/
    int remainingDaysUntilWeekEnd=5-startDayOfWeek;
    System.out.println("remainingDaysUntilWeekEnd="+remainingDaysUntilWeekEnd);
    int completeWorkDays = (workingHours-remainingHoursUntilDayEnd)/8;
    System.out.println("completeWorkDays="+completeWorkDays);
    //excluding both the start day, and the end day, if they are not fully occupied by the task
    int workingHoursLastDay=(workingHours-remainingHoursUntilDayEnd)%8;
    System.out.println("workingHoursLastDay="+workingHoursLastDay);
    /* workingHours=remainingHoursUntilDayEnd+(8*completeWorkDays)+workingHoursLastDay */

    int numberOfWeekends=(int)Math.ceil( (completeWorkDays-remainingDaysUntilWeekEnd)/5.0 );
    if((completeWorkDays-remainingDaysUntilWeekEnd)%5==0)
    {
        if(workingHoursLastDay>0)
        {
            numberOfWeekends++;
        }
    }
    System.out.println("numberOfWeekends="+numberOfWeekends);

    totalHours+=(int)Math.min(remainingHoursUntilDayEnd, workingHours);//covers the case
    //when task lasts 1 or 2 hours, and we have maybe 4h until end of day; that's why i use Math.min

    if(completeWorkDays>0 || workingHoursLastDay>0)
    {
        totalHours+=8;//the hours of the current day between 16:00 and 24:00
        //it might be the case that completeWorkDays is 0, yet the task spans up to tommorrow
        //so we still have to add these 8h
    }
    if(completeWorkDays>0)//redundant if, because 24*0=0
    {           
        totalHours+=24*completeWorkDays;//for every 8 working h, we have a total of 24 h that have 
        //to be added to the date   
    }

    if(workingHoursLastDay>0)
    {
        totalHours+=8;//the hours between 00.00 AM and 8 AM
        totalHours+=workingHoursLastDay;
    }

    if(numberOfWeekends>0)
    {
        totalHours+=48*numberOfWeekends;//every weekend between start and end dates means two days
    }

    System.out.println("totalHours="+totalHours);

    Calendar calendar=Calendar.getInstance();
    calendar.setTime(startOfTask);
    calendar.add(Calendar.HOUR, totalHours);
    return calendar.getTime();
}
}

Вы можете отрегулировать hoursArray [] или d.setHours вместе с c.set (Calendar.DAY_OF_MONTH, чтобы протестировать различные даты начала вместе с различными длинами задач.

По-прежнему существует ошибка, связанная с добавлением 8 часов между 16:00 и 24:00: задача, начинающаяся в четверг 17 мая, 13:00:00 EEST 2018 и продолжающаяся 11 часов, закончитсяв субботу 19 мая 00:00:00 EEST 2018 .

Я сохранил много операторов печати, они полезны для целей отладки.

Вот объясненная терминология:enter image description here

0 голосов
/ 16 мая 2018

Я согласен с тем, что алгоритм 1 является избыточным.

Думаю, я бы позаботился о том, чтобы у меня были правильные условия: часы в день (8), рабочие дни (пн, вт, ср, чт, пт).Затем разделил бы требуемые часы (5 * 10 = 50) на часы в день, чтобы я знал минимум необходимого количества рабочих дней (50/8 = 6).Чуть более продвинутый, сначала разделите на часы в неделю (50/40 = 1 неделя).Подсчитайте рабочие дни от даты начала, чтобы получить первый выстрел в дату окончания.Вероятно, от подразделения был остаток, поэтому используйте его, чтобы определить, могут ли задачи завершиться в этот день или продолжатся до следующего рабочего дня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...