Round time in python odoo - python

I use below example for round time in odoo.
#api.one
#api.depends('start','finish','pause')
def total(self):
for rec in self:
time1 = datetime.strptime(rec.start, "%Y-%m-%d %H:%M:%S")
time2 = datetime.strptime(rec.finish, "%Y-%m-%d %H:%M:%S")
rec.total_time = round(((time2 - time1).seconds / float(60*60) - self.pause))
For example:
if start = 07:57:21 , finish = 16:25:36, pause = 1 get result 7 hours
if start = 07:57:34 , finish = 16:28:42, pause = 1 get result 8 hours
First and second time different is 3 minutes but in result that is one hours!
How change round if total time >= 7 hours 30 minutes 01 second I need result 8 in other solution 7.5 (7 hours and 30 minutes)

For "%Y-%m-%d %H:%M:%S" you can use DEFAULT_SERVER_DATETIME_FORMAT
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
For your problem you can use round(x, n). Example:
round(7.4, 0) = 7
round(7.5, 0) = 8
round(7.5, 1) = 7.5
Here you need n = 1 for 7.5 and n=0 for the 'standard' round. You can check 7.5 with ((7.5 - 0.5) % 1) == 0 and convert it from boolean to int directly with int()
The general solution is:
#api.one
#api.depends('start','finish','pause')
def total(self):
for rec in self:
time1 = datetime.strptime(rec.start, DEFAULT_SERVER_DATETIME_FORMAT)
time2 = datetime.strptime(rec.finish, DEFAULT_SERVER_DATETIME_FORMAT)
total_time = (time2 - time1).seconds / float(60*60) - self.pause
rec.total_time = round(total_time, int(((total_time - 0.5) % 1) == 0))

#api.one
#api.depends('start','finish','pause')
def total(self):
for rec in self:
time1 = datetime.strptime(rec.start, DEFAULT_SERVER_DATETIME_FORMAT)
time2 = datetime.strptime(rec.finish, DEFAULT_SERVER_DATETIME_FORMAT)
total_time = (time2 - time1).seconds / float(60*60) - self.pause
total_time = 2*total_time
if 2*total_time%1 <=0.5 :
res = round(total_time)
else :
res = round(2*total_time)
rec.total_time = res

Related

Number of 15 minutes intervals between two datetimes

from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
How can I find the number of 15 minutes intervals exist between start and finish?
from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
elapsed = finish - start
number_of_intervals = elapsed / timedelta(minutes=15)
elapsed is the timedelta between start and finish. Divide by 15 minutes to calculate how many 15 minute intervals fit in there.
Note that this returns a float, so includes fractional intervals. Round as appropriate.
You need to find the difference between start and finish in minutes, divide by 15, and make that an int:
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
difference = (finish - start).total_seconds()/60
quarters = int(difference/15)
i would write something similar to this:
from datetime import datetime, timedelta
DATE_TIME_STRING_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
from_date_time = datetime.strptime('2016-06-06T05:00:00.000Z',
DATE_TIME_STRING_FORMAT)
to_date_time = datetime.strptime('2016-06-06T06:00:00.000Z',
DATE_TIME_STRING_FORMAT)
date_times = [from_date_time.strftime(DATE_TIME_STRING_FORMAT)]
date_time = from_date_time
while date_time < to_date_time:
date_time += timedelta(minutes=15)
date_times.append(date_time.strftime(DATE_TIME_STRING_FORMAT))
print(date_times)
Output:
['2016-06-06T05:00:00.000000Z', '2016-06-06T05:15:00.000000Z', '2016-06-06T05:30:00.000000Z', '2016-06-06T05:45:00.000000Z', '2016-06-06T06:00:00.000000Z']
Edit:
If you are interested in just the number of 15 minute intervals you can use something like:
from datetime import datetime, timedelta
DATE_TIME_STRING_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
from_date_time = datetime.strptime('2016-06-06T05:00:00.000Z',
DATE_TIME_STRING_FORMAT)
to_date_time = datetime.strptime('2016-06-06T06:00:00.000Z',
DATE_TIME_STRING_FORMAT)
print((to_date_time-from_date_time) / timedelta(minutes=15))
You can use time library instead of date time. time works with seconds and you should convert minutes to seconds:
import time
interval = 45*60
start = time.time()
finish = time.time() + interval
diff = finish - start
print(diff // (15*60))
Simply compare start and finish like so:
from datetime import datetime, timedelta
now = datetime.now()
start = now + timedelta(minutes = 15)
finish = start + timedelta(minutes = 30)
elapsed = finish - start # This is a timedelta object
reference_interval = 15*60 # interval in seconds
number_of_intervals = elapsed.seconds/reference_interval
As pointed out by Sören, this will not work if 'elapsed' is more than one day, in which case, simply compute the number as follow:
number_of_intervals = (elapsed.days*86400+elapsed.seconds)/reference_interval
# (86400 seconds in a day)

RuntimeWarning: DateTimeField Model.date received a naive datetime while time zone support is active

I am trying to filter a query set to obtain this year's all posts.
def thisYearQuerySet(objects):
start_day = datetime.date(datetime.date.today().year, 1, 1)
end_day = datetime.date(datetime.date.today().year, 12, 31)
return objects.filter(date__range=[start_day, end_day])
django moans about start_day and end_day declaration may conflicts django.utils.timezone, I think it is not a big deal.
But the warning is annoying, any suggestion on dismissing it (not disable django warning) will be appreciated. something like, how to get first day of the year and the last from django.utils
full warning
RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-01-01 00:00:00) while time zone support is active.
RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-12-31 00:00:00) while time zone support is active.
it seems I must set a region to dismiss the warning.
I attached the module implemented in my project that have methods may help you.
import pytz
import datetime
from django.utils import timezone
from django.conf import settings
from django.db.models import Q
from django.utils.dateparse import parse_datetime
# MM/DD/YY
def when(create):
return '%s/%s/%s' % (create.month, create.day, create.year)
def current():
return when(timezone.now())
# create: date of object creation
# now: time now
# li: a list of string indicate time (in any language)
# lst: suffix (in any language)
# long: display length
def howLongAgo(
create,
now,
# li=[
# 'sec',
# 'min',
# 'h',
# 'day',
# 'week',
# 'month',
# 'year',
# ],
li=[
'秒',
'分',
'时',
'天',
'周',
'月',
'年',
],
# lst='ago',
lst='之前',
long=2
):
dif = create - now
sec = dif.days * 24 * 60 * 60 + dif.seconds
minute = sec // 60
sec %= 60
hour = minute // 60
minute %= 60
day = hour // 24
hour %= 24
week = day // 7
day %= 7
month = (week * 7) // 30
week %= 30
year = month // 12
month %= 12
s = []
for ii, tt in enumerate([sec, minute, hour, day, week, month, year]):
ss = li[ii]
if tt != 0:
s.append(str(tt) + ss)
# if tt == 1:
# s.append(str(tt) + ss)
# else:
# s.append(str(tt) + ss + 's')
return ' '.join(list(reversed(s))[:long]) + lst
# conversion
def dateToDatetime(li):
res = []
for ar in li:
res.append(datetime.datetime.combine(ar, datetime.datetime.min.time()))
return res
def datespan(startDate, endDate, delta=datetime.timedelta(days=1)):
currentDate = startDate
while currentDate < endDate:
yield currentDate
currentDate += delta
# queryset
def thisMonthQuerySet(objects):
today = timezone.now()
year = today.year
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, today.month, 1)))
end_day = start_day + datetime.timedelta(30)
return objects.filter(date__range=[start_day, end_day])
def lastMonthQuerySet(objects):
today = timezone.now()
year = today.year
month = today.month - 1
if month == 0:
year -= 1
month = 12
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, month, 1)))
end_day = start_day + datetime.timedelta(30)
return objects.filter(date__range=[start_day, end_day])
def thisYearQuerySet(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
return objects.filter(date__range=[start_day, end_day])
def lastYearQuerySet(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
return objects.filter(date__range=[start_day, end_day])
def lastQuaterQuerySet(objects):
today = timezone.now()
four_month_before = today - timezone.timedelta(30 * 4)
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(four_month_before.year, four_month_before.month, 1)))
return objects.filter(date__gte=start_day)
# timespan
def getLastWeek():
date = datetime.date.today()
end_day = date - datetime.timedelta(date.weekday())
start_day = end_day - datetime.timedelta(7)
return dateToDatetime([day for day in datespan(start_day, end_day)])
def getThisWeek():
date = datetime.date.today()
start_day = date - datetime.timedelta(date.weekday())
end_day = start_day + datetime.timedelta(7)
return dateToDatetime([day for day in datespan(start_day, end_day)])
def getLastMonth():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month - 1 if today.month - 1 != 0 else 1, 1)))
end_day = start_day + datetime.timedelta(30)
return [day for day in datespan(start_day, end_day)]
def getThisMonth():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, 1)))
end_day = start_day + datetime.timedelta(30)
return [day for day in datespan(start_day, end_day)]
def getLastYear():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
return [day for day in datespan(start_day, end_day)]
def getThisYear():
today = datetime.date.today()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
return [day for day in datespan(start_day, end_day)]
# exclude
def dayNotIn(objects):
return objects.filter(~Q(date=timezone.now()))
def weekNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=7))
def monthNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=30))
def yearNotIn(objects):
return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=365))
# month only
def getQSbyYM(objects, y, m):
# m in [0, 12]
em = m + 1
ey = y
if em == 13:
em = 1
ey = y + 1
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(y, m, 1)))
end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(ey, em, 1)))
return objects.filter(date__lt=end_day, date__gte=start_day)
def createInToday(objects):
today = timezone.now()
start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, today.day)))
end_day = start_day + datetime.timedelta(1)
return objects.filter(date__lt=end_day, date__gte=start_day)
def dtstr(dt) -> str:
return dt.strftime('%Y-%m-%dT%H:%M:%S')
def strdt(st):
return pytz.timezone('Asia/Shanghai').localize((parse_datetime(st)))
modify date__ according to model date time field name, also change timezone based on where your site works.
django moans about start_day and end_day declaration may conflicts django.utils.timezone, I think it is not a big deal.
This depends on the level of risk you're comfortable with. By not taking into account the user's timezone, thisYearQuerySet could return objects from last year or the current year as you near the new year.
This is because the server could be running at GMT time, which means at 2022-01-01 00:00:00T00:00, it would start returning data with dates of the year 2022. However any Americans using the application would know the year to be 2021 for 4+ hours yet and would expect to see 2021's data until their own midnight.
However, if you're trying to silence the warning and don't care about the above scenario, don't use the python datetime functions when getting today/now. Use:
from django.utils import timezone
now = timezone.now()
today = timezone.now().date()

Slots Creation based on date and time(float) field

I have two date field.
from_date and
to_date
In One2many line item, there is three float fields
from_time ,to_time and interval
Slot have to be created based on the above parameters.
Example:
from_date = '2017-07-21'
to_date = '2017-07-21'
the duration is one day.
The One2many line items have the values
from_time = 9.0
to_time = 10.0
interval = 30(in minutes)
The output should generate two slots
1. '2017-07-21 09:00:00' '2017-07-21 09:30:00'
2. '2017-07-21 09:30:00' '2017-07-21 10:00:00'
It should generate two line items.
If the duration is for week.
it should generate 2 * 7 = 14 slots.
I have used the code which generates for one day.
#api.one
def generate(self):
cr = self.env.cr
uid = self.env.uid
context = self.env.context
event = self.pool.get('calendar.event')
slot = self.pool.get('slot.booking')
old_data_id = slot.search(cr, uid, [('slot_id', '=',self.id)], context=context)
slot.unlink(cr, uid ,old_data_id)
for each in self.shift_line:
if each.interval > 60 or each.interval == 0:
raise osv.except_osv(_('Attention!'), _('Please enter interval timings in minutes range like (10-60) '))
interval = each.interval
fmt = "%Y-%m-%d"
start_date = datetime.strptime(self.from_date, fmt)
end_date = datetime.strptime(self.to_date, fmt)
days = []
date = start_date
pdb.set_trace()
str_start_time = '%s %s' % (self.from_date,'{0:02.0f}:{1:02.0f}'.format(*divmod(each.from_time * 60, 60)))+':00'
str_end_time = '%s %s' % (self.from_date,'{0:02.0f}:{1:02.0f}'.format(*divmod(each.to_time * 60, 60)))+':00'
time = datetime.strptime(str_start_time, '%Y-%m-%d %H:%M:%S')
end = datetime.strptime(str_end_time, '%Y-%m-%d %H:%M:%S')
while date <= end_date:
hours = []
while time <= end:
hours.append(time.strftime("%Y-%m-%d %H:%M:%S"))
time += timedelta(minutes=interval)
date += timedelta(days=1)
time += timedelta(days=1)
end += timedelta(days=1)
days.append(hours)
print "\n\n\n\n\nn\+++++++++++++++++++++days",days
for hours in days[0][:-1]:
val = datetime.strptime(hours, '%Y-%m-%d %H:%M:%S')
val = val + timedelta(minutes=interval)
values = {
'name' : 'Slot for ' + self.employee_id.name,
'start_datetime' : hours,
'stop_datetime' : str(val),
'slot_id' : self.id,
'shift_lines_id' : each.id,
'partner_id': self.employee_id.id,
'duration' : each.interval,
}
print "\n\n\n\n\n\n\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++values",values
slot.create(cr, uid, values, context=context)
Any help for multiple days is appreciated.
ist_timedelta = timedelta(seconds=((time in seconds)-10800))
adding this will give the exact answer, here 10800 is because of 3 hours difference of UTC to KSA.

if logic breaks when calculating time over multiple days

My code below - yes, ugly. I am learning python. It works when the start/end dates are both the same day.
When start = 2017,6,15 6:00 & end = 2017,6,16 6:00
The if statement that gets applied is if start < 6am. Can someone explain why? It does recognize that 1 day is the duration.
from datetime import datetime, date, time
def babysitting():
(st_yr,st_mon,st_day) = [int(s) for s in input("Enter the start date in the format: YYYY,M,D: ").split(',')]
(st_hr,st_min) = [int(s) for s in input("Enter the start time in 24hr format -> HH:MM: ").split(":")]
(e_yr,e_mon,e_day) = [int(s) for s in input("Enter the end date in the format: YYYY,M,D: ").split(',')]
(e_hr,e_min) = [int(s) for s in input("Enter the end time in 24hr format -> HH:MM: ").split(":")]
st_date = date(st_yr,st_mon,st_day)
st_time = time(st_hr,st_min)
end_date= date(e_yr,e_mon,e_day)
end_time = time(e_hr,e_min)
start = datetime.combine(st_date,st_time)
end = datetime.combine(end_date,end_time)
ninePM = datetime.combine(end_date, time(21,00))
sixAM = datetime.combine(end_date, time(6,00))
if start >= sixAM:
if end <= ninePM:
normal_rate_duration = end - start
normal_rate_seconds = normal_rate_duration.total_seconds()
normal_rate_billing = round(((normal_rate_seconds / 60) / 60) * 2.5,2)
print("Cost for babysitting is: $", normal_rate_billing)
elif end > ninePM:
normal_rate_duration = ninePM - start
reduced_rate_pm_duration = end - ninePM
normal_rate_seconds = normal_rate_duration.total_seconds()
normal_rate_billing = round(((normal_rate_seconds / 60) / 60) * 2.5,2)
reduced_rate_pm_seconds = reduced_rate_pm_duration.total_seconds()
reduced_rate_pm_billing = round(((reduced_rate_pm_seconds / 60) / 60) * 1.75,2)
print("Cost for babysitting is: $", normal_rate_billing + reduced_rate_pm_billing)
if start < sixAM:
if end <= ninePM:
reduced_rate_am_duration = sixAM - start
reduced_rate_am_seconds = reduced_rate_am_duration.total_seconds()
reduced_rate_am_billing = round(((reduced_rate_am_seconds / 60) / 60) * 1.75,2)
normal_rate_duration = end - sixAM
normal_rate_seconds = normal_rate_duration.total_seconds()
normal_rate_billing = round(((normal_rate_seconds / 60) / 60) * 2.5,2)
print("Cost for babysitting is: $", normal_rate_billing + reduced_rate_am_billing)
elif end > ninePM:
reduced_rate_am_duration = sixAM - start
reduced_rate_am_seconds = reduced_rate_am_duration.total_seconds()
reduced_rate_am_billing = round(((reduced_rate_am_seconds / 60) / 60) * 1.75,2)
normal_rate_duration = ninePM - sixAM
normal_rate_seconds = normal_rate_duration.total_seconds()
normal_rate_billing = round(((normal_rate_seconds / 60) / 60) * 2.5,2)
reduced_rate_pm_duration = end - ninePM
reduced_rate_pm_seconds = reduced_rate_pm_duration.total_seconds()
reduced_rate_pm_billing =round(((reduced_rate_pm_seconds / 60) / 60) * 1.75,2)
print("Cost for babysitting is: $", normal_rate_billing + reduced_rate_am_billing + reduced_rate_pm_billing)
babysitting()
your if checks whether or not the start time was earlier than 6am on the end date, which of course it will be (it's some time the day before or something like that). you need to check if st_time is earlier than 6am (regardless of date, or on the st_date date).

python data frame filter conditions: any faster way

parts_list = imp_parts_df['Parts'].tolist()
sub_week_list = ['2016-12-11', '2016-12-04', '2016-11-27', '2016-11-20', '2016-11-13']
i = 0
start = DT.datetime.now()
for p in parts_list:
for thisdate in sub_week_list:
thisweek_start = pd.to_datetime(thisdate, format='%Y-%m-%d') #'2016/12/11'
thisweek_end = thisweek_start + DT.timedelta(days=7) # add 7 days to the week date
val_shipped = len(shipment_df[(shipment_df['loc'] == 'USW1') & (shipment_df['part'] == str(p)) & (shipment_df['shipped_date'] >= thisweek_start) & (shipment_df['shipped_date'] < thisweek_end)])
print(DT.datetime.now() - start).total_seconds()
shipment_df has around 35000 records
partlist has 436 parts
sub_week_list has 5 dates in it
it took overall 438.13 secs to run this code
Is there any faster way to do it?
parts_list = imp_parts_df['Parts'].astype(str).tolist()
i = 0
start = DT.datetime.now()
for p in parts_list:
q = 'loc == "xxx" & part == #p & "2016-11-20" <= shipped_date < "2016-11-27"'
val_shipped = len(shipment_df.query(q))
print (DT.datetime.now() - start).total_seconds()

Categories