Finding Month from Day, Week and Year Python - python

I can not figure out how to take the year, day and week to return the month. Right now I am just trying to develop a Python Script that will do this. The goal after finishing this script is to use it for a Spark SQL Query to find the month since in my data I am given a day, year and week in each row.
As of now my python code looks like so. This code only works for the statement I have into the print(getmonth(2, 30 ,2018) returning 7. I have tried other dates and the output is only "None". I have tried variables also, but no success there.
import datetime
def month(day, week, year):
for month in range(1,13):
try:
date = datetime.datetime(year, month, day)
except ValueError:
iso_year, iso_weeknum, iso_weekday = date.isocalendar()
if iso_weeknum == week:
return date.month
print(getmonth(2, 30, 2018))
#iso_(year,weeknum,weekday) are the classes for ISO. Year is 1-9999, weeknum is 0-52 or 53, and weekday is 0-6
#isocaldenar is a tuple (year, week#, weekday)

I don't really understand your questions, but i think datetime will work... sorce: Get date from ISO week number in Python:
>>> from datetime import datetime
>>> day = 28
>>> week = 30
>>> year = 2018
>>> t = datetime.strptime('{}_{}_{}{}'.format(day,week,year,-0), '%d_%W_%Y%w')
>>> t.strftime('%W')
'30'
>>> t.strftime('%m')
'07'
>>>

A simpler solution can be created using the pendulum library. As in your code, loop through month numbers, create dates, compare the weeks for these dates against the desired date. If found halt the loop; if the date is not seen then exit the loop with, say, a -1.
>>> import pendulum
>>> for month in range(1,13):
... date = pendulum.create(2018, month, 28)
... if date.week_of_year == 30:
... break
... else:
... month = -1
...
>>> month
7
>>> date
<Pendulum [2018-07-28T00:00:00+00:00]>

Here is a brute force method that loops through the days of the year (It expects the day as Monday being 0 and Sunday being 6, it also returns the Month 0 indexed, January being 0 and December being 11):
import datetime
def month(day, week, year):
#Generate list of No of days of the month
months = [31,28,31,30,31,30,31,31,30,31,30,31]
if((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): months[1] += 1
#ISO wk1 of the yr is the first wk with a thursday, otherwise it's wk53 of the previous yr
currentWeek = 1 if day < 4 else 0
#The day that the chosen year started on
currentDay = datetime.datetime(year, 1, 1).weekday()
#Loop over every day of the year
for i in range(sum(months)):
#If the week is correct and day is correct you're done
if day == currentDay and week == currentWeek:
return months.index(next(filter(lambda x: x!=0, months)))
#Otherwise, go to next day of wk/next wk of yr
currentDay = (currentDay + 1) % 7
if currentDay == 0:
currentWeek += 1
#And decrement counter for current month
months[months.index(next(filter(lambda x: x!=0, months)))]-=1
print(month(2, 30, 2018)) # 6 i.e. July
months.index(next(filter(lambda x: x!=0, months))) is used to get the first month of that we haven't used all of the days of, i.e. the month you're currently in.

Related

Create list with days of month

Hi everyone!
I'm trying to generate list with dates of current month, but it generates wrong: from 2nd january to 1st february, I need list starts from 1st day of current month to last - 1 to 31, for example.
I have already searched the site and on Google, but so far I have not found anything. What am I doing wrong?
import datetime
year = 2021
month = 1
my_date = datetime.date(year, month, 1)
delta = datetime.timedelta(days=1)
dates = []
while my_date.month == month:
dates.append((my_date + delta).strftime('%d-%b-%Y'))
my_date += delta
print(dates)
print(len(dates))
That's because you are adding the date delta twice. Remove the first delta addition:
import datetime
year = 2021
month = 1
my_date = datetime.date(year, month, 1)
delta = datetime.timedelta(days=1)
dates = []
while my_date.month == month:
dates.append((my_date).strftime('%d-%b-%Y'))
my_date += delta
print(dates)
print(len(dates))
Output:
>>> print(dates)
['01-Jan-2021', '02-Jan-2021', '03-Jan-2021', '04-Jan-2021', '05-Jan-2021', '06-Jan-2021', '07-Jan-2021', '08-Jan-2021', '09-Jan-2021', '10-Jan-2021', '11-Jan-2021', '12-Jan-2021', '13-Jan-2021', '14-Jan-2021', '15-Jan-2021', '16-Jan-2021', '17-Jan-2021', '18-Jan-2021', '19-Jan-2021', '20-Jan-2021', '21-Jan-2021', '22-Jan-2021', '23-Jan-2021', '24-Jan-2021', '25-Jan-2021', '26-Jan-2021', '27-Jan-2021', '28-Jan-2021', '29-Jan-2021', '30-Jan-2021', '31-Jan-2021']
>>> print(len(dates))
31

For-loop for days over years, python script for targeting data

If I want to add a loop to constrain days as well, what is the easiest way to do it, considering different length of month, leap years etc.
This is the script with years and months:
yearStart = 2010
yearEnd = 2017
monthStart = 1
monthEnd = 12
for year in list(range(yearStart, yearEnd + 1)):
for month in list(range(monthStart, monthEnd + 1)):
startDate = '%04d%02d%02d' % (year, month, 1)
numberOfDays = calendar.monthrange(year, month)[1]
lastDate = '%04d%02d%02d' % (year, month, numberOfDays)
If you want only the days then this code, using the pendulum library, is probably the easiest.
>>> import pendulum
>>> first_date = pendulum.Pendulum(2010, 1, 1)
>>> end_date = pendulum.Pendulum(2018, 1, 1)
>>> for day in pendulum.period(first_date, end_date).range('days'):
... print (day)
... break
...
2010-01-01T00:00:00+00:00
pendulum has many other nice features. For one thing, it's a drop-in replacement for datetime. Therefore, many of the properties and methods that you are familiar with using for that class will also be available to you.
You may want to use datetime in addition to calendar library. I am exactly not sure on requirements. But it appears you want the first date and last date of a given month and year. And, then loop through those dates. The following function will give you the first day and last day of each month. Then, you can loop between those two dates in whichever way you want.
import datetime
import calendar
def get_first_last_day(month, year):
date = datetime.datetime(year=year, month=month, day=1)
first_day = date.replace(day = 1)
last_day = date.replace(day = calendar.monthrange(date.year, date.month)[1])
return first_day, last_day
Adding the logic for looping through 2 dates as well.
d = first_day
delta = datetime.timedelta(days=1)
while d <= last_day:
print d.strftime("%Y-%m-%d")
d += delta

How can i query for objects in current year , current month in django

I need to find total objects created in
1. current year
2. current month
3. last month
4. last year
I am thinking like this
this_year = datetime.now().year
last_year = datetime.now().year -1
this_month = datetime.now().month
last month = (datetime.today() - timedelta(days=30)).month
Use like
Order.objects.filter(created_at__month=this_month)
The problem is
last_month i want is calendar month not 30 days back
i am not sure whether created_at__month=this_month will match current month or same month in previous year
is it possible to get all counts in single query
today = datetime.datetime.now()
1 Current year
Order.objects.filter(created_at__year=today.year)
2 Current month
Order.objects.filter(created_at__year=today.year, created_at__month=today.month)
3 Last month
last_month = today.month - 1 if today.month>1 else 12
last_month_year = today.year if today.month > last_month else today.year - 1
Order.objects.filter(created_at__year=last_month_year, created_at__month=last_month)
4 Last year
last_year = today.year - 1
Order.objects.filter(created_at__year=last_year)
5 Single Query
As last year + current year includes last month and current month, and all orders>= last_year includes current year, the query is super simple:
Order.objects.filter(created_at__year__gte=last_year)
I don't think you'll be able to just match the "month" or "year" part of a date field without some significant fiddling or annotating. Most likely, your simplest solution is to define the start and end of the range you want and search against that. And that might involve a little bit of work.
For example, last calendar month would be:
today = datetime.now()
if today.month == 1:
last_month_start = datetime.date(today.year-1, 12, 1)
last_month_end = datetime.date(today.year-1, 12, 31)
else:
last_month_start = datetime.date(today.year, today.month -1, 1)
last_month_end = datetime.date(today.year, today.month, 1) - datetime.timedelta(days=1)
Order.objects.filter(created_at__gte=last_month_start, created_at__lte=last_month_end)
GTE and LTE are "greater than or equal" and "less than or equal". Also worth noting, we use timedelta to figure out what the day before the first of this month is rather than go through all the different cases of whether the previous month had 28, 29, 30 or 31 days.
If you want it in separate queries, do something like that.
from_this_year = Order.objects.filter(created_at__year=this_year)
from_last_year = Order.objects.filter(created_at__year=last_year)
from_june = Order.objects.filter(created_at__month='06',created_at__year=this_year)
from_this_month = Order.objects.filter(created_at__month=this_month,created_at__year=this.year)
note: in my example, I put '06' that is June, but you can change it.

Algorithm for getting current week number after changing the starting day of the week in python?

I want to design an algorithm which will calculate the week number according to the start week day set. for eg : - If I set the start day as WEDNESDAY and currently its 40 week and its TUESDAY, it should print 40 as the week number. If it is WEDNESDAY or THURSDAY, I should get 41.
Think of it like a cycle. From Wednesday till tuesday, it should be assigned a week no + 1, then when next wednesday comes, week should be incremented again.
I tried using calendar.setfirstweekday(calendar.WEDNESDAY) and then altering my system machine time, all I get is 40 as the week number everytime.
How do I design such as algorithm in python?
I have a similar problem for month, but I have designed a solution for it. Here is it.
current_date = datetime.datetime.now()
if current_date.day < gv.month_start_date:
month = current_date.month -1
if month == 0:
month = 12
else:
month = current_date.month
How can I design it for week?
I finally designed a solution for this.
if current_day >= set_week_day:
week = current_week
else:
week = current_week - 1
Works for all cases.
datetime in python has a function called isocalender to get the ISO week number (starts on Monday)
import datetime
datetime.date(2013, 9, 30).isocalendar()[1]
You can use this with a little bit of logic (this script should have the week begin on Wednesdays)
import datetime
day = 30
month = 9
year = 2013
weekcount = datetime.date(year, month, day).isocalendar()[1]
if datetime.date(year, month, day).isocalendar()[2] <= 3: # start on wednesday
weekcount -= 1
print weekcount

How to get week number in Python?

How to find out what week number is current year on June 16th (wk24) with Python?
datetime.date has a isocalendar() method, which returns a tuple containing the calendar week:
>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar()[1]
24
datetime.date.isocalendar() is an instance-method returning a tuple containing year, weeknumber and weekday in respective order for the given date instance.
In Python 3.9+ isocalendar() returns a namedtuple with the fields year, week and weekday which means you can access the week explicitly using a named attribute:
>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar().week
24
You can get the week number directly from datetime as string.
>>> import datetime
>>> datetime.date(2010, 6, 16).strftime("%V")
'24'
Also you can get different "types" of the week number of the year changing the strftime parameter for:
%U - Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0. Examples: 00, 01, …, 53
%W - Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. Examples: 00, 01, …, 53
[...]
(Added in Python 3.6, backported to some distribution's Python 2.7's) Several additional directives not required by the C89 standard are included for convenience. These parameters all correspond to ISO 8601 date values. These may not be available on all platforms when used with the strftime() method.
[...]
%V - ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 4. Examples: 01, 02, …, 53
from: datetime — Basic date and time types — Python 3.7.3 documentation
I've found out about it from here. It worked for me in Python 2.7.6
I believe date.isocalendar() is going to be the answer. This article explains the math behind ISO 8601 Calendar. Check out the date.isocalendar() portion of the datetime page of the Python documentation.
>>> dt = datetime.date(2010, 6, 16)
>>> wk = dt.isocalendar()[1]
24
.isocalendar() return a 3-tuple with (year, wk num, wk day). dt.isocalendar()[0] returns the year,dt.isocalendar()[1] returns the week number, dt.isocalendar()[2] returns the week day. Simple as can be.
There are many systems for week numbering. The following are the most common systems simply put with code examples:
ISO: First week starts with Monday and must contain the January 4th (or first Thursday of the year). The ISO calendar is already implemented in Python:
>>> from datetime import date
>>> date(2014, 12, 29).isocalendar()[:2]
(2015, 1)
North American: First week starts with Sunday and must contain the January 1st. The following code is my modified version of Python's ISO calendar implementation for the North American system:
from datetime import date
def week_from_date(date_object):
date_ordinal = date_object.toordinal()
year = date_object.year
week = ((date_ordinal - _week1_start_ordinal(year)) // 7) + 1
if week >= 52:
if date_ordinal >= _week1_start_ordinal(year + 1):
year += 1
week = 1
return year, week
def _week1_start_ordinal(year):
jan1 = date(year, 1, 1)
jan1_ordinal = jan1.toordinal()
jan1_weekday = jan1.weekday()
week1_start_ordinal = jan1_ordinal - ((jan1_weekday + 1) % 7)
return week1_start_ordinal
>>> from datetime import date
>>> week_from_date(date(2014, 12, 29))
(2015, 1)
MMWR (CDC): First week starts with Sunday and must contain the January 4th (or first Wednesday of the year). I created the epiweeks package specifically for this numbering system (also has support for the ISO system). Here is an example:
>>> from datetime import date
>>> from epiweeks import Week
>>> Week.fromdate(date(2014, 12, 29))
(2014, 53)
Here's another option:
import time
from time import gmtime, strftime
d = time.strptime("16 Jun 2010", "%d %b %Y")
print(strftime(d, '%U'))
which prints 24.
See: http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior
The ISO week suggested by others is a good one, but it might not fit your needs. It assumes each week begins with a Monday, which leads to some interesting anomalies at the beginning and end of the year.
If you'd rather use a definition that says week 1 is always January 1 through January 7, regardless of the day of the week, use a derivation like this:
>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24
Generally to get the current week number (starts from Sunday):
from datetime import *
today = datetime.today()
print today.strftime("%U")
For the integer value of the instantaneous week of the year try:
import datetime
datetime.datetime.utcnow().isocalendar()[1]
If you are only using the isocalendar week number across the board the following should be sufficient:
import datetime
week = date(year=2014, month=1, day=1).isocalendar()[1]
This retrieves the second member of the tuple returned by isocalendar for our week number.
However, if you are going to be using date functions that deal in the Gregorian calendar, isocalendar alone will not work! Take the following example:
import datetime
date = datetime.datetime.strptime("2014-1-1", "%Y-%W-%w")
week = date.isocalendar()[1]
The string here says to return the Monday of the first week in 2014 as our date. When we use isocalendar to retrieve the week number here, we would expect to get the same week number back, but we don't. Instead we get a week number of 2. Why?
Week 1 in the Gregorian calendar is the first week containing a Monday. Week 1 in the isocalendar is the first week containing a Thursday. The partial week at the beginning of 2014 contains a Thursday, so this is week 1 by the isocalendar, and making date week 2.
If we want to get the Gregorian week, we will need to convert from the isocalendar to the Gregorian. Here is a simple function that does the trick.
import datetime
def gregorian_week(date):
# The isocalendar week for this date
iso_week = date.isocalendar()[1]
# The baseline Gregorian date for the beginning of our date's year
base_greg = datetime.datetime.strptime('%d-1-1' % date.year, "%Y-%W-%w")
# If the isocalendar week for this date is not 1, we need to
# decrement the iso_week by 1 to get the Gregorian week number
return iso_week if base_greg.isocalendar()[1] == 1 else iso_week - 1
I found these to be the quickest way to get the week number; all of the variants.
from datetime import datetime
dt = datetime(2021, 1, 3) # Date is January 3rd 2021 (Sunday), year starts with Friday
dt.strftime("%W") # '00'; Monday is considered first day of week, Sunday is the last day of the week which started in the previous year
dt.strftime("%U") # '01'; Sunday is considered first day of week
dt.strftime("%V") # '53'; ISO week number; result is '53' since there is no Thursday in this year's part of the week
Further clarification for %V can be found in the Python doc:
The ISO year consists of 52 or 53 full weeks, and where a week starts on a Monday and ends on a Sunday. The first week of an ISO year is the first (Gregorian) calendar week of a year containing a Thursday. This is called week number 1, and the ISO year of that Thursday is the same as its Gregorian year.
https://docs.python.org/3/library/datetime.html#datetime.date.isocalendar
NOTE: Bear in mind the return value is a string, so pass the result to a int constructor if you need a number.
I summarize the discussion to two steps:
Convert the raw format to a datetime object.
Use the function of a datetime object or a date object to calculate the week number.
Warm up
from datetime import datetime, date, time
d = date(2005, 7, 14)
t = time(12, 30)
dt = datetime.combine(d, t)
print(dt)
1st step
To manually generate a datetime object, we can use datetime.datetime(2017,5,3) or datetime.datetime.now().
But in reality, we usually need to parse an existing string. we can use strptime function, such as datetime.strptime('2017-5-3','%Y-%m-%d') in which you have to specific the format. Detail of different format code can be found in the official documentation.
Alternatively, a more convenient way is to use dateparse module. Examples are dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12') or dateparser.parse('2017-5-3')
The above two approaches will return a datetime object.
2nd step
Use the obtained datetime object to call strptime(format). For example,
python
dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object. This day is Sunday
print(dt.strftime("%W")) # '00' Monday as the 1st day of the week. All days in a new year preceding the 1st Monday are considered to be in week 0.
print(dt.strftime("%U")) # '01' Sunday as the 1st day of the week. All days in a new year preceding the 1st Sunday are considered to be in week 0.
print(dt.strftime("%V")) # '52' Monday as the 1st day of the week. Week 01 is the week containing Jan 4.
It's very tricky to decide which format to use. A better way is to get a date object to call isocalendar(). For example,
python
dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object
d = dt.date() # convert to a date object. equivalent to d = date(2017,1,1), but date.strptime() don't have the parse function
year, week, weekday = d.isocalendar()
print(year, week, weekday) # (2016,52,7) in the ISO standard
In reality, you will be more likely to use date.isocalendar() to prepare a weekly report, especially in the Christmas-New Year shopping season.
You can try %W directive as below:
d = datetime.datetime.strptime('2016-06-16','%Y-%m-%d')
print(datetime.datetime.strftime(d,'%W'))
'%W': Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. (00, 01, ..., 53)
For pandas users, if you want to get a column of week number:
df['weekofyear'] = df['Date'].dt.week
isocalendar() returns incorrect year and weeknumber values for some dates:
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime as dt
>>> myDateTime = dt.datetime.strptime("20141229T000000.000Z",'%Y%m%dT%H%M%S.%fZ')
>>> yr,weekNumber,weekDay = myDateTime.isocalendar()
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2015, weekNumber is 1
Compare with Mark Ransom's approach:
>>> yr = myDateTime.year
>>> weekNumber = ((myDateTime - dt.datetime(yr,1,1)).days/7) + 1
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2014, weekNumber is 52
Let's say you need to have a week combined with the year of the current day as a string.
import datetime
year,week = datetime.date.today().isocalendar()[:2]
week_of_the_year = f"{year}-{week}"
print(week_of_the_year)
You might get something like 2021-28
If you want to change the first day of the week you can make use of the calendar module.
import calendar
import datetime
calendar.setfirstweekday(calendar.WEDNESDAY)
isodate = datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
week_of_year = isodate[1]
For example, calculate the sprint number for a week starting on WEDNESDAY:
def calculate_sprint(sweek):
calendar.setfirstweekday(calendar.WEDNESDAY)
isodate=datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
return "{year}-{month}".format(year=isodate[0], month=isodate[1])
calculate_sprint('2021-01-01')
>>>'2020-53'
We have a similar issue and we came up with this logic
I have tested for 1year test cases & all passed
import datetime
def week_of_month(dt):
first_day = dt.replace(day=1)
dom = dt.day
if first_day.weekday() == 6:
adjusted_dom = dom
else:
adjusted_dom = dom + first_day.weekday()
if adjusted_dom % 7 == 0 and first_day.weekday() != 6:
value = adjusted_dom / 7.0 + 1
elif first_day.weekday() == 6 and adjusted_dom % 7 == 0 and adjusted_dom == 7:
value = 1
else:
value = int(ceil(adjusted_dom / 7.0))
return int(value)
year = 2020
month = 01
date = 01
date_value = datetime.datetime(year, month, date).date()
no = week_of_month(date_value)
userInput = input ("Please enter project deadline date (dd/mm/yyyy/): ")
import datetime
currentDate = datetime.datetime.today()
testVar = datetime.datetime.strptime(userInput ,"%d/%b/%Y").date()
remainDays = testVar - currentDate.date()
remainWeeks = (remainDays.days / 7.0) + 1
print ("Please pay attention for deadline of project X in days and weeks are : " ,(remainDays) , "and" ,(remainWeeks) , "Weeks ,\nSo hurryup.............!!!")
A lot of answers have been given, but id like to add to them.
If you need the week to display as a year/week style (ex. 1953 - week 53 of 2019, 2001 - week 1 of 2020 etc.), you can do this:
import datetime
year = datetime.datetime.now()
week_num = datetime.date(year.year, year.month, year.day).strftime("%V")
long_week_num = str(year.year)[0:2] + str(week_num)
It will take the current year and week, and long_week_num in the day of writing this will be:
>>> 2006

Categories

Resources