Making a time adding function in python - 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!

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 solve the weekday function problem Python

I am very new to Python and we were told to write the weekday function without any modules like e.g. daytime etc.
But it doesn't work and i am not sure where is a problem
def weekDay (day,month,year):
global y0
global m0
global x
y0 = 0
m0 = 0
day,month,year = int(input("Enter a day: "))
month = int(input("Enter a month: "))
year = int(input("Enter a year:"))
a = (day + x + (31 * m0) // 12) % 7
for m0 in a:
m0 = month + 12 * ((14 - month) // 12) - 2
for x in a:
x = y0 + y0 // 4 - y0 // 100 + y0 // 400
for y0 in x:
y0 = year - ((14 - month) // 12)
if a == 0:
print("Sunday")
elif a == 1:
print("Monday")
elif a == 2:
print("Tuesday")
elif a == 3:
print("Wednesday")
elif a == 4:
print("Thursday")
elif a == 5:
print("Friday")
else:
print("Error")
return weekDay(a)
'''
here is the formula we were given:
[![formula][1]][1]
[1]: https://i.stack.imgur.com/iBv30.png
This should help:
>>> import datetime
>>> now = datetime.datetime.now()
>>> now.strftime('%A')
'Friday'
>>>
Global variables not defined anywhere and I am not able to understand the logic you are trying to write. So written a function based on a aptitude trick.
def weekday(day,month,year):
"""
This function is written based upon aptitude trick
to obtain day from given a date.
Input date example : 15-5-2020
Link for logic : https://www.youtube.com/watch?v=rJ0_GWDTdD4
"""
# for different months we are assigning specific number to that month
months = {1:1, 2:4, 3:4, 4:0, 5:2, 6:5, 7:0, 8:3, 9:6, 10:1, 11:4, 12:6}
# assigning days to a number
day_name = {1:'Sunday', 2:'Monday', 3:'Tuesday', 4:'Wednesday', 5:'Thursday',
6:'Friday', 0:'Saturday'}
# to get the year in between 1600 and 2000. since we are assiging values
# for the years also
while year not in range(1600,2000):
if year>2000:
year-=400
if year<1600:
year+=400
# assigning values to years
if year in range(1600,1700):
yr = 6
if year in range(1700,1800):
yr = 4
if year in range(1800,1900):
yr = 2
if year in range(1900,2000):
yr = 0
# assigning last two numbers of year to last
first = year//100
last = year - (first * 100)
# obtaining remainder
res = (day + months[month] + yr + last + (last//4))%7
#returning the day_name
return day_name[res]
day,month,year = list(map(int,input("Enter date in format dd-mm-yyyy : ").split('-')))
print(weekday(day,month,year))
Hope, you are satisfied with logic.

How can I optimize a code that is using xarray for better performance?

I'm trying to extract climate data from various .nc files I have but the process is taking extremely long, I suspect it has something to do with the fact that I'm trying to extract the data for every day of June, July, August for the next 79 years. But I'm a novice programmer and I realize there might've been a few oversights by me (efficiency wise) that might've resulted in a slightly better performance.
This is the snippet
def calculateTemp(coords, year, model):
"""
takes in all coordinates of a line between two grid stations and the year
converts the year into date
takes average of temperature of each day of the month of June for each
coordinate and then takes average of all coordinates to find average temp
for that line for the month of June
"""
print(year)
# coords represents a list of different sets of coordinates between two grids
temp3 = 0 # sum of all temps of all coordinates
for i in range(0, len(coords)):
temp2 = 0
counter = 0
# this loop represents that the 15 years data is being extracted for
# each coordinate set and average of those 15 years is being taken
for p in range(0, 15):
temp1 = 0 # sum of all temps for one coordinate in all days of June, tuly, august
if year+ p < 100:
# this loop represents the months of jun, jul, aug
for j in range(6, 9):
# 30 days of each month
for k in range(1, 31):
if k < 10:
# this if-else makes a string of date
date = '20'+str(year+p)+'-0'+str(j)+'-0'+str(k)
else:
date = '20'+str(year+p)+'-0'+str(j)+'-'+str(k)
# there are 3 variants of the climate model
# for years upto 2040, between 2041-2070
# and between 2071 and 2099
# hence this if else block
if year+p < 41:
temp1 += model[0]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
elif year+p >= 41 and year+p <71:
temp1 += model[1]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
else:
temp1 += model[2]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
counter += 1
avg = temp1/(len(range(0,30))*len(range(6,9)))
temp2 += avg
temp3 += temp2/counter
Tamb = temp3/len(coords)
return Tamb
Is there anyway I can increase the performance of this code and optimize it?
I just replaced the innermost loops k in range(1,31)and j in range(6,9)into a dict comprehension to generate all the dates and corresponding value from your model. Then simply averaged these values for every value of p and then for every coord in coords.
Give this a shot. Dicts should make the processing faster. Also check if the averages are exactly how you are calculating them in your function.
def build_date(year,p,j,k):
return '20'+str(year+p)+'-0'+str(j)+'-0'+str(k) if k<10 else '20'+str(year+p)+'-0'+str(j)+'-'+str(k)
def calculateTemp(coords, year, model):
func2 = lambda x,date:model[x]['tasmax'].sel(lon=coords[i][1],
lat=coords[i][0],
time=date,
method='nearest').data[0]
print(year)
out = {}
for i in range(len(coords)):
inner = {}
for p in range(0,15):
if year + p < 100:
dates = {build_date(year,p,j,k):func2(0,build_date(year,p,j,k)) if year+p<41 \
else func2(1,build_date(year,p,j,k)) if (year+p >= 41 and year+p <71) \
else func2(2,build_date(year,p,j,k))
for j in range(6,9) \
for k in range(1,31) }
inner[p] = sum([v for k,v in dates.items()])/len(dates)
out[i] = inner
coord_averages = {k : sum(v.values())/len(v) for k,v in out.items() }
Tamb = sum([v for k,v in coord_averages.items()])/len(coord_averages)
return Tamb

While loops in Procedures

I am trying to output 1 to 30 days but it isn't working and it says Your code didn't display any output
here is my code:
def nextDay(year, month, day):
day = 0
while (day < 30):
day = day + 1
print day
this what they are having me do. But i am stuck on the day portion. Sorry i noticed I put month instead of day so i fixed it, but this is what I am trying to get to at the end.
Define a simple nextDay procedure, that assumes every month has 30 days.
For example:
nextDay(1999, 12, 30) => (2000, 1, 1)
nextDay(2013, 1, 30) => (2013, 2, 1)
nextDay(2012, 12, 30) => (2013, 1, 1) (even though December really has 31 days)
def nextDay(year, month, day):
"""
Returns the year, month, day of the next day.
Simple version: assume every month has 30 days.
"""
# YOUR CODE HERE
return
Well if you're trying to output 1 through 30 this will work...
for x in range(1, 31):
print 'Day: %d' % x
I literally don't get your function at all, as it makes no sense.
In addition, I don't really get why you would use a while loop for that as it is slower than both range and xrange.
Did you want this
def nextDay(year, month, day):
if day == 30:
if month == 12:
day, month = 1, 1
year+=1
else:
month+=1
else:
day+=1
return (year, month, day)
>>>nextDay(2012, 12, 30)
(2013, 1, 1)
I hope this is what you needed.
def nextDay(year, month, day):
day += 1
if day > 30:
day = 1
month += 1
if month > 12:
month = 1
year += 1
return (year, month, day)
Your code did not show anything as I don't think you have called the function.

Python, printing things a select number of times

I'm new to coding and am having an issue with my program. I have to get sales information from a file and print it in a certain format. This is the code:
#Looping program to read file per line
for line in lines:
# Formatting line to read later
line = line.strip().split(',')
year = line[0]
year = int(year)
month = line[1]
month = int(month)
day = line[2]
day = int(day)
linePoint = date(year, month, day)
cost = line[3]
cost = float(cost)
#Finding the lines within the start and end date
if (linePoint >= startDate) and (linePoint <= endDate):
printcost = (cost / 100)
printcost = int(printcost)
print "%s.%s.%s" % (startYear, startMonth, startDay)
print "0%s:" % printNum, "*" * printcost
newcost = newcost + cost
printNum += 1
When I use the %s.%s.%s it's printing the date above the sales, I want it to print that above the other print statement once per month, and be able to increase it once the month is up.
Also in the print "0%s:" % printNum, "*" * printcost statement I would like it to only print the zero for the first nine days.
Essentially my question is how in Python do I run something a certain number of times, but the number of times is dependent on the user and correlate with the date, and in order to do that the computer needs to be able to recognize the date. Sorry for the vagueness.
If you want the output to be '01', '02', ..., '10', '11', ... then the format you want to use is:
print "%02d" % printNum
As for printing the header out at the start of each new month (that's how I'm reading the first part of your question, you could do something like:
old_month = 0
for line in lines:
# do stuff
month = whatever...
if month != old_month:
# print header here
old_month = month
#rest of loop
I'm almost sure this is what you want. Note the "%02d" format specifier, which gives you the leading zero, and the check to see if the month has changed via if month != current_month.
current_month, print_num, new_cost = None, 0, 0
for line in lines:
fields = line.strip().split(',')
year = int(fields[0])
month = int(fields[1])
day = int(fields[2])
cost = float(fields[3])
line_date = date(year, month, day)
#Finding the lines within the start and end date
if startDate <= line_date <= endDate:
if month != current_month:
print "%s.%s.%s" % (year, month, day)
current_month = month
print_cost = int(cost / 100)
print "%02d: %s" % (print_num, "*" * print_cost)
new_cost += cost
print_num += 1

Categories

Resources