Please tell me how I can list next 24 months' start dates with python,
such as:
01May2014
01June2014
.
.
.
01Aug2015
and so on
I tried:
import datetime
this_month_start = datetime.datetime.now().replace(day=1)
for i in xrange(24):
print (this_month_start + i*datetime.timedelta(40)).replace(day=1)
But it skips some months.
Just increment the month value; I used datetime.date() types here as that's more than enough:
current = datetime.date.today().replace(day=1)
for i in xrange(24):
new_month = current.month % 12 + 1
new_year = current.year + current.month // 12
current = current.replace(month=new_month, year=new_year)
print current
The new month calculation picks the next month based on the last calculated month, and the year is incremented every time the previous month reached December.
By manipulating a current object, you simplify the calculations; you can do it with i as an offset as well, but the calculation gets a little more complicated.
It'll work with datetime.datetime() too.
To simplify arithmetics, try/except could be used:
from datetime import date
current = date.today().replace(day=1)
for _ in range(24):
try:
current = current.replace(month=current.month + 1)
except ValueError: # new year
current = current.replace(month=1, year=current.year + 1)
print(current.strftime('%d%b%Y'))
Related
I want to do a time serie with temperature data from 1850 to 2014. And I have an issue because when I plot the time series the start is 0 and it corresponds to day 1 of January 1850 and it stops day 60 230 with the 31 December of 2014.
I try to do a loop to create a new list with the time in month-years but it didn't succeed, and to create the plot with this new list and my initial temperature list.
This is the kind of loop that I tested :
days = list(range(1,365+1))
years = []
y = 1850
years.append(y)
while y<2015:
for i in days:
years.append(y+i)
y = y+1
del years [-1]
dsetyears = Dataset(years)
I also try with the tool called "datetime" but it didn't work also (maybe this tool is better because it will take into account the bissextile years...).
day_number = "0"
year = "1850"
res = datetime.strptime(year + "-" + day_number, "%Y-%j").strftime("%m-%d-%Y")
If anyone has a clue or a lead I can look into I'm interested.
Thanks by advance !
You can achieve that using datetime module. Let's declare starting and ending date.
import datetime
dates = []
starting_date = datetime.datetime(1850, 1, 1)
ending_date = datetime.datetime(2014, 1, 1)
Then we can create a while loop and check if the ending date is greater or equal to starting date and add 1-day using timedelta function for every iteration. before iteration, we will append the formatted date as a string to the dates list.
while starting_date <= ending_date:
dates.append(starting_date.strftime("%m-%d-%Y"))
starting_date += datetime.timedelta(days=1)
Basically, I'm trying to check whether a date, e.g. 2021-07-08, is in the next week, or the week after that, or neither.
#I can call the start and end dates of the current week
start = tday - timedelta(days=tday.weekday())
end = start + timedelta(days=6)
print("Today: " + str(tday))
print("Start: " + str(start))
print("End: " + str(end))
# and I can get the current week number.
curr_week = datetime.date.today().strftime("%V")
print(curr_week)
Is there a better way than getting a list of dates in curr_week + 1 and then checking whether date is in in that list?
Thanks so much
GENERAL ANSWER
It is best to stick to datetime and timedelta, since this handles all edge cases like year changes, years with 53 weeks etc.
So find the number of the next week, and compare the weeknumber of the week you want to check against that.
import datetime
# Date to check in date format:
check_date = datetime.datetime.strptime("2021-09-08", "%Y-%d-%m").date()
# Current week number:
curr_week = datetime.date.today().strftime("%V")
# number of next week
next_week = (datetime.date.today()+datetime.timedelta(weeks=1)).strftime("%V")
# number of the week after that
week_after_next_week = (datetime.date.today()+datetime.timedelta(weeks=2)).strftime("%V")
# Compare week numbers of next weeks to the week number of the date to check:
if next_week == check_date.strftime("%V"):
# Date is within next week, put code here
pass
elif week_after_next_week == check_date.strftime("%V"):
# Date is the week after next week, put code here
pass
OLD ANSWER
This messes up around year changes, and modulo doesn't fix it because there are years with 53 weeks.
You can compare the week numbers by converting them to integers. You don't need to create a list of all dates within the next week.
import datetime
# Date to check in date format:
check_date = datetime.datetime.strptime("2021-07-08", "%Y-%d-%m").date()
# Current week number, make it modulo so that the last week is week 0:
curr_week = int(datetime.date.today().strftime("%V"))
# Compare week numbers:
if curr_week == (int(check_date.strftime("%V"))-1):
# Date is within next week, put code here
pass
elif curr_week == (int(check_date.strftime("%V"))-2):
# Date is the week after next week, put code here
pass
You can cast the date you want to check in datetime, and then compare the week numbers.
# date you want to check
date = datetime.datetime.strptime("2021-07-08","%Y-%m-%d")
# current date
tday = datetime.date.today()
# compare the weeks
print(date.strftime("%V"))
print(tday.strftime("%V"))
27
32
[see Alfred's answer]
You can get the week number directly as an integer integer from the IsoCalendarDate representation of each date.
from datetime import datetime
date_format = '%Y-%m-%d'
t_now = datetime.strptime('2021-08-11', date_format)
target_date = datetime.strptime('2021-08-18', date_format)
Just using datetime comparing:
from datetime import datetime, timedelta
def in_next_week(date):
""" -1: before; 0: in; 1: after next week;"""
today = datetime.today()
this_monday = today.date() - timedelta(today.weekday())
start = this_monday + timedelta(weeks=1)
end = this_monday + timedelta(weeks=2)
return -1 if date < start else 0 if date < end else 1
Test cases:
for i in range(14):
dt = datetime.today().date() + timedelta(days=i)
print(dt, in_next_week(dt))
#first and last day of every month
s_january, e_january = ("1/1/2017"), ("1/31/2017")
s_february, e_february = ("2/1/2017"), ("2/28/2017")
s_march, e_march = ("3/1/2017"), ("3/31/2017")
s_april, e_april = ("4/1/2017"), ("4/30/2017")
s_may, e_may = ("5/1/2017"), ("5/31/2017")
s_june, e_june = ("6/1/2017"), ("6/30/2017")
s_july, e_july = ("7/1/2017"), ("7/31/2017")
s_august, e_august = ("8/1/2017"), ("8/31/2017")
s_September, e_September = ("9/1/2017"), ("9/30/2017")
s_october, e_october = ("10/1/2017"), ("10/31/2017")
s_november, e_november = ("11/1/2017"), ("11/30/2017")
s_december, e_december = ("12/1/2017"), ("12/31/2017")
def foo(s_date, e_date):
does stuff
foo(s_january, e_january)
foo(s_february, e_february)
foo(s_march, e_march)
foo(s_april, e_april)
foo(s_may, e_may)
foo(s_june, e_june)
foo(s_july, e_july)
foo(s_august, e_august)
foo(s_september, e_september)
foo(s_october, e_october)
foo(s_november, e_november)
foo(s_december, e_december)
I have a function that on a random date does stuff, but I have to call the function for every month, if I put the range for year I don't get the result that I want.
Is there any better way to avoid running it 12 times?
Set up your dates in a dictionary rather than 24 variables, and make life easier for yourself by computing the first and last day of each month. It would be useful also to represent your dates as datetimes not strings, since it's clear from your question header that you want to do computation on them.
import datetime
from dateutil import relativedelta
year = 2017
dates = {}
for month in range(1,13):
dates[(year,month)] = (
datetime.date(year,month,1),
datetime.date(year,month,1)
+ relativedelta.relativedelta(months=1)
- relativedelta.relativedelta(days=1))
The first element in each tuple is computed straightforwardly as the first day of the month. The second date is the same date, but with one month added (first day of the next month) and then one day subtracted, to get the last day of the month.
Then you can do:
for (year,month),(start,end) in dates.items():
print(year, month, foo (start,end))
You could use a dictionary to keep all start end end dates:
import calendar
import datetime as dt
def foo(s_date, e_date):
print ("Doing something between {} and {}".format(s_date.strftime('%d/%m/%Y'), e_date.strftime('%d/%m/%Y')))
def getMonths(year):
result = {}
for month in range(1, 13):
lastDayOfMonth = calendar.monthrange(year, month)[1]
result[month] = (dt.datetime(year, month, 1), dt.datetime(year, month, lastDayOfMonth))
return result
for month, start_end_dates in getMonths(2018).items():
foo(*start_end_dates)
Prints:
Doing something between 01/01/2018 and 31/01/2018
Doing something between 01/02/2018 and 28/02/2018
Doing something between 01/03/2018 and 31/03/2018
...
What do you mean by putting the range for year?
You could consider putting your dates to a dictionary or nested lists.
Problem:
I have a bunch of files that were downloaded from an org. Halfway through their data directory the org changed the naming convention (reasons unknown). I am looking to create a script that will take the files in a directory and rename the file the same way, but simply "go back one day".
Here is a sample of how one file is named: org2015365_res_version.asc
What I need is logic to only change the year day (2015365) in this case to 2015364. This logic needs to span a few years so 2015001 would be 2014365.
I guess I'm not sure this is possible since its not working with the current date so using a module like datetime does not seem applicable.
Partial logic I came up with. I know it is rudimentary at best, but wanted to take a stab at it.
# open all files
all_data = glob.glob('/somedir/org*.asc')
# empty array to be appended to
day = []
year = []
# loop through all files
for f in all_data:
# get first part of string, renders org2015365
f_split = f.split('_')[0]
# get only year day - renders 2015365
year_day = f_split.replace(f_split[:3], '')
# get only day - renders 365
days = year_day.replace(year_day[0:4], '')
# get only year - renders 2015
day.append(days)
years = year_day.replace(year_day[4:], '')
year.append(years)
# convert to int for easier processing
day = [int(i) for i in day]
year = [int(i) for i in year]
if day == 001 & year == 2016:
day = 365
year = 2015
elif day == 001 & year == 2015:
day = 365
year = 2014
else:
day = day - 1
Apart from the logic above I also came across the function below from this post, I am not sure what would be the best way to combine that with the partial logic above. Thoughts?
import glob
import os
def rename(dir, pattern, titlePattern):
for pathAndFilename in glob.iglob(os.path.join(dir, pattern)):
title, ext = os.path.splitext(os.path.basename(pathAndFilename))
os.rename(pathAndFilename,
os.path.join(dir, titlePattern % title + ext))
rename(r'c:\temp\xx', r'*.doc', r'new(%s)')
Help me, stackoverflow. You're my only hope.
You can use datetime module:
#First argument - string like 2015365, second argument - format
dt = datetime.datetime.strptime(year_day,'%Y%j')
#Time shift
dt = dt + datetime.timedelta(days=-1)
#Year with shift
nyear = dt.year
#Day in year with shift
nday = dt.timetuple().tm_yday
Based on feedback from the community I was able to get the logic needed to fix the files downloaded from the org! The logic was the biggest hurdle. It turns out that the datetime module can be used, I need to read up more on that.
I combined the logic with the batch renaming using the os module, I put the code below to help future users who may have a similar question!
# open all files
all_data = glob.glob('/some_dir/org*.asc')
# loop through
for f in all_data:
# get first part of string, renders org2015365
f_split = f.split('_')[1]
# get only year day - renders 2015365
year_day = f_split.replace(f_split[:10], '')
# first argument - string 2015365, second argument - format the string to datetime
dt = datetime.datetime.strptime(year_day, '%Y%j')
# create a threshold where version changes its naming convention
# only rename files greater than threshold
threshold = '2014336'
th = datetime.datetime.strptime(threshold, '%Y%j')
if dt > th:
# Time shift - go back one day
dt = dt + datetime.timedelta(days=-1)
# Year with shift
nyear = dt.year
# Day in year with shift
nday = dt.timetuple().tm_yday
# rename files correctly
f_output = 'org' + str(nyear) + str(nday).zfill(3) + '_res_version.asc'
os.rename(f, '/some_dir/' + f_output)
else:
pass
I'm trying to check if first date of the month and the last date of the month lies in a range of dates (the range is 7 days window starting from current date) . below is an example for what I'm trying to achieve:
import datetime, calendar
today = datetime.date.today()
date_list = [today + datetime.timedelta(days=x) for x in range(0, 7)]
lastDayOfMonth = today.replace(day=calendar.monthrange(today.year,today.month)[-1])
if 1 in [ date_list[i].day for i in range(0, len(date_list))]:
print "we have first day of month in range"
elif lastDayOfMonth in [ date_list[i].day for i in range(0, len(date_list))]:
print " we have last date of month in the range"
I'm wondering if there is a cleaner way for doing that? I also want to print the exact date if I find it in the list but I don't know how without expanding the for loop in the if statement and save print date_list[i] if it matches my condition. so instead of printing the message when I find the first day in the range I should print the actual date. same for last date.
Thanks in advance!
The only thing I can come up with, without having to make use of iteration is:
import datetime, calendar
today = datetime.date.today()
week_from_today = today + datetime.timedelta(days=6)
last_day_of_month = today.replace(day=calendar.monthrange(today.year,today.month)[-1])
if today.month != week_from_today.month:
print datetime.date(week_from_today.year, week_from_today.month, 1)
elif today <= last_day_of_month <= week_from_today:
print last_day_of_month
since today it's 2016-06-02 it's hard to test the code.
Try changing the variable today to another day. I used the dates 2016-05-25 and 2016-05-26 to test the code.
to set a custom date: today = datetime.date(yyyy, m, d)