Dado um intervalo de datas como calcular o número de fins de semana parcial ou totalmente dentro desse intervalo?

votos
1

Dado um intervalo de datas como calcular o número de fins de semana parcial ou totalmente dentro desse intervalo?

(Algumas definições como solicitado:. Assumir 'fim de semana' para significar sábado e domingo O período é incluído ou seja, a data final é parte da gama 'total ou parcialmente' significa que qualquer parte do fim de semana cair dentro do intervalo de data significa o fim de semana inteiro é contado.)

Para simplificar eu imagino que você realmente só precisa saber a duração e que dia da semana, o dia inicial é ...

Eu bem danado agora vai envolver fazendo divisão inteira por 7 e alguma lógica para adicionar 1 dependendo do restante, mas eu não consigo descobrir o que ...

pontos extras para respostas em Python ;-)

Editar

Aqui está o meu código final.

Fins de semana são sexta-feira e sábado (como estamos contando noites de estadia) e os dias são 0-indexados a partir de segunda-feira. Eu usei o algoritmo de onebyone e layout de código de Tom. Thanks a lot pessoas.

def calc_weekends(start_day, duration):
    days_until_weekend = [5, 4, 3, 2, 1, 1, 6]
    adjusted_duration = duration - days_until_weekend[start_day]
    if adjusted_duration < 0:
        weekends = 0
    else:
        weekends = (adjusted_duration/7)+1
    if start_day == 5 and duration % 7 == 0: #Saturday to Saturday is an exception
        weekends += 1
    return weekends

if __name__ == __main__:
    days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    for start_day in range(0,7):
        for duration in range(1,16):
            print %s to %s (%s days): %s weekends % (days[start_day], days[(start_day+duration) % 7], duration, calc_weekends(start_day, duration))
        print
Publicado 19/05/2009 em 16:58
fonte usuário
Em outras línguas...                            


4 respostas

votos
5

abordagem geral para este tipo de coisa:

Para cada dia da semana, descobrir quantos dias são necessários antes de um período que se inicia nesse dia "contém um fim de semana". Por exemplo, se "contém um fim de semana" significa "contém tanto o sábado e domingo", então temos a seguinte tabela:

Domingo: 8 Segunda-feira: 7 Terça-feira: 6 Quarta-feira: 5 Quinta-feira: 4 Sexta-feira: 3 Sábado: 2

Para "parcial ou totalmente", temos:

Domingo: 1 Segunda-feira: 6 Terça-feira: 5 Quarta-feira: 4 Quinta-feira: 3 Sexta-feira: 2 Sábado: 1

Obviamente, isso não tem de ser codificada como uma mesa, agora que é óbvio o que parece.

Então, dado o dia da semana do início do seu período, subtrair [*] o valor mágico da duração do período em dias (provavelmente começar-end + 1, para incluir ambos os fenceposts). Se o resultado for menor que 0, que contém 0 fins de semana. Se for igual ou superior a 0, em seguida, ele contém (pelo menos) um fim de semana.

Então você tem que lidar com os dias restantes. No primeiro caso, isso é fácil, um fim de semana extra por 7 dias completos. Isto também é verdade no segundo caso, para cada dia de início, excepto ao domingo, que requer apenas mais 6 dias para incluir outro fim de semana. Então, no segundo caso, para períodos com início no domingo você poderia contar um fim de semana no início do período, em seguida, subtrair 1 do comprimento e recalcular a partir de segunda-feira.

Mais geralmente, o que está acontecendo aqui por "todo ou em parte" fins de semana é que estamos verificando para ver se nós começamos a meio do pouco interessante (o "fim de semana"). Se assim for, nós pode:

  • 1) Conte um, mover a data de início para o final do pouco interessante, e recalcular.
  • 2) Mova a data de início de volta para o início do pouco interessante, e recalcular.

No caso de fins de semana, há apenas um caso especial que começa no meio do caminho, então (1) parece ser bom. Mas se você estava começando a data como uma data + tempo em segundos, em vez de dias, ou se você estivesse interessado em semanas de trabalho de 5 dias em vez de fins de semana de 2 dias, em seguida, (2) pode ser mais simples de entender.

[*] A menos que você estiver usando tipos não assinados, é claro.

Respondeu 19/05/2009 em 17:19
fonte usuário

votos
2

Minha abordagem geral para este tipo de coisa: não comece brincando tentando reimplementar sua própria lógica de data - é difícil, ie. você vai estragar tudo para os casos de ponta e ficar mal. Dica: se você mod 7 aritmética em qualquer lugar em seu programa, ou estão tratando datas como números inteiros em qualquer lugar em seu programa: você falhar . Se eu vi a "solução aceite" em qualquer lugar (ou mesmo próximo) a minha base de código, alguém teria que começar de novo. Não dá para a imaginação que qualquer um que se considera um programador votariam essa resposta para cima.

Em vez disso, usar o construída em lógica de data / hora que vem com Python:

Em primeiro lugar, obter uma lista de todos os dias que você está interessado em:

from datetime import date, timedelta    
FRI = 5; SAT = 6

# a couple of random test dates
now = date.today()
start_date = now - timedelta(57)
end_date = now - timedelta(13)
print start_date, '...', end_date    # debug

days = [date.fromordinal(d) for d in  
            range( start_date.toordinal(),
                   end_date.toordinal()+1 )]

Em seguida, filtrar para apenas os dias que são fins de semana. No seu caso você estiver interessado em noites de sexta e sábado, que são 5 e 6. (Observe como eu não estou tentando rolar esta parte na compreensão da lista anterior, uma vez que seria difícil para verificar como correto).

weekend_days = [d for d in days if d.weekday() in (FRI,SAT)]

for day in weekend_days:      # debug
    print day, day.weekday()  # debug

Finalmente, você quer descobrir quantos fins de semana estão em sua lista. Esta é a parte mais complicada, mas há realmente apenas quatro casos a considerar, um para cada extremidade para a sexta ou sábado. Exemplos concretos ajudar a tornar mais claro, mais este é realmente o tipo de coisa que você quer documentado em seu código:

num_weekends = len(weekend_days) // 2

# if we start on Friday and end on Saturday we're ok,
# otherwise add one weekend
#  
# F,S|F,S|F,S   ==3 and 3we, +0
# F,S|F,S|F     ==2 but 3we, +1
# S|F,S|F,S     ==2 but 3we, +1
# S|F,S|F       ==2 but 3we, +1

ends = (weekend_days[0].weekday(), weekend_days[-1].weekday())
if ends != (FRI, SAT):
    num_weekends += 1

print num_weekends    # your answer

Shorter, mais clara e fácil de entender significa que você pode ter mais confiança em seu código, e pode continuar com problemas mais interessantes.

Respondeu 12/05/2010 em 01:59
fonte usuário

votos
1

Para contar fins de semana inteiros, basta ajustar o número de dias para que você começar na segunda-feira, em seguida, dividir por sete. (Note que, se o dia de início é um dia da semana, adicionar dias para mudar para segunda-feira anterior, e se ele estiver em um fim de semana, subtrair dias para passar para a próxima segunda-feira desde que você já perdeu neste fim de semana.)

days = {"Saturday":-2, "Sunday":-1, "Monday":0, "Tuesday":1, "Wednesday":2, "Thursday":3, "Friday":4}

def n_full_weekends(n_days, start_day):
    n_days += days[start_day]
    if n_days <= 0:
        n_weekends = 0
    else:
        n_weekends = n_days//7
    return n_weekends

if __name__ == "__main__":
    tests = [("Tuesday", 10, 1), ("Monday", 7, 1), ("Wednesday", 21, 3), ("Saturday", 1, 0), ("Friday", 1, 0),
    ("Friday", 3, 1), ("Wednesday", 3, 0), ("Sunday", 8, 1), ("Sunday", 21, 2)]
    for start_day, n_days, expected in tests:
        print start_day, n_days, expected, n_full_weekends(n_days, start_day)

Se você quiser saber fins de semana parciais (ou semanas), basta olhar para a parte fracionária da divisão por sete.

Respondeu 19/05/2009 em 18:20
fonte usuário

votos
0

Você precisaria de lógica externa ao lado matemática cru. Você precisa ter uma biblioteca calendário (ou se você tem uma quantidade razoável de tempo implementá-lo) para definir o que um fim de semana, que dia da semana você começar em, termina em, etc.

Dê uma olhada na classe calendário de Python .

Sem uma definição lógica de dias em seu código, um puro métodos matemáticos iria falhar em caso de canto, como um intervalo de 1 dia ou, acredito, qualquer coisa menor, em seguida, uma semana (ou mais baixo, então 6 dias se você permitidos parciais).

Respondeu 19/05/2009 em 17:09
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more