2010-03-13 13 views
11

Come è possibile calcolare il seguente venerdì alle 3:00 come oggetto datetime?Come calcolare il prossimo venerdì alle 3 del mattino?

Chiarificazione: Per esempio, la data calcolata deve sempre essere maggiore di 7 giorni di distanza, e inferiore o uguale a 14.


Andando con una versione leggermente modificata di 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

eh? .......... –

+0

E se fosse lunedì? Dovrebbe calcolare 4 giorni da adesso? O tra 11 giorni? Ed è domenica 5 giorni da oggi? Si prega di precisare! – Tom

+0

chiarimento aggiunto – mpen

risposta

6

Ecco una funzione e una prova che essa soddisfa i requisiti della 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

Haha ... test molto completo. Mi stavo chiedendo perché ci fosse voluto così tanto tempo per correre finché non lo leggevo: D – mpen

+0

Mi piace molto questa soluzione in realtà. Non dipende da un'altra libreria, ed è semplicemente da modificare per altri giorni/orari. – mpen

9

Se si installa dateutil, quindi si potrebbe fare qualcosa di simile:

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 

Sopra, hours=+21 indica relativedelta per incrementare lo dt di 21 ore prima di trovare il venerdì successivo. Quindi, se dt è il 12 marzo 2010 alle 2:00, l'aggiunta di 21 ore lo rende 11 00 dello stesso giorno, ma se dt è dopo le 3:00, quindi aggiungendo 21 ore si spinge dt in sabato.

Ecco alcuni codici di test.

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))) 

che 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 

po 'prima di 3:00:

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)) 

rendimenti:

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' accetta anche valori assoluti come' hour', 'minute', ecc. In questo modo è possibile produrre un delta che imposta anche ore e minuti e secondi sul risultato a 3am sharp. Vedi: http://labix.org/python-dateutil#head-6a1472b7c74e5b8bab7784f11214250d34e09aa5 –

+0

ack! Non intendevo che giovedì fosse un caso speciale, quello era solo un esempio. anche se sostituiamo +2 con +7 .... dovrebbe funzionare bene? – mpen

+1

@Mark: ho modificato il codice per conformarmi, auspicabilmente, a quello che vuoi. 'days = + 8' dovrebbe farlo se ho capito bene. – unutbu

4

mi piacciono dateutil per questi compiti in generale, ma io don' t capire l'euristica che vuoi - mentre uso le parole, se dico "venerdì prossimo" ed è giovedì I significherebbe domani (probabilmente ho lavorato troppo e ho perso la cognizione di che giorno della settimana è). Se è possibile specificare la propria euristica in modo rigoroso, possono sicuramente essere programmati, ovviamente, ma se sono abbastanza strani e bizzarri è improbabile che li troviate già pre-programmati per voi in pacchetti esistenti ;-).

+0

Non so, le persone usano la parola "next" ambiguamente. In genere, le persone usano "questo venerdì" per indicare "questo venerdì prossimo, quello entro questa settimana" e "venerdì prossimo" per indicare "il venerdì che risiede nella settimana successiva". Intendo semplicemente il secondo. – mpen

+0

Ho discusso con varie persone su cosa significa "prossimo" quando si tratta di frasi come "il prossimo venerdì". Per me, l'interpretazione che ha più senso sarebbe il primo venerdì successivo a oggi, ma tutti gli altri sembrano pensare che significhi il secondo venerdì successivo a oggi. Secondo queste persone, si direbbe "questo venerdì" per riferirsi al primo venerdì successivo a oggi. – allyourcode

2

Sulla base della sua precisazione ... Penso che si possa fare qualcosa di simile:

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) 

Avviso isoweekday() torna da 1 a 7 per lunedi a domenica. 12 rappresenta il venerdì della settimana successiva. Quindi 12 - today.isoweekday() ti fornisce il delta orario corretto che devi aggiungere ad oggi.

Spero che questo aiuti.

+0

Penso che sia sbagliato. Dovrebbe effettivamente tornare il 26 marzo, poiché è attualmente dopo le 3 del venerdì. Ricorda che dovrebbe essere strettamente superiore a 7 giorni di distanza :) – mpen

+0

Forse un condizionale lo farebbe? '= Giorni 12-today.isoweekday(); se giorni <= 7: giorni + = 7'? – mpen

Problemi correlati