2010-03-13 2 views
11

Как вы можете рассчитать следующую пятницу в 3 часа ночи как объект datetime?Как рассчитать следующую пятницу в 3 часа ночи?

Разъяснение: т.е. расчетная дата всегда должна быть больше, чем за 7 дней, а меньше или равна 14.


Идущий с немного измененной версией 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

да? .......... –

+0

что будет, если это понедельник? Должен ли он рассчитать через 4 дня? Или через 11 дней? И по воскресеньям через 5 дней? Просьба уточнить! – Tom

+0

добавлено разъяснение – mpen

ответ

6

Вот функция и испытание, что она отвечает требованиям 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

Ха-ха ... очень всесторонний тест. Мне было интересно, почему так долго нужно было бежать, пока я не прочитал: D – mpen

+0

Мне очень нравится это решение. Не зависит от другой библиотеки, и это просто для изменения в другие дни/времена. – mpen

9

Если вы установили dateutil, то вы могли бы сделать что-то вроде этого:

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 

Вверху, hours=+21 сообщает relativedelta, чтобы увеличить счет dt на 21 час раньше, чем на следующей неделе. Таким образом, если dt - 12 марта 2010 года в 2 часа ночи, добавление 21 часа составляет 11 вечера того же дня, но если dt после 3 часов, то добавление 21 часа толчков dt в субботу.

Вот несколько тестовых кодов.

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

, который дает:

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 

пока до 3 утра:

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

урожайности:

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' также принимает абсолютные значения, такие как' hour', 'minute' и т. Д. Таким образом, вы можете создать дельту, которая также установит часы и минуты и секунды на результат до 3-часового. См .: http://labix.org/python-dateutil#head-6a1472b7c74e5b8bab7784f11214250d34e09aa5 –

+0

ack! Я не имел в виду, что в четверг был особый случай, это был просто пример. хотя, если мы заменим +2 на +7 ...., он должен работать правильно? – mpen

+1

@Mark: Я редактировал код, чтобы надежно соответствовать тому, что вы хотите. 'days = + 8' должен делать это, если я правильно понимаю. – unutbu

4

Мне нравится dateutil для таких задач в целом, но я не» Т понять эвристика, которую вы хотите - так как я использую слова, если я скажу «в следующую пятницу», и в четверг я буду будет означает завтра (возможно, я слишком много работал и потерял информацию о том, что это за день недели). Если вы можете точно указать свою эвристику, они, безусловно, могут быть запрограммированы, но если они странные и причудливые, вы вряд ли найдете их уже запрограммированными для вас в существующих пакетах ;-).

+0

Я не знаю, люди используют слово «следующий» неоднозначно. Как правило, люди используют «в эту пятницу», чтобы означать «в эту пятницу, а именно в течение этой недели» и «в следующую пятницу», чтобы означать «пятница, которая находится на следующей неделе». Я просто имею в виду последний. – mpen

+0

Я спорил с разными людьми о том, что означает «следующий», когда речь идет о фразах типа «в следующую пятницу». Для меня интерпретация, которая имеет наибольший смысл, будет первой пятницей, следующей сегодня, но все остальные, похоже, думают, что это означает одну вторую пятницу после сегодняшнего дня. По словам этих людей, вы бы сказали «в эту пятницу» обратиться к первой пятнице следующего дня. – allyourcode

2

Основываясь на ваших разъяснений ... Я думаю, что вы можете сделать что-то вроде этого:

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) 

Уведомление isoweekday() возвращается 1 до 7 для понедельника по воскресенье. 12 - пятница на следующей неделе. Итак, 12 - today.isoweekday() дает вам правильную временную дельту, которую вы должны добавить к сегодняшнему дню.

Надеюсь, это поможет.

+0

Я думаю, что это неправильно. Это должно фактически вернуться 26 марта, так как в настоящее время это происходит через 3 часа ночи в пятницу. Помните, что он должен быть строго больше, чем за 7 дней :) – mpen

+0

Может быть, условный будет? 'Дней = 12-today.isoweekday(); если дни <= 7: дни + = 7'? – mpen

Смежные вопросы