I need to compile a program that can convert a Gregorian date to a Mayan one. I also need to use 01/01/1970 as a reference date.
The following auxiliary functions work accordingly and have no mistakes.
# turns dates into tuples
def dmj(date):
"""
>>> dmj('01/01/1970')
(1, 1, 1970)
>>> dmj('00012+00012+02012')
(12, 12, 2012)
"""
tup = ()
for i in date:
if i.isdigit() == False and i != ' ':
date = date.replace(i, ' ')
number_str = ''
for i in date:
number_str += i
if i == ' ':
number = int(number_str)
tup += (number,)
number_str = ''
tup += (int(number_str),)
return tup
# counts days that have passed since 01/01/1970
def daysPassed(date):
"""
>>> daysPassed('01/01/1970')
0
>>> daysPassed('20-7-1988')
6775
>>> daysPassed('00012+00012+02012')
15686
"""
from datetime import date
tup = dmj(date)
begin = date(1970, 1, 1)
end = date(tup[2], tup[1], tup[0])
passed = abs(end - begin)
return passed.days
My idea was to first calculate how many days have passed since the beginning of this pictun (20 baktuns long) in 01/01/1970 and then added the days passed since then according to the given date.
In the Mayan calendar a day is refered to as a kin. Their periods (within one pictun) are as follows:
20 kin = 1 uinal; 18 uinal = 1 tun; 20 tun = 1 katun; 20 katun = 1 baktun
In the long count notation the Mayan date for 01/01/1970 is '12.17.16.7.5'. Baktun are written first, then katuns, etc... Mayan dates start from 0. Basically the first kin of a uinal is number zero and the last one number 19, twenty in total.
I've first compiled the following:
def mayanDate(date, separation='')
"""
>>> mayanDate('01/01/1970')
'12/17/16/7/5'
>>> mayaDate('20-7-1988', separator='/')
'12/18/15/4/0'
>>> mayaDate('00012+00012+02012', separator='-')
'12-19-19-17-11'
>>> mayaDate('21 12 2012', separator='+')
'13+0+0+0+0'
>>> mayaDate('26.03.2407')
'14.0.0.0.0'
"""
days = daysPassed(date) + 13 * 144000 + 18 * 7200\
+ 17 * 400 + 8 * 20 + 6
baktun = str((days //((20 **3) * 18)) - 1)
days = days % ((20 **3) * 18)
katun = str((days //((20 **2) * 18)) - 1)
days = days % ((20 **2) * 18)
tun = str((days // (20 **2)) - 1)
days = days % (20 **2)
uinal = str((days // 20) - 1)
days = days % 20 - 1
kin = str(days)
mayanlist = [baktun, katun, tun, uinal, kin]
for i in date:
if i.isdigit() == False and separator == '':
separator = i
break
mayandate = separator.join(mayanlist)
return mayandate
For some strange reason only 01/01/1970 returns the correct Mayan long notation, despite counting from the beginning of an entire pictun (7,900 years in length!). For all other dates it seems to advance too fast through the calendar, despite my second auxiliary function returning the correct values (even for millennia into the future).
I wonder where's the mistake. For instance mayanDate('20-7-1988') returns '12-18-15-6-0' instead of '12-18-15-4-0' and mayanDate('21 12 2012') returns '13 0 1 12 0' instead of '13 0 0 0 0'.
The issue you're seeing with the negative 1 kin for date '15/01/1970' is due to the removal of one from every date ordinal during the calculation. Taking x%20 will always return a value between 0 and 19 inclusive. Taking one from the result necessarily shifts this range to -1 to 18 inclusive.
The number added to the result of daysPassed(date) seems to be a conversion of the long form of 1/1/1970, with one added to each digit. I'm assuming this has been done to counter the fact that the Mayan calendar starts counting at zero, but is unnecessary. The Mayan date 0.0.0.0.1.5 counts 25, not 151646. This doesn't appear to be the source of the error though, since removing this issue from my own code, I still get the same results as described for the 20-7-1988 and 21-12-2012.
I finally rooted out the error when I went back and switched out all the magic numbers in my code for named constants (it makes the code far easier to debug, read and maintain). You state there are 18 uinal in a tun, and 20 tun in a katun, but these numbers are reversed in the code.
Here's my code:
def mayanDate(date_str, seperation=','):
days_in_kin = 1
kin_in_uinal = 20
uinal_in_tun = 18
tun_in_katun = 20
katun_in_baktun = 20
days_in_uinal = days_in_kin * kin_in_uinal
days_in_tun = days_in_uinal * uinal_in_tun
days_in_katun = days_in_tun * tun_in_katun
days_in_baktun = days_in_katun * katun_in_baktun
days_1970 = 12 * days_in_baktun \
+ 17 * days_in_katun\
+ 16 * days_in_tun\
+ 7 * days_in_uinal\
+ 5 * days_in_kin
total_days = daysPassed(date_str) + days_1970
baktun = total_days // days_in_baktun
total_days -= baktun * days_in_baktun
katun = total_days // days_in_katun
total_days -= katun * days_in_katun
tun = total_days // days_in_tun
total_days -= tun * days_in_tun
uinal = total_days // days_in_uinal
total_days -= uinal * days_in_uinal
kin = total_days // days_in_kin
print seperation.join(map(str, (baktun, katun, tun, uinal, kin)))
(I subtracted the previous calculations from total days, rather than using a modulo operator, since I feel it's cleaner. I guess it's a matter of personal preference.)
I may have found something.
>>>mayanDate('15/01/1970')
'12/17/16/8/-1'
Obviously not possible. -1 has to be 19 here and 8 has to be 7. It seems to turn month too early. Still not out why 01/01/1970 remains correct here. No idea what's so special about that date.
Related
I need the following script to compute the working hours from 9 am to 6 pm, so that if I add 5 hours it will be added from 9 am the next day.
Example: if it is now 5 pm and I add 5 hours and the working day ends at 6 pm, the output would be: 13 hours.
17 + 1 = 18 and
9 + 4 = 13 hs
So far the script computes hours regardless of the labor restriction.
from datetime import datetime, timedelta
updated = ( datetime.now() +
timedelta( hours = 5 )).strftime('%H:%M:%S')
print( updated )
--22:12:00
Here you are:
workday_begin = time(9)
workday_end = time(18)
# compute workday length
workday_hours = datetime.combine(date.today(), workday_end) - datetime.combine(date.today(), workday_begin)
# this is timedelta from your example
duration_hours = timedelta(hours=17)
# ignore times longer than a workday
day_cnt = 0 # this could be used to know how many day we've skipped, not part of question tho
while duration_hours > workday_hours:
day_cnt += 1
duration_hours -= workday_hours
now = datetime.now()
# now = datetime(2021,12,10,11,25,16)
if workday_begin < now.time() < workday_end:
# now is in work-hours
if datetime.combine(date.today(), workday_end) - now < duration_hours:
# duration would exceed work-hours, jumping to next day
day_cnt += 1
duration_hours -= (datetime.combine(date.today(), workday_end) - now)
updated = datetime.combine(date.today(), workday_begin) + duration_hours
else:
# everything is fine, just add hours
updated = now + duration_hours
else:
# now is not in work-hours. Add remaining duration to workday begin
updated = datetime.combine(date.today(), workday_begin) + duration_hours
# keep just a time part
updated = updated.time().strftime('%H:%M:%S')
print( updated )
I hope I understood your question.
So i'm trying know in what time of day the man will end running. When in last line of code, trying to use an operator addition this error is popping out. What i'm doing wrong?
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
import datetime
# first run, 1 mile
pace_minutes1 = 8
pace_seconds1 = 15
distance = 1 #1 mile
b = ((pace_minutes1 * 60) + pace_seconds1) * distance
print(b)
# second run, 3 mile
pace_minutes2 = 7
pace_seconds2 = 12
distance = 3 # 3 miles
a = ((pace_minutes2 * 60) + pace_seconds2) * distance
print(a)
# third run, 1 mile run
pace_minutes3 = 8
pace_seconds3 = 15
distance = 1 # 1 mile
c = ((pace_minutes3 * 60) + pace_seconds3) * distance
print(c)
x = (a + b + c)
print(x, "seconds")
time = datetime.timedelta(seconds=x) # converse value "x" seconds to time (h,m,s)
print("All running time will gonna take",time,"seconds") # total time spent running
start_time = datetime.time(6,52,0) # time from where he started running
print("The running started in",start_time)
end_time = (start_time + time) # time when he ended running
print(end_time)
You can only add the timedelta to a datetime.datetime object, not a datetime.time object (probably in order to avoid overflows).
So simple fix, use start_time = datetime.datetime(2021, 04, 21, 6,52,0)
Please find below answer .check if it what you desired.May be you can check stack overflow answer
import datetime
# first run, 1 mile
pace_minutes1 = 8
pace_seconds1 = 15
distance = 1 #1 mile
b = ((pace_minutes1 * 60) + pace_seconds1) * distance
print(b)
# second run, 3 mile
pace_minutes2 = 7
pace_seconds2 = 12
distance = 3 # 3 miles
a = ((pace_minutes2 * 60) + pace_seconds2) * distance
print(a)
# third run, 1 mile run
pace_minutes3 = 8
pace_seconds3 = 15
distance = 1 # 1 mile
c = ((pace_minutes3 * 60) + pace_seconds3) * distance
print(c)
x = (a + b + c)
print(x, "seconds")
time = datetime.timedelta(seconds=x) # converse value "x" seconds to time (h,m,s)
print("All running time will gonna take",time,"seconds") # total time spent running
start_time = datetime.time(6,52,0) # time from where he started running
# print(type(start_time))
# print(type(time))
print("The running started in",start_time)
end_time = (dt.datetime.combine(dt.date(1,1,1),start_time) + time).time()
print(end_time)
This is part of a bigger problem we're facing but the problem at the moment is splitting time between two datetimes into two rates based on when those hours are in the day. It's quite arbitrary but we treat 7am-7pm as normal hours and the opposite 12 hours as premium.
So for any given pair of datetimes, we need to grade these down so that we know how many normal hours, or how many premium hours there were in that period. A couple of examples:
If we took the next 24 hours, I'd expect an exact split of 12 hours.
> start = datetime.datetime.now()
> end = start + datetime.timedelta(1)
> split_hours(start, end)
(datetime.timedelta(0, 43200), datetime.timedelta(0, 43200))
If we took the next 12 hours, at 20:26, I'd expect 1h26 normal and 10h34m premium rate:
> start = datetime.datetime(2017, 11, 6, 20, 26, 0)
> end = start + datetime.timedelta(hours=12)
> split_hours(start, end)
(datetime.timedelta(0, 5160), datetime.timedelta(0, 38040))
"How do I do that?" is my question. Sorry. I've been thinking through this most of the day but only ever got as far as the following napkin algorithm:
Split range into distinct-date datetime ranges (how?!) and for each:
Count hours before 7am and after 7pm as premium
Count hours between 7am and 7pm
Total them up.
But even there I don't know how to split things up.
There is also a natural extension —that I'll almost certainly have to implement at some point— that also grades weekend hours as premium too. If I could split time (as in my napkin algorithm) it would be easy to tack on but I still don't like how clumsy that "code" is). If your answer covers that too, you can have my firstborn. Well, no, you can have a bounty or something.
I'm doing this in Python without any real library limits (if eg Pandas Just Does™ this) but if you want to submit a raw C or Pseudo code answer, I'm sure I'll be able to read it.
We could:
generate a range of datetime between start and end
loop that range and calculate normal seconds (the length - normal = premium)
Here is the code:
import datetime
def split_hours(start, end):
# Total seconds
length = int((end-start).total_seconds())
# Generator with datetime objects
s = (start + datetime.timedelta(seconds=i) for i in range(length))
# Calculate normal and premium
# normal when hour > 7 AM, smaller than 7 PM and weekday not sat,sun
normal = sum(7 <= i.hour < 19 and i.weekday() not in [5,6] for i in s)
premium = length - normal
d = dict(normal=normal,
premium=premium,
total=dict(h=length/3600,m=length/60,s=length))
return d
And now we can do some tests:
start = datetime.datetime.now()
end1 = start + datetime.timedelta(hours=12)
end2 = start + datetime.timedelta(days=1)
end3 = start + datetime.timedelta(days=24)
print(split_hours(start,end1))
print(split_hours(start,end2))
print(split_hours(start,end3))
Returns:
# 12 hours
{'total': {'h': 12.0, 's': 43200, 'm': 720.0}, 'premium': 26131, 'normal': 17069}
# 1 days / 24 hours
{'total': {'h': 24.0, 's': 86400, 'm': 1440.0}, 'premium': 43200, 'normal': 43200}
# 7 days
{'total': {'h': 168.0, 's': 604800, 'm': 10080.0}, 'premium': 388800, 'normal': 216000}
That would be my approach:
from datetime import datetime, timedelta
def is_premium_time_period(start_time, end_time):
start_time = datetime.strptime(start_time, "%d-%m-%Y %H:%M")
end_time = datetime.strptime(end_time, "%d-%m-%Y %H:%M")
seconds = (end_time - start_time).total_seconds()
minutes = int(seconds / 60)
premium_minutes = 0
regular_minutes = 0
for minute in range(minutes):
premium_start = datetime.strptime("19:00 {}".format(start_time.date()), "%H:%M %Y-%m-%d")
premium_end = premium_start + timedelta(hours=12)
previous_start = premium_start - timedelta(hours=24)
previous_end = previous_start + timedelta(hours=12)
if premium_start <= start_time < premium_end or previous_start <= start_time < previous_end:
premium_minutes += 1
else:
regular_minutes += 1
start_time += timedelta(minutes=1)
_premium_hours = premium_minutes / 60
_regular_hours = regular_minutes / 60
return _premium_hours, _regular_hours
datetime_01 = "06-11-2017 14:17"
datetime_02 = "06-11-2017 19:20"
datetime_03 = "05-11-2017 02:39"
datetime_04 = "11-11-2017 08:39"
print(is_premium_time_period(datetime_01, datetime_02))
print(is_premium_time_period(datetime_03, datetime_04))
EDIT: I'm sorry, I forgot to post what it returns:
It returns:
(0.3333333333333333, 4.716666666666667)
(76.35, 73.65)
Meaning (premium_hours, regular_hours)
got a weird one i can not figure out how to solve
basically i have to run a section of code, this code extracts data from a file, which name is the format year-month-day-hour-00-00-consensus
so what i am trying to do is complete a loop that after the code runs adds an hour then once it gets to midnight adds a day etc, however while i have this working, i can not figure out how i can do this for the months as if it was easy as all months being 30 days for example this would be simple, i am having issues defining the length of days in the month, does any one have any ideas ?
this is the code so far :
def calculate_and_write_hsdir(h,d,m,y):
if h < 24:
if d < 10:
d = "0"+str(d)
if h < 10:
h = "0"+str(h)
if m < 10:
m = "0"+str(m)
consensus_file_name = str(y) + "-" + str(m) + "-" + str(d) + "-" + str(h) + "-00-00-consensus"
print consensus_file_name
..... do stuff ....
h = int(h) + 1
else:
h = 00
d = int(d) + 1
# d = d + 1
i pre set this by :
h = 00 #Hour
d = 01 #Day
m = 10 #Month
y = 2013 #Year
calculate_and_write_hsdir(h,d,m,y)
# def run_calculate(h,d,m,y):
# if m == 02:
# if d == 28:
# calculate_and_write_hsdir(h,d,m,y)
i want to start at 2013-10-01 and end at the present day, how can i achieve this ? sorry if it is a bit confusing but struggle on explaining what i want it to achieve
Python has a datetime module that will handle this for you. You make a datetime object representing the date and time, and a timedelta object to represent the addition of 1 hour. You can then, if you need to, check whether the new date is within the same day as the original date by comparing the .day property of the datetime object.
datetime also has a convenient method strftime for printing formatted output based on the date and time.
from datetime import datetime, timedelta
def calculate_and_write_hsdir(h,d,m,y):
before = datetime(hour = h, day = d, month = m, year = y)
now = before + timedelta(hours = 1)
if before.day == now.day:
print 'still the same day'
# ... do stuff ...
else:
print "now it's a different day"
# ... do other stuff ...
print now.strftime('%Y-%m-%d-%H-00-00-consensus')
h = 00 #Hour
d = 01 #Day
m = 10 #Month
y = 2013 #Year
calculate_and_write_hsdir(h, d, m, y)
I was asked to make a program that takes the day that I start my travel length of my stay as an input and give the day that I return in as an output so I tried this and I keep getting an error that says (KeyError = -3)
Note: I'm a beginner, so be easy on me :)
dect = {0:'Sunday', 1: 'Monday', 2:'Tuesday',3:'Wednesday', 4:'Thursday',
5:'Friday',6:'Saturday'
}
def day(x):
print( dect[x])
def holiday(start,length):
length = length + start
while True:
if length <= 0:
break
print(length)
else:
length = length - 7
day(length)
s = int(input('Enter the start day: '))
l = int(input('Enter the length of your stay: '))
holiday(s,l)
The value of length can become negative and this is why you're looking up -3 in the dictionary.
For example, if my holiday is 4 days (length = 4) then you're doing length = length - 7 which means you're calling day() with -3 as value.
Your dictionary only has values for the keys 0 - 6 and that's why you're getting a KeyError as the key -3 is not in the dictionary.
You can fix it by changing the check into if length < 7.
What you can do is, simply use datetime module.
from datetime import date,timedelta
d = date.today() + timedelta(days=2)
print d
You can use timedelta to add as many days/hours/whatever you want. See here for the documentation.
Replace your holiday function as -
def holiday(start,length):
length = length + start
length = length % 7
day(length)