segunda-feira, 31 de março de 2014

Dias uteis (WorkDays) do Excell mas mais completo

Dias e horas úteis

Mais um desafio que recentemente tive de superar, num projecto. Engraçado foi o quão simples é a solução e o quão rebuscada a mente consegue ser para a encontrar.

Neste caso uma simples classe em C# permite achar as horas uteis decorridas entre duas datas e horas, sendo estas passadas como objectos Datetime.

Outras particularidades da classe é asseitar como parametro os dias feriados (excludeDays), que com pouco código até podem vir de uma tabela de uma BD.

Achei engraçada a facilidade com que se consegue instanciar, fazer os calculos e obter o tempo decorrido com precisão ao segundo.

using System;
using System.Linq;
namespace duteis
{
    public class uteis
    {
        private TimeSpan startingTime;
        private TimeSpan endingTime;
        private DayOfWeek[] excludeDays;
        public uteis(TimeSpan? startingTime, TimeSpan? endingTime, DayOfWeek[] excludeDays)
        {
            this.startingTime = startingTime ?? new TimeSpan(8, 30, 0);
            this.endingTime = endingTime ?? new TimeSpan(17, 30, 0);
            this.excludeDays = excludeDays ?? new DayOfWeek[]   
   {   
    DayOfWeek.Saturday ,   
    DayOfWeek.Sunday   
   };
        }
        public uteis()
            : this(null, null, null)
        {
        }
        public double Calculate(DateTime startDate, DateTime endDate)
        {
            var counter = startDate;
            double hours = 0;
            while (counter <= endDate)
            {
                var dayStart = counter.Date.Add(startingTime);
                var dayEnd = counter.Date.Add(endingTime);
                var nextDayStart = startDate.Date.Add(startingTime).AddDays(1);
                if (counter < dayStart)
                    counter = dayStart;
                if (excludeDays == null ||
                  excludeDays.Contains(counter.DayOfWeek) == false)
                {
                    if (endDate < nextDayStart)
                    {
                        var ticks = Math.Min(endDate.Ticks, dayEnd.Ticks) - counter.Ticks;
                        hours = TimeSpan.FromTicks(ticks).TotalHours;
                        break;
                    }
                    else if (counter.Date == startDate.Date)
                    {
                        if (counter >= dayStart && counter <= dayEnd)
                        {
                            hours += (dayEnd - counter).TotalHours;
                        }
                    }
                    else if (counter.Date == endDate.Date &&
                         startDate.Date != endDate.Date)
                    {
                        if (counter >= dayStart && counter <= dayEnd)
                        {
                            hours += (counter - dayStart).TotalHours;
                        }
                        else if (counter > dayEnd)
                        {
                            hours += (endingTime - startingTime).TotalHours;
                        }
                    }
                    else
                    {
                        hours += (endingTime - startingTime).TotalHours;
                    }
                }
                counter = counter.AddDays(1);
                if (counter.Date == endDate.Date)
                    counter = endDate;
            }
            return hours;
        }
    }
}


Atenção a estas linhas onde se define a duração do dia ùtil, e são tratados os "excludeDays" que podem ser os feriados como escrevi anteriormente.

this.startingTime = startingTime ?? new TimeSpan(8, 30, 0);  
this.endingTime = endingTime ?? new TimeSpan(17, 30, 0);  
this.excludeDays = excludeDays ?? new DayOfWeek[]  

Nenhum comentário:

Postar um comentário

Observação: somente um membro deste blog pode postar um comentário.