I want to count summer days between two dates. Summer is May first to August last.
This will count all days:
import datetime
startdate=datetime.datetime(2015,1,1)
enddate=datetime.datetime(2016,6,1)
delta=enddate-startdate
print delta.days
>>517
But how can only count the passed summer days?
You could define a generator to iterate over every date between startdate and enddate, define a function to check if a date represents a summer day and use sum to count the summer days:
import datetime
startdate = datetime.datetime(2015,1,1)
enddate = datetime.datetime(2016,6,1)
all_dates = (startdate + datetime.timedelta(days=x) for x in range(0, (enddate-startdate).days))
def is_summer_day(date):
return 5 <= date.month <= 8
print(sum(1 for date in all_dates if is_summer_day(date)))
# 154
Thanks to the generator, you don't need to create a huge list in memory with every day between startdate and enddate.
This iteration still considers every single day, even if it's not needed. For very large gaps, you could use the fact that every complete year has 123 summer days according to your definition.
You can create a few functions to count how many summer days you have between two days:
from datetime import date
def get_summer_start(year):
return date(year, 5, 1)
def get_summer_end(year):
return date(year, 8, 31)
def get_start_date(date, year):
return max(date, get_summer_start(year))
def get_end_date(date, year):
return min(date, get_summer_end(year))
def count_summer_days(date1, date2):
date1_year = date1.year
date2_year = date2.year
if date1_year == date2_year:
s = get_start_date(date1, date1_year)
e = get_end_date(date2, date1_year)
return (e - s).days
else:
s1 = max(date1, get_summer_start(date1_year))
e1 = get_summer_end(date1_year)
first_year = max(0,(e1 -s1).days)
s1 = get_summer_start(date2_year)
e1 = min(date2, get_summer_end(date2_year))
last_year = max(0,(e2 -s2).days)
other_years = date2_year - date1_year - 1
summer_days_per_year = (get_summer_end(date1_year) - get_summer_start(date1_year)).days
return first_year + last_year + (other_years * summer_days_per_year)
date1 = date(2015,1,1)
date2 = date(2016,6,1)
print count_summer_days(date1, date2)
Here is a better solution for large periods:
first_summer_day = (5,1)
last_summer_day = (8,31)
from datetime import date
startdate = date(2015,1,1)
enddate = date(2016,6,1)
# make sure that startdate > endate
if startdate > enddate:
startdate, endate = endate, startdate
def iter_yearly_summer_days(startdate, enddate):
for year in range(startdate.year, enddate.year+1):
start_period = startdate if year == startdate.year else date(year, 1, 1)
end_period = enddate if year == enddate.year else date(year, 12, 31)
year_first_summer_day = date(year, *first_summer_day)
year_last_summer_day = date(year, *last_summer_day)
summer_days_that_year = (min(year_last_summer_day, end_period) - max(year_first_summer_day, start_period)).days
print('year {} had {} days of summer'.format(year, summer_days_that_year))
yield summer_days_that_year
print(sum(iter_yearly_summer_days(startdate, enddate)))
Related
This is the code I have so far:
from calendar import isleap
import datetime
year =2021
month= 4
year2=2022
months_choices=[]
for i in range(1, 5):
month = datetime.date(2021, i, 1).strftime('%b')
startDate = f"01-Dec-{year}"
if month in ["Jan", "Mar", "May", "Jul", "Aug", "Oct", "Dec"]:
endDate = f"31-{month}-{year}"
elif month in ["Apr", "Jun", "Sep", "Nov"]:
endDate = f"30-{month}-{year}"
else:
isLeap = isleap(1900)
if isLeap:
endDate = f"29-{month}-{year}"
else:
endDate = f"28-{month}-{year}"
months_choices.append((startDate, endDate))
print(months_choices)
I would like my output to print as [('01-Dec-2021', '31-Dec-2021'), ('01-Jan-2022', '31-Jan-2022'), ('01-Feb-2022', '28-Feb-2022'), ('01-March-2021', '31-March-2021'),('01-April-2021', '30-Apr-2021')], but it prints like below.
print(months_choices)
[('01-Dec-2021', '31-Jan-2021'), ('01-Dec-2021', '28-Feb-2021'), ('01-Dec-2021', '31-Mar-2021'), ('01-Dec-2021', '30-Apr-2021')]
The calendar module has some very useful features that you could utilise.
As a starting point you would benefit from having a function that takes the start month/year and end month/year.
Something like this:
from calendar import monthrange, month_abbr
def range_ok(start_month, start_year, end_month, end_year):
if start_month < 1 or start_month > 12 or end_month < 1 or end_month > 12:
return False
if start_year > end_year or (start_year == end_year and start_month > end_month):
return False
return True
def func(start_month, start_year, end_month, end_year):
result = []
while range_ok(start_month, start_year, end_month, end_year):
mn = month_abbr[start_month]
d1 = f'01-{mn}-{start_year}'
sd = monthrange(start_year, start_month)[1]
d2 = f'{sd}-{mn}-{start_year}'
result.append((d1, d2))
if (start_month := start_month + 1) > 12:
start_month = 1
start_year += 1
return result
print(func(12, 2021, 4, 2022))
Output:
[('01-Dec-2021', '31-Dec-2021'), ('01-Jan-2022', '31-Jan-2022'), ('01-Feb-2022', '28-Feb-2022'), ('01-Mar-2022', '31-Mar-2022'), ('01-Apr-2022', '30-Apr-2022')]
EDIT
As requested in the comments, in order to generate the date range between two dates, the solution can be adjusted like this:
import pandas as pd
import calendar
from datetime import date
start_date = '2021-12-01'
end_date = '2022-04-30'
date_range = pd.date_range(start_date,end_date,
freq='MS').map(lambda x: (x.year, x.month)).tolist()
def get_dates(year, month):
return (date(year, month, 1).strftime("%d-%b-%Y"),
date(year,
month,
calendar.monthrange(year, month)[1]
).strftime("%d-%b-%Y"))
[get_dates(year, month)
for year, month in date_range]
Original solution
Use calendar.monthrange(YEAR, MONTH) to get the last day of the month. It handles the leap years for you.
import calendar
from datetime import date
years = [2021,2022]
months = [range(12, 13), range(1,5)]
def get_dates(year, month):
return (date(year, month, 1).strftime("%d-%b-%Y"),
date(year,
month,
calendar.monthrange(year, month)[1]
).strftime("%d-%b-%Y"))
[get_dates(year, month)
for year, month_range in zip(years, months)
for month in month_range]
Output:
[('01-Dec-2021', '31-Dec-2021'),
('01-Jan-2022', '31-Jan-2022'),
('01-Feb-2022', '28-Feb-2022'),
('01-Mar-2022', '31-Mar-2022'),
('01-Apr-2022', '30-Apr-2022')]
I have this code
today = datetime.now().date()
# prints: 2022/1/14
rd = REL.relativedelta(days=1, weekday=REL.SU)
nextSunday = today + rd
#prints : 2022/1/16
How do i add 10 hours to the date so i can get a variable nextSunday_10am that i can substract to the current time
difference = nextSunday_10am - today
and schedule what I need to do
You can do the same thing as suggested by #Dani3le_ more directly with the following:
def getSundayTime(tme: datetime.date) -> datetime:
nxt_sndy = tme + timedelta(days= 6 - tme.weekday())
return datetime.combine(nxt_sndy, datetime.strptime('10:00', '%H:%M').time())
This will compute calculate the next Sunday and set time to 10:00
You can add hours to a DateTime by using datetime.timedelta().
nextSunday += datetime.timedelta(hours=10)
For example:
import datetime
today = datetime.datetime.today()
print("Today is "+str(today))
while today.weekday()+1 != 6: #0 = "Monday", 1 = "Tuesday"...
today += datetime.timedelta(1)
nextSunday = today + datetime.timedelta(hours=10)
print("Next sunday +10hrs will be "+str(nextSunday))
I am trying to filter a query set to obtain this year's all posts.
def thisYearQuerySet(objects):
start_day = datetime.date(datetime.date.today().year, 1, 1)
end_day = datetime.date(datetime.date.today().year, 12, 31)
return objects.filter(date__range=[start_day, end_day])
django moans about start_day and end_day declaration may conflicts django.utils.timezone, I think it is not a big deal.
But the warning is annoying, any suggestion on dismissing it (not disable django warning) will be appreciated. something like, how to get first day of the year and the last from django.utils
full warning
RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-01-01 00:00:00) while time zone support is active.
RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-12-31 00:00:00) while time zone support is active.
it seems I must set a region to dismiss the warning.
I attached the module implemented in my project that have methods may help you.
import pytz
import datetime
from django.utils import timezone
from django.conf import settings
from django.db.models import Q
from django.utils.dateparse import parse_datetime
# MM/DD/YY
def when(create):
return '%s/%s/%s' % (create.month, create.day, create.year)
def current():
return when(timezone.now())
# create: date of object creation
# now: time now
# li: a list of string indicate time (in any language)
# lst: suffix (in any language)
# long: display length
def howLongAgo(
create,
now,
# li=[
# 'sec',
# 'min',
# 'h',
# 'day',
# 'week',
# 'month',
# 'year',
# ],
li=[
'秒',
'分',
'时',
'天',
'周',
'月',
'年',
],
# lst='ago',
lst='之前',
long=2
):
dif = create - now
sec = dif.days * 24 * 60 * 60 + dif.seconds
minute = sec // 60
sec %= 60
hour = minute // 60
minute %= 60
day = hour // 24
hour %= 24
week = day // 7
day %= 7
month = (week * 7) // 30
week %= 30
year = month // 12
month %= 12
s = []
for ii, tt in enumerate([sec, minute, hour, day, week, month, year]):
ss = li[ii]
if tt != 0:
s.append(str(tt) + ss)
# if tt == 1:
# s.append(str(tt) + ss)
# else:
# s.append(str(tt) + ss + 's')
return ' '.join(list(reversed(s))[:long]) + lst
# conversion
def dateToDatetime(li):
res = []
for ar in li:
res.append(datetime.datetime.combine(ar, datetime.datetime.min.time()))
return res
def datespan(startDate, endDate, delta=datetime.timedelta(days=1)):
currentDate = startDate
while currentDate < endDate:
yield currentDate
currentDate += delta
# queryset
def thisMonthQuerySet(objects):
today = timezone.now()
year = today.year
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, today.month, 1)))
end_day = start_day + datetime.timedelta(30)
return objects.filter(date__range=[start_day, end_day])
def lastMonthQuerySet(objects):
today = timezone.now()
year = today.year
month = today.month - 1
if month == 0:
year -= 1
month = 12
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, month, 1)))
end_day = start_day + datetime.timedelta(30)
return objects.filter(date__range=[start_day, end_day])
def thisYearQuerySet(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
return objects.filter(date__range=[start_day, end_day])
def lastYearQuerySet(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
return objects.filter(date__range=[start_day, end_day])
def lastQuaterQuerySet(objects):
today = timezone.now()
four_month_before = today - timezone.timedelta(30 * 4)
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(four_month_before.year, four_month_before.month, 1)))
return objects.filter(date__gte=start_day)
# timespan
def getLastWeek():
date = datetime.date.today()
end_day = date - datetime.timedelta(date.weekday())
start_day = end_day - datetime.timedelta(7)
return dateToDatetime([day for day in datespan(start_day, end_day)])
def getThisWeek():
date = datetime.date.today()
start_day = date - datetime.timedelta(date.weekday())
end_day = start_day + datetime.timedelta(7)
return dateToDatetime([day for day in datespan(start_day, end_day)])
def getLastMonth():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month - 1 if today.month - 1 != 0 else 1, 1)))
end_day = start_day + datetime.timedelta(30)
return [day for day in datespan(start_day, end_day)]
def getThisMonth():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, 1)))
end_day = start_day + datetime.timedelta(30)
return [day for day in datespan(start_day, end_day)]
def getLastYear():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
return [day for day in datespan(start_day, end_day)]
def getThisYear():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
return [day for day in datespan(start_day, end_day)]
# exclude
def dayNotIn(objects):
return objects.filter(~Q(date=timezone.now()))
def weekNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=7))
def monthNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=30))
def yearNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=365))
# month only
def getQSbyYM(objects, y, m):
# m in [0, 12]
em = m + 1
ey = y
if em == 13:
em = 1
ey = y + 1
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(y, m, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(ey, em, 1)))
return objects.filter(date__lt=end_day, date__gte=start_day)
def createInToday(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, today.day)))
end_day = start_day + datetime.timedelta(1)
return objects.filter(date__lt=end_day, date__gte=start_day)
def dtstr(dt) -> str:
return dt.strftime('%Y-%m-%dT%H:%M:%S')
def strdt(st):
return pytz.timezone('Asia/Shanghai').localize((parse_datetime(st)))
modify date__ according to model date time field name, also change timezone based on where your site works.
django moans about start_day and end_day declaration may conflicts django.utils.timezone, I think it is not a big deal.
This depends on the level of risk you're comfortable with. By not taking into account the user's timezone, thisYearQuerySet could return objects from last year or the current year as you near the new year.
This is because the server could be running at GMT time, which means at 2022-01-01 00:00:00T00:00, it would start returning data with dates of the year 2022. However any Americans using the application would know the year to be 2021 for 4+ hours yet and would expect to see 2021's data until their own midnight.
However, if you're trying to silence the warning and don't care about the above scenario, don't use the python datetime functions when getting today/now. Use:
from django.utils import timezone
now = timezone.now()
today = timezone.now().date()
python get the quarterly dates from a date range
example :
start date = 01/04/2020
end date = 01/04/2021
Here I need to get the Quaternary dates from this date range.
Try:
start_date = "01/04/2020"
end_date = "01/04/2021"
pd.date_range(start_date, end_date, freq='Q')
DatetimeIndex(['2020-03-31', '2020-06-30', '2020-09-30', '2020-12-31'], dtype='datetime64[ns]', freq='Q-DEC')
pd.date_range(start date, end date, freq='3m').to_period('Q')
With pure Python:
import datetime
start_date_str = "01/04/2020"
end_date_str = "01/04/2021"
start_date = datetime.datetime.strptime(start_date_str, "%d/%m/%Y").date()
end_date = datetime.datetime.strptime(end_date_str, "%d/%m/%Y").date()
print(f"Quarters within {start_date_str} and {end_date_str}:")
start_of_quarter = start_date
while True:
far_future = start_of_quarter + datetime.timedelta(days=93)
start_of_next_quarter = far_future.replace(day=1)
end_of_quarter = start_of_next_quarter - datetime.timedelta(days=1)
if end_of_quarter > end_date:
break
print(f"\t{start_of_quarter:%d/%m/%Y} - {end_of_quarter:%d/%m/%Y}")
start_of_quarter = start_of_next_quarter
Language Python
I am wondering if anyone can help me print out some dates.
i cam trying to create a loop in which i pass in a date say 01/1/2017 and the loop will then output the first and last day in every month between then and the present day.
Example
01/01/2017
31/01/2017
01/02/2017
28/02/2017
etc
Any help will be appreciated
Hope this will help,
Code:
from datetime import date
from dateutil.relativedelta import relativedelta
from calendar import monthrange
d1 = date(2018, 2, 26)
d2 = date.today()
def print_month_day_range(date):
first_day = date.replace(day = 1)
last_day = date.replace(day = monthrange(date.year, date.month)[1])
print (first_day.strftime("%d/%m/%Y"))
print (last_day.strftime("%d/%m/%Y"))
print_month_day_range(d1)
while (d1 < d2):
d1 = d1 + relativedelta(months=1)
print_month_day_range(d1)
Output:
01/02/2018
28/02/2018
01/03/2018
31/03/2018
...
01/07/2018
31/07/2018
you can use calendar module. Below is the code:
import datetime
from calendar import monthrange
strt_date = '01/1/2017'
iter_year = datetime.datetime.strptime(strt_date, '%m/%d/%Y').year
iter_month = datetime.datetime.strptime(strt_date, '%m/%d/%Y').month
cur_year = datetime.datetime.today().year
cur_month = datetime.datetime.today().month
while cur_year > iter_year or (cur_year == iter_year and iter_month <= cur_month):
number_of_days_in_month = monthrange(iter_year, iter_month)[1]
print '/'.join([str(iter_month) , '01', str(iter_year)])
print '/'.join([str(iter_month), str(number_of_days_in_month), str(iter_year)])
if iter_month == 12:
iter_year += 1
iter_month = 1
else:
iter_month += 1
this could work, as long as the first date you give is always the first of the month
from datetime import datetime
from datetime import timedelta
date_string = '01/01/2017'
date = datetime.strptime(date_string, '%d/%m/%Y').date()
today = datetime.now().date()
months = range(1,13)
years = range(date.year, today.year + 1)
for y in years:
for m in months:
new_date = date.replace(month=m, year=y)
last_day = new_date - timedelta(days=1)
if (date < new_date) & (new_date <= today):
print last_day.strftime('%d/%m/%Y')
print new_date.strftime('%d/%m/%Y')
elif (date <= new_date) & (new_date <= today):
print new_date.strftime('%d/%m/%Y')
This code would print the first and last days of all months in a year.
Maybe add some logic to iterate through the years
import datetime
def first_day_of_month(any_day):
first_month = any_day.replace(day=1)
return first_month
def last_day_of_month(any_day):
next_month = any_day.replace(day=28) + datetime.timedelta(days=4)
return next_month - datetime.timedelta(days=next_month.day)
for month in range(1, 13):
print first_day_of_month(datetime.date(2017, month, 1))
print last_day_of_month(datetime.date(2017, month, 1))