from time import *
import re
from sys import exit
dico = {'Monday':0,'monday':0,'Tuesday':1,'tuesday':1,
'Wednesday':2,'wednesday':2,'Thursday':3,'thursday':3,
'Friday':4,'friday':4,'Saturday':5,'saturday':5,
'Sunday':6,'sunday':6}
regx = re.compile('((\d{4})-(\d\d)-(\d\d))\s+(%s)' % '|'.join(dico.iterkeys()))
for s in ('2011-08-10 Wednesday', '2011-08-25 Thursday', '2011-08-30 Tuesday',
'2011-12-04 Sunday', '2011-12-30 Friday',
'2012-02-18 Saturday', '2012-02-25 Saturday', '2012-02-29 Wednesday '):
print 's == ' + s
try:
the_date,y,m,d,day_name = regx.match(s).groups()
wday = dico[day_name]
except:
mess = "The string isn't expressing a date correctly"
exit(mess)
try:
s_strp = strptime(the_date,'%Y-%m-%d')
except:
mess = "The date isn't an existing date"
exit(mess)
if s_strp.tm_wday != wday:
mess = 'The name of week-day in the string is incoherent with the date'
exit(mess)
n = (int(d)-1)//7
print '(y,m,d,day_name,wday,n) ==',(y,m,d,day_name,wday,n)
print 'The day %s is the %sth %s in the month %s\n' % (d,n+1,day_name,y+'-'+m)
yp,mp = (int(y)+1, 1) if m=='12' else (int(y), int(m)+1)
next_month = ('%s-%s-%s' % (yp,mp,dp) for dp in xrange(1,32))
same_days = []
for day in next_month:
try:
if strptime(day,'%Y-%m-%d').tm_wday==wday: same_days.append(day)
except:
break
print '%s days in the next month are :\n%s' % (day_name,same_days)
try:
print 'The %sth %s in the next month is on date %s' % (n+1,day_name,same_days[n])
except:
print 'The last %s (%sth) in the next month is on date %s' % (day_name,n,same_days[n-1])
print '\n-------------------------------------------------------------'
результат
s == 2011-08-10 Wednesday
(y,m,d,day_name,wday,n) == ('2011', '08', '10', 'Wednesday', 2, 1)
The day 10 is the 2th Wednesday in the month 2011-08
Wednesday days in the next month are :
['2011-9-7', '2011-9-14', '2011-9-21', '2011-9-28']
The 2th Wednesday in the next month is on date 2011-9-14
-------------------------------------------------------------
s == 2011-08-25 Thursday
(y,m,d,day_name,wday,n) == ('2011', '08', '25', 'Thursday', 3, 3)
The day 25 is the 4th Thursday in the month 2011-08
Thursday days in the next month are :
['2011-9-1', '2011-9-8', '2011-9-15', '2011-9-22', '2011-9-29']
The 4th Thursday in the next month is on date 2011-9-22
-------------------------------------------------------------
s == 2011-08-30 Tuesday
(y,m,d,day_name,wday,n) == ('2011', '08', '30', 'Tuesday', 1, 4)
The day 30 is the 5th Tuesday in the month 2011-08
Tuesday days in the next month are :
['2011-9-6', '2011-9-13', '2011-9-20', '2011-9-27']
The last Tuesday (4th) in the next month is on date 2011-9-27
-------------------------------------------------------------
s == 2011-12-04 Sunday
(y,m,d,day_name,wday,n) == ('2011', '12', '04', 'Sunday', 6, 0)
The day 04 is the 1th Sunday in the month 2011-12
Sunday days in the next month are :
['2012-1-1', '2012-1-8', '2012-1-15', '2012-1-22', '2012-1-29']
The 1th Sunday in the next month is on date 2012-1-1
-------------------------------------------------------------
s == 2011-12-30 Friday
(y,m,d,day_name,wday,n) == ('2011', '12', '30', 'Friday', 4, 4)
The day 30 is the 5th Friday in the month 2011-12
Friday days in the next month are :
['2012-1-6', '2012-1-13', '2012-1-20', '2012-1-27']
The last Friday (4th) in the next month is on date 2012-1-27
-------------------------------------------------------------
s == 2012-02-18 Saturday
(y,m,d,day_name,wday,n) == ('2012', '02', '18', 'Saturday', 5, 2)
The day 18 is the 3th Saturday in the month 2012-02
Saturday days in the next month are :
['2012-3-3', '2012-3-10', '2012-3-17', '2012-3-24', '2012-3-31']
The 3th Saturday in the next month is on date 2012-3-17
-------------------------------------------------------------
s == 2012-02-25 Saturday
(y,m,d,day_name,wday,n) == ('2012', '02', '25', 'Saturday', 5, 3)
The day 25 is the 4th Saturday in the month 2012-02
Saturday days in the next month are :
['2012-3-3', '2012-3-10', '2012-3-17', '2012-3-24', '2012-3-31']
The 4th Saturday in the next month is on date 2012-3-24
-------------------------------------------------------------
s == 2012-02-29 Wednesday
(y,m,d,day_name,wday,n) == ('2012', '02', '29', 'Wednesday', 2, 4)
The day 29 is the 5th Wednesday in the month 2012-02
Wednesday days in the next month are :
['2012-3-7', '2012-3-14', '2012-3-21', '2012-3-28']
The last Wednesday (4th) in the next month is on date 2012-3-28
-------------------------------------------------------------
Со строкой '2011-08-11 Понедельник' результат:
Traceback (most recent call last):
File "I:\wednesday.py", line 37, in <module>
exit(mess)
SystemExit: The name of week-day in the string is incoherent with the date
Со строкой '2011-34-58 Monday' выдается ошибка:
Traceback (most recent call last):
File "I:\wednesday.py", line 33, in <module>
exit(mess)
SystemExit: The date isn't an existing date
Редактировать 1
Я был недоволен своим кодом: он плохо читается
Следующий более понятен
Обратите внимание, что в этом новом коде N не имеет того же значения, что и n в предыдущем коде
from time import strptime
import re
from sys import exit
from datetime import date,timedelta
dico = {'Monday':0,'monday':0,'Tuesday':1,'tuesday':1,
'Wednesday':2,'wednesday':2,'Thursday':3,'thursday':3,
'Friday':4,'friday':4,'Saturday':5,'saturday':5,
'Sunday':6,'sunday':6}
regx = re.compile('((\d{4})-(\d\d)-(\d\d))\s+(%s)' % '|'.join(dico.iterkeys()))
for s in ('2011-08-10 Wednesday', '2011-08-25 Thursday', '2011-08-30 Tuesday',
'2011-12-04 Sunday', '2011-12-30 Friday',
'2012-02-18 Saturday', '2012-02-25 Saturday', '2012-02-29 Wednesday ',
'2011-07-24 sunday', '2011-07-25 monday',
'2011-10-28 friday', '2011-10-30 monday'):
print 's == ' + s
# Verifications ----------------------------------------------------------------
try:
the_date,y,m,d,day_name = regx.match(s).groups()
wday = dico[day_name]
except:
mess = "The string isn't expressing a date correctly"
exit(mess)
else:
try:
s_strp = strptime(the_date,'%Y-%m-%d')
except:
mess = "The date isn't an existing date"
exit(mess)
else:
if s_strp.tm_wday != wday:
mess = 'The name of week-day in the string is incoherent with the date'
exit(mess)
# Extraction of needed info -----------------------------------------------------
y,m,d = map(int,(y,m,d)) # y,m,d = year,month,day
N = (d-1)//7 + 1 # N is in (1,2,3,4,5) , it tells if the week-day is the first/2nd/3nd/4th/5th in the month
print '(y,m,d,day_name,wday,N) ==',(y,m,d,day_name,wday,N)
print 'The day %s is the %sth %s in the month %s-%s\n' % (d,N,day_name,y,m)
# Finding the desired next date -------------------------------------------------
ahead = (date(y,m,d) + timedelta(weeks=i) for i in (1,2,3,4,5))
# this generator yields the 5 next dates of same week-day name after the date 'y-m-d' because the date 'y-m-d'
# and the date of same week-day name and same position in the next month can't be separated by more than 5 weeks
cnt = 0
for xd in ahead:
cnt += (xd.month != m) # cnt is incremented only if xd is a same week-day in the next month
if cnt in (N,4):
# There is no couple of adjacent months in a year
# having a given week-day name present 5 times in each of them
# Then if N==5, cnt can't be 5
print 'The %sth %s %s in the next month is on date %s' % (cnt,day_name,'(the last)' if N==5 else '',xd)
break
print '\n-------------------------------------------------------------'
Редактировать 2
Аааааааааа! У меня было чувство, что результат может быть найден в очень немногих строках, и я, наконец, получил его.
Нет необходимости в dateutil, нет необходимости в моих сложных предыдущих решениях, следующий код выполняет работу в 4 строки!
import re
from sys import exit
from datetime import date,timedelta
from time import strptime
dico = {'Monday':0,'monday':0,'Tuesday':1,'tuesday':1,
'Wednesday':2,'wednesday':2,'Thursday':3,'thursday':3,
'Friday':4,'friday':4,'Saturday':5,'saturday':5,
'Sunday':6,'sunday':6}
regx = re.compile('((\d{4})-(\d\d)-(\d\d))\s+(%s)' % '|'.join(dico.iterkeys()))
for s in ('2011-08-10 Wednesday', '2011-08-25 Thursday', '2011-08-30 Tuesday',
'2011-12-04 Sunday', '2011-12-30 Friday',
'2012-02-18 Saturday', '2012-02-25 Saturday', '2012-02-29 Wednesday ',
'2011-07-24 sunday', '2011-07-25 monday',
'2011-10-28 friday', '2011-10-30 monday'):
print 's == ' + s
# --- Verifications ----------------------------------------------------------------
mess = ("The string isn't expressing a date correctly",
"The date isn't an existing date",
'The name of week-day in the string is incoherent with the date')
try:
the_date,y,m,d,weekday_name = regx.match(s).groups()
except:
exit(mess[0])
else:
try:
y,m,d = map(int,(y,m,d))
xdate = date(y,m,d)
except:
exit(mess[1])
else:
if strptime(the_date,'%Y-%m-%d').tm_wday != dico[weekday_name]:
exit(mess[2])
# --- Extraction of the position of the day in the month ----------------------------
n = (d-1)//7
# n is in (0,1,2,3,4) , it tells the position of the input day
# among the list of same week-days in the month
# --- Going to the first next same week-day in the next month------------------------
while xdate.month == m:
xdate = xdate + timedelta(weeks=1)
# this loop makes xdate to be incremented of one week until reaching the next month
# --- Displaying the extracted data and the result ----------------------------------
print '(y,m,d,weekday_name,dico[weekday_name],n) ==',(y,m,d,weekday_name,dico[weekday_name],n)
print 'The day %s is the %sth %s in the month %s-%s\n' % (d,n+1,weekday_name,y,m)
# There is no couple of adjacent months in a year having a given week-day name
# present 5 times (that is to say at position 4) in each of them.
# Then if n==4, the desired next date can't be xdate + timedelta(weeks=4))
print 'The %sth %s %s in the next month is on date %s' \
% (min(n,3)+1,weekday_name,'(the last)' if n==4 else '',xdate + timedelta(weeks=min(n,3)))
print '\n-------------------------------------------------------------'
Редактировать 3
Принимая во внимание замечание unutbu , которое показало, что мой код неясен относительно причины, по которой необходимо писать timedelta(weeks=min(n,3))
, я попытался найти другой алгоритм, чтобы избежать этой инструкции min (n, 3) .
Но в конце концов я понял, что ни один алгоритм не может решить сам, что он должен делать, когда невозможно найти пятый день недели в следующем месяце. У автора кода нет другого выбора, чтобы тот, кто понимает, что этот случай существует, и решил принять 4-й день недели вместо 5-го.
Так что я сохранил общий принцип моего кода. Но я немного изменил его, чтобы сделать более понятным использование значения weekday_appear вместо прежнего n . Я думаю, что следующий легко понятный код более понятен и прост в написании.
for s in ('2011-08-10 Wednesday', '2011-08-25 Thursday', '2011-08-30 Tuesday',
'2011-12-04 Sunday', '2011-12-30 Friday',
'2012-02-18 Saturday', '2012-02-25 Saturday', '2012-02-29 Wednesday ',
'2011-07-24 sunday', '2011-07-25 monday',
'2011-10-28 friday', '2011-10-30 monday'):
print 's == ' + s
# --- Verifications --------------------------------------------------------
mess = ("The string isn't expressing a date correctly",
"The date isn't an existing date",
'The name of week-day in the string is incoherent with the date')
try:
the_date,y,m,d,wkd_name = regx.match(s).groups()
print '(y,m,d,wkd_name) ==',(y,m,d,wkd_name)
except:
exit(mess[0])
else:
try:
y,m,d = map(int,(y,m,d))
xdate = date(y,m,d)
except:
exit(mess[1])
else:
if xdate.weekday() != dico[wkd_name]:
exit(mess[2])
# --- Extraction of the number of the weekday in the month ---------------
weekday_appear = (d+6)//7
print 'weekday_appear == %s' % weekday_appear
# weekday_appear is 1 if 1<=d<=7, 2 if 8<=d<=14 ... 5 if 29<=d<=31
# It tells if the input weekday is the 1st/2nd/3rd/4th/5th
# among the list of same weekdays in the month
# --- Going to the last same weekday in the month-------------------------
for deltadays in (7,14,21,28):
try:
xdate= date(y,m,d+deltadays)
except:
break
# after this loop, xdate is the last date in the month having the same
# weekday name as input date
# --- Displaying the result ----------------------------------------------
# There is no couple of adjacent months in a year in which a given weekday
# name can be present 5 times in each of the two months .
# Then, when it happens that wkd_appear==5 in the input month, it is sure
# that the desired weekday in the next month can't be the 5th one in this
# month. In the case, we will take the last of the dates with same weekday
# name in the next month, that is to say the 4th such date.
# That's the reason of the following reduction:
next_appear = min(4, weekday_appear)
# By the way, the fact that every month in a year have a minimum of 4*7
# days is the reason why it is sure to find at least 4 times in a month
# any weekday name, whatever which one it is.
print 'The %sth %s %s in the next month is on date %s' \
% (next_appear, wkd_name, ('','(the last)')[weekday_appear==5],
xdate + timedelta(weeks=next_appear))
print '\n-------------------------------------------------------------'