How can I add only months together in python? - python

I understand using relativedelta for exact month calculation taking into account the number of days in each month.
Are there any streamlined libraries for adding just month ints together?
ie. December is 12. Adding 2 months is 14 which is 2 == February?
I am hoping to solve all edge cases surrounding the problem with a tested library.
I have thought of doing a modulo calculation along the following:
curr_month = 12 - 1 (-1 for 0 indexing) = 11
if we do divmod(curr_month, 11) , we get (0,0) but the result in reality should be 11. If I just handled that with an if result[0] == 0: curr_month = 11, then whenever result[1] we will get the wrong answer

This formula should work for you
>>> current_month = 12
>>> delta = 2
>>> (((current_month - 1) + delta) % 12) + 1
2

Related

Select dates in index

i have start date and end date and dataframe with daily observations. The problem is that i can't find a way, which will enable me select dates with periodicity of 3 months
for example:
2003-01-03 + 3 months = 2003-04-03 and so on
output should consist of 20 rows because 5 years with 3 months periodicity, including start and end dates
EDIT: Old solution didn't work for all cases. Therefore a new one:
start, end = returns.index[0], returns.index[-1]
length = (end.year - start.year) * 12 + (end.month - start.month)
if length % 3 == 0 and end.day >= start.day:
length += 3
new_index = []
for m in range(3, length, 3):
ydelta, month = divmod(start.month + m, 12)
day = pd.Timestamp(year=start.year + ydelta, month=month, day=1)
day += pd.Timedelta(f'{min(start.day, day.days_in_month) - 1}d')
new_index.append(day)
new_index = pd.DatetimeIndex(new_index)
returns = returns.loc[new_index]
Another version which has some slight inaccuracies around the month ends but is more compact:
add_3_months = pd.tseries.offsets.DateOffset(months=3)
new_index = pd.date_range(returns.index[0] + add_3_months,
returns.index[-1],
freq=add_3_months)
returns = returns.loc[new_index]

How to change the index,without giving wrong output?

So im trying to change the index and output the values as numbers.
this is my code:
import datetime
year = int(input('Enter the year (4 digits):\n'))
month = int(input('Enter the month (1-12)')
DayL = ['Mon','Tues','Wednes','Thurs','Fri','Satur','Sun']
date = DayL[datetime.date(year,month,1).weekday()] + 'day'
print(date)
Sample Output:
Enter the year (4 digits):
> 2020
Enter the month (1 - 12):
> 1
Wednesday
Im trying to get the output as a index, and it should start at Sunday (Sunday = 0), but still give the correct answer. How do i go about this ?
The output i want:
Enter the year (4 digits):
> 2020
Enter the month (1 - 12):
> 1
3
There’s no reason to use DayL.
The date.weekday function already gives you the numeric weekday using Monday=0.
To map that to a Sunday=0 system, just add 1 mod 7:
weekday = (datetime.date(year,month,1).weekday() + 1) % 7
Try to use this:
>>> (datetime.datetime( 2020, 1, 1).weekday() + 1) % 7
3
>>>

Nonetype error concatenating integers as strings Python

Hello stackoverflowbros
I came up with a fun problem to find all the years (in the recent future, before I day basically) for which all of the following are true:
1) the day is prime (eg the 5th or the 17th of the month)
2) the month is prime (eg May is the 5th month 5 is prime)
3) the year is prime (eg the year 2027 is prime)
4) the numbers concatenated in DDMMYYYY format is prime (eg 3022027 is prime)
My code works which is nice. I get the following answers:
3-02-2027
13-02-2027
31-02-2027 ## February has 31 days now ok
31-05-2027
29-07-2027
But I also get told that the line if isPrime(year) and isPrime(month) and isPrime(day) and isPrime(int(str(day) + datefix(month) + str(year))):
Is TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
I have two questions: 1) what have I done wrong? 2) why do i only get answers in 2027 (kind of related, why do i get any answers at all if there's an error)
def isPrime(n) :
# Corner cases
if (n <= 1) :
return False
if (n <= 3) :
return True
# This is checked so that we can skip
# middle five numbers in below loop
if (n % 2 == 0 or n % 3 == 0) :
return False
i = 5
while(i * i <= n) :
if (n % i == 0 or n % (i + 2) == 0) :
return False
i = i + 6
return True
def datefix(y):
if y <= 9:
y = str(str(0) + str(y))
return y
print(type(datefix(5)))
years = range(2019, 2054) ## 2053 is a good year to stop - and it's prime
days = range(2, 32)
months = range(2,13)
for year in years:
for month in months:
for day in days:
if isPrime(year) and isPrime(month) and isPrime(day) and isPrime(int(str(day) + datefix(month) + str(year))):
print(str(day) + '-' + datefix(month) + '-' + str(year))
Well because datefix only returns y if y <= 9, then if it's not,
It returns None, the default return type of a function in Python.
So in your example Month is bigger than 9.
The function datefix needs to handle that case.
You can actually change your function datefix to a single line datefix = '{:02d}'.format to get left zero padded months. No need to account for cases greater/smaller 10.
Currently it returns None for arguments > 9, as mentioned in another answer.

Making a time adding function in python

I'm trying to build a function that recieves a date and adds days, updating everything in case it changes, so far i've come up with this:
def addnewDate(date, numberOfDays):
date = date.split(":")
day = int(date[0])
month = int(date[1])
year = int(date[2])
new_days = 0
l = 0
l1 = 28
l2 = 30
l3 = 31
#l's are the accordingly days of the month
while numberOfDays > l:
numberOfDays = numberOfDays - l
if month != 12:
month += 1
else:
month = 1
year += 1
if month in [1, 3, 5, 7, 8, 10, 12]:
l = l3
elif month in [4, 6, 9, 11]:
l = l2
else:
l = l1
return str(day) + ':' + str(month) + ':' + str(year) #i'll deal
#with fact that it doesn't put the 0's in the < 10 digits later
Desired output:
addnewDate('29:12:2016', 5):
'03:01:2017'
I think the problem is with either the variables, or the position i'm using them in, kinda lost though..
Thanks in advance!
p.s I can't use python build in functions :)
Since you cannot use standard library, here's my attempt. I hope I did not forget anything.
define a table for month lengths
tweak it if leap year detected (every 4 year, but special cases)
work on zero-indexed days & months, much easier
add the number of days. If lesser that current month number of days, end, else, substract current month number of days and retry (while loop)
when last month reached, increase year
add 1 to day and month in the end
code:
def addnewDate(date, numberOfDays):
month_days = [31,28,31,30,31,30,31,31,30,31,30,31]
date = date.split(":")
day = int(date[0])-1
month = int(date[1])-1
year = int(date[2])
if year%4==0 and year%400!=0:
month_days[1]+=1
new_days = 0
#l's are the accordingly days of the month
day += numberOfDays
nb_days_month = month_days[month]
done = False # since you don't want to use break, let's create a flag
while not done:
nb_days_month = month_days[month]
if day < nb_days_month:
done = True
else:
day -= nb_days_month
month += 1
if month==12:
year += 1
month = 0
return "{:02}:{:02}:{:04}".format(day+1,month+1,year)
test (may be not exhaustive):
for i in ("28:02:2000","28:02:2004","28:02:2005","31:12:2012","03:02:2015"):
print(addnewDate(i,2))
print(addnewDate(i,31))
result:
02:03:2000
31:03:2000
01:03:2004
30:03:2004
02:03:2005
31:03:2005
02:01:2013
31:01:2013
05:02:2015
06:03:2015
of course, this is just for fun. Else use time or datetime modules!

Python 2 - How would you round up/down to the nearest 6 minutes?

There are numerous examples of people rounding to the nearest ten minutes but I can't figure out the logic behind rounding to the nearest six. I thought it would be a matter of switching a few numbers around but I can't get it to work.
The code I'm working with is located at my Github. The block I've got that isn't even close to working (won't give any output) is:
def companyTimer():
if minutes % 6 > .5:
companyMinutes = minutes + 1
elif minutes % 6 < 5:
companyMinutes = minutes - 1
else:
companyMinutes = minutes
print companyMinutes
Looking at it now, I see that my logic is incorrect - even if it were working, the add and subtract 1 minute portion of the code doesn't make sense.
Anyway, I have no idea how to remedy this - could someone point me in the right direction, please?
PS - this is something I'm making for personal use at work.. not asking for help with my job but this will help me keep track of my hours at work. Don't want there to be any issues with that.
Thanks!
Here's a general function to round to nearest x:
def round_to_nearest(num, base):
n = num + (base//2)
return n - (n % base)
[round_to_nearest(i, 6) for i in range(20)]
# [0, 0, 0, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 18, 18, 18, 18, 18]
Explanation:
n % base is the remainder left over when dividing n by base. Also known as the modulo operator.
Simply subtracting num%6 from num would give you 0 for 0-5, 6 for 6-11, and so on.
Since we want to "round" instead of "floor", we can bias this result by adding half of the base (base//2) beforehand.
If you want to round to the nearest 7 minutes (e.g. round7(3.6) => 7, round7(17.4) => 14), you can make use of Python's built in round function like so:
def round7(value):
return round(value / 7.0) * 7.0
>>> round7(17.4999)
14.0
>>> round7(17.5001)
21.0
or, a more general function:
def round_to_nearest(increment, value):
return round(value / float(increment)) * increment
>>> round_to_nearest(7, 17.4999)
14.0
>>> round_to_nearest(6, 21.0001)
24.0
Is this what you are after?
def roundto6(minute):
return int((minute+3) / 6) * 6
for i in xrange(13):
print roundto6(i),
# 0 0 0 6 6 6 6 6 6 12 12 12 12 12 12
simply use round, to round hours to 1 digit:
>>> import time
>>> import datetime
>>> now = datetime.datetime.now()
datetime.datetime(2015, 4, 9, 20, 4, 20, 578322)
>>> datetime.datetime.fromtimestamp(round(time.mktime(w.timetuple())/3600,1)*3600)
datetime.datetime(2015, 4, 9, 20, 6, 0)
A good way to consider would be:
def companyTimer(cm):
minutes = (time.time() - starting_time) / 60
print(minutes)
if minutes % 6 >= 0.5:
cm += 1
return cm
Where companyTimer takes one argument: companyMinutes.
>>> import time
>>> starting_time = time.time()
>>> companyMinutes = 0
>>> companyTimer(companyMinutes) # will return 0 until 3 minutes have passed
this is maybe not the smartest but a readable try :)
myNumber is your current minute
myList = range(0, 60, 6) # [0,6,12,18,24,30,36,42,48,54] # all accepted minutes
myNumber = 8
print(min(myList, key=lambda x:abs(x-myNumber)))
If you're rounding up, the general formula
x + (roundtothis - x % roundtothis)
is of use to you.
I'm assuming that this is for rounding to nearest multiple of seven based on the question title, otherwise change to 6:
So:
def roundUpToSeven(minute):
if ( minute % 7 == 0 and minute != 0 ):
return minute
else:
return minute + (7 - minute % 7)
See a working example here
I am assuming you want 2 to round to 0, 3 to stay at 3, and 4 to round to 6. Is this what you want?
def companyTimer(minutes, roundingNumber):
remainder = minutes % roundingNumber
if remainder > roundingNumber / 2:
companyMinutes = minutes - remainder + roundingNumber
elsif remainder < roundingNumber / 2:
companyMinutes = minutes - remainder
else:
companyMinutes = minutes
print companyMinutes

Categories

Resources