Add one month to a given date (rounded day after) with Python
You can use dateutil.relativedelta.relativedelta
and manually check the datetime.day
attribute, if the original day is greater than the new day, then add a day.
The function below accepts a datetime
object and relativedelta
object. Note that the code below only works for years and months, I don't believe it'll work if you use anything below that (days, hours, etc). You could easily modify this function to take years
and months
as arguments and then construct the relativedelta
inside the function itself.
from datetime import datetime
from dateutil.relativedelta import relativedelta
def add_time(d, rd):
day = relativedelta(days=+1)
out = d + rd
if d.day > out.day:
out = out + day
return out
# Check that it "rolls over"
print(add_time(datetime(year=2015, month=1, day=29), relativedelta(years=+4, months=+1))) # 2019-03-01 00:00:00
print(add_time(datetime(year=2015, month=3, day=31), relativedelta(years=+0, months=+2))) # 2015-05-01 00:00:00
# Check that it handles "normal" scenarios
print(add_time(datetime(year=2015, month=6, day=19), relativedelta(months=+1))) # 2015-07-19 00:00:00
print(add_time(datetime(year=2015, month=6, day=30), relativedelta(years=+2, months=+1))) # 2017-07-30 00:00:00
# Check across years
print(add_time(datetime(year=2015, month=12, day=25), relativedelta(months=+1))) # 2016-01-25 00:00:00
# Check leap years
print(add_time(datetime(year=2016, month=1, day=29), relativedelta(years=+4, months=+1))) # 2020-02-29 00:00:00
How to increment datetime by custom months in python without using library
Edit - based on your comment of dates being needed to be rounded down if there are fewer days in the next month, here is a solution:
import datetime
import calendar
def add_months(sourcedate, months):
month = sourcedate.month - 1 + months
year = sourcedate.year + month // 12
month = month % 12 + 1
day = min(sourcedate.day, calendar.monthrange(year,month)[1])
return datetime.date(year, month, day)
In use:
>>> somedate = datetime.date.today()
>>> somedate
datetime.date(2010, 11, 9)
>>> add_months(somedate,1)
datetime.date(2010, 12, 9)
>>> add_months(somedate,23)
datetime.date(2012, 10, 9)
>>> otherdate = datetime.date(2010,10,31)
>>> add_months(otherdate,1)
datetime.date(2010, 11, 30)
Also, if you're not worried about hours, minutes and seconds you could use date
rather than datetime
. If you are worried about hours, minutes and seconds you need to modify my code to use datetime
and copy hours, minutes and seconds from the source to the result.
Cumulatively add month to a Date column based off the first date of a group
- You can create a series
m
with a.groupby
on the columnID1
, return the cumulative count per group, and add 3 (since that is how many months you want to offset initially). With.cumcount()
, the offset will grow by 1 with each additional row of your group. - Then, we want to create the
New Date
column but ONLY Addm
to the FIRST date of each group, so we usedf.groupby('ID1')['Date'].transform('first')
before addingm.values.astype("timedelta64[M]")
:
Input (Latest Edit of your question):
ID1 ID2 Date
1 20 5/15/2019 11:06:47 AM
1 21 5/15/2019 11:06:47 AM
1 22 5/15/2019 11:06:47 AM
1 23 5/15/2019 11:06:47 AM
1 24 5/15/2019 11:06:47 AM
1 25 5/15/2019 11:06:47 AM
1 26 6/15/2019 11:06:47 AM
1 27 6/15/2019 11:06:47 AM
1 28 6/15/2019 11:06:47 AM
1 29 6/15/2019 11:06:47 AM
1 30 6/15/2019 11:06:47 AM
1 31 6/15/2019 11:06:47 AM
# df['Date'] = pd.to_datetime(df['Date'])
m = df.groupby('ID1').cumcount() + 3
df['New Date'] = df.groupby('ID1')['Date'].transform('first') + m.values.astype("timedelta64[M]")
df
Out[1]:
ID1 ID2 Date New Date
0 1 20 2019-05-15 11:06:47 2019-08-14 18:34:05
1 1 21 2019-05-15 11:06:47 2019-09-14 05:03:11
2 1 22 2019-05-15 11:06:47 2019-10-14 15:32:17
3 1 23 2019-05-15 11:06:47 2019-11-14 02:01:23
4 1 24 2019-05-15 11:06:47 2019-12-14 12:30:29
5 1 25 2019-05-15 11:06:47 2020-01-13 22:59:35
6 1 26 2019-06-15 11:06:47 2020-02-13 09:28:41
7 1 27 2019-06-15 11:06:47 2020-03-14 19:57:47
8 1 28 2019-06-15 11:06:47 2020-04-14 06:26:53
9 1 29 2019-06-15 11:06:47 2020-05-14 16:55:59
10 1 30 2019-06-15 11:06:47 2020-06-14 03:25:05
11 1 31 2019-06-15 11:06:47 2020-07-14 13:54:11
How to add datetime and round it considering months?
Not sure what result do you want here?
What is a month in this case? February can be of various size dependent on year, for example. If you add "three month" to June, this is one case, if "to July" - another, since different months has different day numbers.
Looks like you can have "100 minutes 100 hours 100 days 100 month"? Then just add months to months, days to days?
Anyhow, adding large time ranges like month and years, I'd probably went via seconds, relative to the year 1 AD (in Python there is no 0 year). Where questions like "what does it mean to add one month and one year" will still be relevant. So one might want to "add another year in seconds", etc.
from datetime import datetime, timedelta
time1 = datetime.strptime('28 01 2021', '%d %m %Y')
time_min = datetime.min
time2 = datetime.strptime('15 01 2021', '%d %m %Y')
time = (time1 - time_min).total_seconds() + (time2 - time_min).total_seconds()
#year_of_seconds = (datetime(2,1,1) - time_min).total_seconds()
(time_min + timedelta(seconds = time)).strftime('%d %m %Y')
11 02 4041
Adding month, day, year to a date
Try this.
class Date(object):
def __init__(self, day=1, month=1, year=2015):
self.day = day
self.mon = month
self.year = year
def __str__(self):
return "Date is: %s %s %s"%(self.day,self.mon,self.year)
def IsLeapYear(self):
"""
function returns 1 if self.year is leap,0 if it's not
"""
if(not (self.year%400) or (not(self.year%4) and self.year%100)):
return 1
else:
return 0
#values by each month whether it's leap year or not
monthlength = (
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
)
#the function you probably were looking for
def AddDay(self, n):
days=n
leap_year=self.IsLeapYear()
while(self.day+days>=Date.monthlength[leap_year][self.mon-1]):
days=days-(Date.monthlength[leap_year][self.mon-1]-self.day)
self.day=0
self.mon+=1
if (self.mon>12):
self.mon=1
self.year+=1
leap_year=self.IsLeapYear()
else:
self.day+=days
find start and end date of previous 12 month from current date in python
You can use current_date.replace(day=1)
to get first day in current month.
And if you substract datetime.timedelta(days=1)
then you get last day in previous month.
And you can use again replace(day=1)
to get first day in previous month.
If you repeate it in loop then you can get first day and last day for all 12 months.
import datetime
current = datetime.datetime(2022, 5, 5)
start = current.replace(day=1)
for x in range(1, 13):
end = start - datetime.timedelta(days=1)
start = end.replace(day=1)
print(f'{x:2} |', start.date(), '|', end.date())
Result:
1 | 2022-04-01 | 2022-04-30
2 | 2022-03-01 | 2022-03-31
3 | 2022-02-01 | 2022-02-28
4 | 2022-01-01 | 2022-01-31
5 | 2021-12-01 | 2021-12-31
6 | 2021-11-01 | 2021-11-30
7 | 2021-10-01 | 2021-10-31
8 | 2021-09-01 | 2021-09-30
9 | 2021-08-01 | 2021-08-31
10 | 2021-07-01 | 2021-07-31
11 | 2021-06-01 | 2021-06-30
12 | 2021-05-01 | 2021-05-31
EDIT:
And if you use pandas then you can use pd.date_range()
but it can't for previous dates so you would have to first get '2021.04.05'
(for MS
) and '2021.05.05'
(for M
)
import pandas as pd
#all_starts = pd.date_range('2021.04.05', '2022.04.05', freq='MS')
all_starts = pd.date_range('2021.04.05', periods=12, freq='MS')
print(all_starts)
#all_ends = pd.date_range('2021.05.05', '2022.05.05', freq='M')
all_ends = pd.date_range('2021.05.05', periods=12, freq='M')
print(all_ends)
for start, end in zip(all_starts, all_ends):
print(start.to_pydatetime().date(), '|', end.to_pydatetime().date())
DatetimeIndex(['2021-05-01', '2021-06-01', '2021-07-01', '2021-08-01',
'2021-09-01', '2021-10-01', '2021-11-01', '2021-12-01',
'2022-01-01', '2022-02-01', '2022-03-01', '2022-04-01'],
dtype='datetime64[ns]', freq='MS')
DatetimeIndex(['2021-05-31', '2021-06-30', '2021-07-31', '2021-08-31',
'2021-09-30', '2021-10-31', '2021-11-30', '2021-12-31',
'2022-01-31', '2022-02-28', '2022-03-31', '2022-04-30'],
dtype='datetime64[ns]', freq='M')
2021-05-01 | 2021-05-31
2021-06-01 | 2021-06-30
2021-07-01 | 2021-07-31
2021-08-01 | 2021-08-31
2021-09-01 | 2021-09-30
2021-10-01 | 2021-10-31
2021-11-01 | 2021-11-30
2021-12-01 | 2021-12-31
2022-01-01 | 2022-01-31
2022-02-01 | 2022-02-28
2022-03-01 | 2022-03-31
2022-04-01 | 2022-04-30
EDIT:
I found out that standard module calendar can gives number of days and weeks in month.
weeks, days = calendar.monthrange(year, month)
Working example:
import calendar
year = 2022
month = 5
for number in range(1, 13):
if month > 1:
month -= 1
else:
month = 12
year -= 1
weeks, days = calendar.monthrange(year, month)
print(f'{number:2} | {year}.{month:02}.01 | {year}.{month:02}.{days}')
Result:
1 | 2022.04.01 | 2022.04.30
2 | 2022.03.01 | 2022.03.31
3 | 2022.02.01 | 2022.02.28
4 | 2022.01.01 | 2022.01.31
5 | 2021.12.01 | 2021.12.31
6 | 2021.11.01 | 2021.11.30
7 | 2021.10.01 | 2021.10.31
8 | 2021.09.01 | 2021.09.30
9 | 2021.08.01 | 2021.08.31
10 | 2021.07.01 | 2021.07.31
11 | 2021.06.01 | 2021.06.30
12 | 2021.05.01 | 2021.05.31
How to round a datetime up to a specific time?
If the result is a timezone-aware datetime object in a timezone with a non-fixed UTC offset then you can't just call .replace()
or .combine()
-- it may create a datetime with a wrong UTC offset. The issue is similar to How do I get the UTC time of "midnight" for a given timezone? (00:00
is used instead of 08:00
).
Assuming 8AM always exists and unambiguous in PST:
from datetime import datetime, time as datetime_time, timedelta
import pytz # $ pip install pytz
def next_8am_in_pst(aware_dt, tz=pytz.timezone('America/Los_Angeles')):
pst_aware_dt = tz.normalize(aware_dt.astimezone(tz)) # convert to PST
naive_dt = round_up_to_8am(pst_aware_dt.replace(tzinfo=None))
return tz.localize(naive_dt, is_dst=None)
def round_up_to_8am(dt):
rounded = datetime.combine(dt, datetime_time(8))
return rounded + timedelta(rounded < dt)
Example:
>>> str(next_8am_in_pst(datetime.now(pytz.utc)))
'2016-02-25 08:00:00-08:00'
Related Topics
How to Split Vector into Columns - Using Pyspark
Comparing Two Dataframes and Getting the Differences
Visual Studio Code Windows , Python Pandas . No Module Named Pandas
Is There Any Numpy Group by Function
How to Crop the Black Background of the Image Using Opencv in Python
Why Calling .Sort() Function on Pandas Series Sorts Its Values In-Place and Returns Nothing
Background Color for Tk in Python
Creating a New Dataframe Column by Comparing Strings of Two Unequal Dataframes
Get Max Value Comparing Multiple Columns and Return Specific Values
How to Read a Column Without Header from CSV and Save the Output in a Txt File Using Python
How to Convert a Datetime Object to Milliseconds Since Epoch (Unix Time) in Python
Find Matching Rows in 2 Dimensional Numpy Array
Replace Empty Strings With None/Null Values in Dataframe
Formatting Datetimefield in Django
How to Extract the Entire Row and Columns When Condition Met in Numpy Array