I want to find a way that could give me next month/quarter/year/bi-annual date given a Pandas timestamp.
If the timestamp is already an end of month/quarter/year/bi-annual date than I can get next quarter date as follows:
pd.Timestamp('1999-12-31') + pd.tseries.offsets.DateOffset(months=3)
What if the time stamp was pd.Timestamp('1999-12-30'), the above won't work.
Expected output
input = pd.Timestamp('1999-12-30')
next_quarter_end = '2000-03-31'
next_month_end = '2000-01-31'
next_year_end = '2000-12-31'
next_biannual_end = '2000-06-30'
This works. I used pandas.tseries.offsets.QuarterEnd, .MonthEnd, and .YearEnd, multiplied by specific factors that change based on the input, to achieve the four values you're looking for.
date = pd.Timestamp('1999-12-31')
month_factor = 1 if date.day == date.days_in_month else 2
year_factor = 1 if date.day == date.days_in_month and date.month == 12 else 2
next_month_end = date + pd.tseries.offsets.MonthEnd() * month_factor
next_quarter_end = date + (pd.tseries.offsets.QuarterEnd() * month_factor)
next_year_end = date + pd.tseries.offsets.YearEnd() * year_factor
next_biannual_end = date + pd.tseries.offsets.DateOffset(months=6)
Technically, the next quarter end after Timestamp('1999-12-30') is Timestamp('1999-12-31 00:00:00')
You can use pandas.tseries.offsets.QuarterEnd
>>> pd.Timestamp('1999-12-30') + pd.tseries.offsets.QuarterEnd()
Timestamp('1999-12-31 00:00:00')
>>> pd.Timestamp('1999-12-30') + pd.tseries.offsets.QuarterEnd()*2
Timestamp('2000-03-31 00:00:00')
Similarly, use pandas.tseries.offsets.MonthEnd() and pandas.tseries.offsets.YearEnd()
For biannual, I guess you can take 2*QuarterEnd().
Related
I would like to create a variable (suffix) that prints current year and quarter in this format: '_21_q2' and (previous_suffix) which is simply suffix - 2 quarters in this case: '_21_q2'
This is what I have tried so far:
currrent_date = datetime.datetime.now()
current_year = str(x.year)[2:]
current_quarter = str(((x.month-1)//3)+1)
suffix = ('_' + current_year + '_q' + currentquarter)
previous_suffix = ?
Desired output
suffix = '_22_q1'
previous_suffix = '_21_q2'
You should consider using strftime instead of calling str on a datetime object.
That said, here is one way leveraging pd.Period (since you have a pandas tag anyway):
import pandas as pd
from datetime import datetime
def format_quarter(date):
year = date.strftime('%y')
quarter = pd.Period(date, freq='q').strftime('%q')
return f'_{year}_q{quarter}_'
# You're better off choosing a date first and formatting it afterwards
d1 = datetime.now()
d2 = d1 - pd.tseries.offsets.QuarterEnd(3)
suffix = format_quarter(d1)
previous_suffix = format_quarter(d2)
Output:
In [18]: suffix
Out[18]: '_22_q1_'
In [19]: previous_suffix
Out[19]: '_21_q2_'
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))
I calculated a column using the following code:
df_EVENT5_5['age'] = dt.datetime.now().date() - df_EVENT5_5['dt_old']
df_EVENT5_5['age_no_days'] = df_EVENT5_5['age'].dt.total_seconds()/ (24 * 60 * 60)
The output column contains the timestamp for some reason.
How do I remove the time stamp?
I tried below but didn't work:
remove_timestamp_col = ['COL_1', 'COL_2']
for i in remove_timestamp_col:
df_EVENT5_13[i] = df_EVENT5_13[i].age.days()
I think there might be some dates with time stamps in the data, try subtracting the date only:
df_EVENT5_5['age'] = dt.date.today() - df_EVENT5_5['dt_old'].apply(dt.datetime.date)
#This gives you the days difference as a number
df_EVENT5_5['age_no_days'] = df_EVENT5_5['age'].dt.days
#If you want it to have 'Days' in the end, you can use concatenation:
df_EVENT5_5['age_with_days'] = df_EVENT5_5['age_no_days'].astype('str') + ' Days'
I need to write a python code that generates a random date between 1/1/2014 and 12/31/2014, this will be stored as the beginning date. I then need to have an end date that ends 3 days after the beginning date. I've tried multiple ways of doing this but cant figure out how to get the end date. Please help!
def strTimeProp(start, end, format, prop):
stime = time.mktime(time.strptime(start, format))
etime = time.mktime(time.strptime(end, format))
ptime = stime + prop * (etime - stime)
return time.strftime(format, time.localtime(ptime))
def Order_Date(start, end, prop):
return strTimeProp(start, end, '%m/%d/%Y', prop)
date_1 = Order_Date("1/1/2014", "12/31/2014", random.random())
def Due_Date(end_date):
end_date = date_1 + datetime.timedelta(days=3)
return end_date
print (date_1)
print(Due_Date)
I've tried multiple ways of doing this but cant figure out how to get
the end date.
With datetime.timedelta(days=3). You can add timedeltas to dates:
import datetime as dt
import random
date_format = '%m/%d/%Y'
start_date = dt.datetime.strptime('1/1/2014', date_format)
end_date = dt.datetime.strptime('12/31/2014', date_format)
time_delta = end_date - start_date
rand_days = random.randint(0, time_delta.days)
rand_time_delta = dt.timedelta(days=rand_days)
random_date = start_date + rand_time_delta
print(random_date.strftime(date_format))
random_end_date = random_date + dt.timedelta(days=3)
print(random_end_date.strftime(date_format))
--output:--
09/26/2014
09/29/2014
And if the random_date is 12/31/2014, then the end date will be 01/03/2015, which you can see by setting rand_days = 364.
Using timedelta it's simple to add three days on to your start date. If you don't want the date going past 12/31/2014 then you'll want to subtract three days off your range. You can also reduce your code quite a bit which should make the entire thing easier to understand:
from datetime import datetime, timedelta
import random
def randDate(y,m,d):
s = datetime(y, m, d)
e = s + timedelta(days=3)
return ("{:%m/%d/%Y}\n{:%m/%d/%Y}".format(s,e))
y = random.randint(2014, 2014) # range for year
m = random.randint(1, 12) # range for month
d = random.randint(1, 28) # range for day
print(randDate(y,m,d))
↳ https://docs.python.org/2/library/datetime.html
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'))