2010-03-13 13 views
11

¿Cómo se puede calcular el siguiente viernes a las 3am como un objeto datetime?¿Cómo calcular el próximo viernes a las 3 a.m.?

Aclaración: es decir, la fecha calculada siempre debe ser mayor que 7 días de distancia, y menos que o igual a 14.


Ir con una versión ligeramente modificada de Mark's solution:

def _next_weekday(day_of_week=4, time_of_day=datetime.time(hour=3), dt=None): 
    if dt is None: dt = datetime.datetime.now() 
    dt += datetime.timedelta(days=7) 
    if dt.time() < time_of_day: dt = dt.combine(dt.date(), time_of_day) 
    else: dt = dt.combine(dt.date(), time_of_day) + datetime.timedelta(days=1) 
    return dt + datetime.timedelta((day_of_week - dt.weekday()) % 7) 
+3

Huh? .......... –

+0

¿y si es lunes? ¿Debería calcular 4 días a partir de ahora? O dentro de 11 días? Y es domingo 5 días a partir de ahora? Por favor aclara! – Tom

+0

aclaración agregada – mpen

Respuesta

6

Aquí es una función y una prueba de que cumple con los requisitos de la OP:

import datetime 

_3AM = datetime.time(hour=3) 
_FRI = 4 # Monday=0 for weekday() 

def next_friday_3am(now): 
    now += datetime.timedelta(days=7) 
    if now.time() < _3AM: 
     now = now.combine(now.date(),_3AM) 
    else: 
     now = now.combine(now.date(),_3AM) + datetime.timedelta(days=1) 
    return now + datetime.timedelta((_FRI - now.weekday()) % 7) 

if __name__ == '__main__': 
    start = datetime.datetime.now() 
    for i in xrange(7*24*60*60): 
     now = start + datetime.timedelta(seconds=i) 
     then = next_friday_3am(now) 
     assert datetime.timedelta(days=7) < then - now <= datetime.timedelta(days=14) 
     assert then.weekday() == _FRI 
     assert then.time() == _3AM 
+0

Jaja ... prueba muy completa. Me preguntaba por qué tardaba tanto en correr hasta que lo leí: D – mpen

+0

Me gusta bastante esta solución en realidad. No depende de otra biblioteca, y es simplemente modificar para otros días/horas. – mpen

9

Si instala dateutil, entonces podría hacer algo como esto:

import datetime 
import dateutil.relativedelta as reldate 

def following_friday(dt): 
    rd=reldate.relativedelta(
     weekday=reldate.FR(+2), 
     hours=+21) 
    rd2=reldate.relativedelta(
     hour=3,minute=0,second=0,microsecond=0) 
    return dt+rd+rd2 

Arriba, hours=+21 dice relativedelta para incrementar el dt antes de 21 horas antes de encontrar el próximo viernes. Por lo tanto, si dt es el 12 de marzo de 2010 a las 2am, al sumar 21 horas hace que sea 11pm del mismo día, pero si dt es después de las 3am, entonces la adición de 21 horas empuja dt al sábado.

Aquí hay algunos códigos de prueba.

if __name__=='__main__': 
    today=datetime.datetime.now() 
    for dt in [today+datetime.timedelta(days=i) for i in range(-7,8)]: 
     print('%s --> %s'%(dt,following_friday(dt))) 

que produce:

2010-03-05 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-06 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-07 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-08 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-09 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-10 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-11 20:42:09.246124 --> 2010-03-19 03:00:00 
2010-03-12 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-13 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-14 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-15 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-16 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-17 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-18 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-19 20:42:09.246124 --> 2010-04-02 03:00:00 

tiempo antes de 03 a.m.:

two = datetime.datetime(2010, 3, 12, 2, 0) 
for date in [two+datetime.timedelta(days=i) for i in range(-7,8)]: 
    result = following_friday(date) 
    print('{0}-->{1}'.format(date,result)) 

rendimientos:

2010-03-05 02:00:00-->2010-03-12 03:00:00 
2010-03-06 02:00:00-->2010-03-19 03:00:00 
2010-03-07 02:00:00-->2010-03-19 03:00:00 
2010-03-08 02:00:00-->2010-03-19 03:00:00 
2010-03-09 02:00:00-->2010-03-19 03:00:00 
2010-03-10 02:00:00-->2010-03-19 03:00:00 
2010-03-11 02:00:00-->2010-03-19 03:00:00 
2010-03-12 02:00:00-->2010-03-19 03:00:00 
2010-03-13 02:00:00-->2010-03-26 03:00:00 
2010-03-14 02:00:00-->2010-03-26 03:00:00 
2010-03-15 02:00:00-->2010-03-26 03:00:00 
2010-03-16 02:00:00-->2010-03-26 03:00:00 
2010-03-17 02:00:00-->2010-03-26 03:00:00 
2010-03-18 02:00:00-->2010-03-26 03:00:00 
2010-03-19 02:00:00-->2010-03-26 03:00:00 
+0

'relativedelta' también toma valores absolutos como' hour', 'minute', etc. De esta forma puede producir un delta que también establecerá horas y minutos y segundos en su resultado a las 3 am en punto. Ver: http://labix.org/python-dateutil#head-6a1472b7c74e5b8bab7784f11214250d34e09aa5 –

+0

ack! No quise decir que el jueves fue un caso especial, eso fue solo un ejemplo. aunque, si reemplazamos +2 con +7 ... debería funcionar bien? – mpen

+1

@Mark: He editado el código para que concuerde con lo que desea. 'days = + 8' debería hacerlo si entiendo correctamente. – unutbu

4

I como dateutil para tales tareas en general, pero Don' entiendo la heurística que desea, como uso las palabras, si digo "el próximo viernes" y es jueves, significaría mañana (probablemente he estado trabajando demasiado y perdí la pista de qué día de la semana es). Si puede especificar su heurística de manera rigurosa, seguramente se pueden programar, por supuesto, pero si son lo suficientemente extrañas y peculiares, es poco probable que las encuentre previamente programadas para usted en paquetes existentes ;-).

+0

No sé, la gente usa la palabra "siguiente" de manera ambigua. Típicamente, las personas usan "este viernes" para decir "el próximo viernes, el de esta semana", y "el próximo viernes" para decir "el viernes que reside en la semana siguiente". Simplemente me refiero a este último. – mpen

+0

He discutido con varias personas sobre lo que significa "siguiente" cuando se trata de frases como "el próximo viernes". Para mí, la interpretación que tiene más sentido sería el primer viernes siguiente al día de hoy, pero todos los demás parecen pensar que significa el segundo viernes siguiente al día de hoy. De acuerdo con esas personas, usted diría "este viernes" para referirse al primer viernes siguiente al día de hoy. – allyourcode

2

Basado en su aclaración ... Creo que se puede hacer algo como esto:

from datetime import * 
>>> today = datetime.today() 
>>> todayAtThreeAm = datetime(today.year, today.month, today.day, 3) 
>>> todayAtThreeAm 
datetime.datetime(2010, 3, 12, 3, 0) 
>>> nextFridayAtThreeAm = todayAtThreeAm + timedelta(12 - today.isoweekday()) 
>>> nextFridayAtThreeAm 
datetime.datetime(2010, 3, 19, 3, 0) 

Aviso isoweekday() devuelve 1 a 7 de lunes a domingo. 12 representa el viernes de la semana siguiente. Entonces 12 - today.isoweekday() le da el delta de tiempo correcto que necesita agregar hoy.

Espero que esto ayude.

+0

Creo que eso es incorrecto. En realidad debería regresar el 26 de marzo, ya que actualmente es después de las 3 a.m. del viernes. Recuerde que debe ser estrictamente superior a 7 días de distancia :) – mpen

+0

Tal vez un condicional lo haría? 'days = 12-today.isoweekday(); si días <= 7: días + = 7'? – mpen

Cuestiones relacionadas