odoo calculate age from a date field and today date - odoo

I want to get an age between a field and today date
from openerp import models, fields, api, _
from openerp import SUPERUSER_ID
from datetime import date
class report_purchase_stock(models.Model):
_name='report.purchase.stock'
etaw_update = fields.Date('ETA Warehouse') // 2022-01-24
etaw_age = fields.Char('Days in Warehouse')
I have tried something like this from the forum but it return empty
#api.onchange('etaw_update')
def set_age(self):
for rec in self:
if rec.etaw_update:
dt = rec.etaw_update
d1 = datetime.strptime(dt, "%Y-%m-%d").date()
d2 = date.today()
rd = relativedelta(d2, d1)
rec.etaw_age = str(rd.years) + ' years'
What I want is something like 1 month 14 days

I assume that etaw_update is a date where the product entering warehouse for the first time, and etaw_age is the total days where that product has been stored. Is that right?
If that so, you may want to define a current_date variable which will get the todays date, and then you can subtract that current_date with etaw_update
#api.onchange('etaw_update')
def set_age(self):
for rec in self:
current_date = date.today()
date_in_your_field = rec.etaw_update
rec.etaw_age = current_date - date_in_your_field
print(str(rec.etaw_age))
Please let me know if this what you need

Related

Rate of return calc. on time-series. Function doesn't select all past and valid business days in a time-series. Also, for loop issues

I am doing a period (annual, quarter, month) rate of return function for the SPX Stock Market Index (S&P500) for data range from 1990 to 13 Jan. 2023. Data source: yfinance. I'm working with "Close" prices, daily frequency data and Date column set as index.
Dataframe:
Date
Close
2023-01-13
3999.09
2023-01-12
3983.17
.........
........
........
........
1990-01-03
358.76
1990-01-02
359.69
Functions bellow generally work, but it is not selecting all valid End and Previous/Past dates. Valid dates are business or trading days. Weekends are not valid days.
In code bellow, I wish to get the annual return between years: (end_date.Close / past_date.Close - 1) * 100. For example, 2023 annual return is [2023/01/13].Close / [2022/01/13].Close - 1.
However, my output is missing the following end_date / return pair: 2020/01/13 - Return %. And this is the issue; I need all period returns in a time-series or the analysis doesn't make sense.
I also need these functions to work with quarter and monthly return periods.
This is what my output looks like:
Date
Return (%)
2023-01-13
-14.164751
2022-01-13
22.289387
2021-01-13
15.866465
2019-01-11
-6.818508
.......
..........
1992-12-29
5.501758
1991-01-11
-7.266202
You can see in the output that I am missing 2020/01/13 - Return % pair. The rest of the output is correct and as expected.
My best guess is that I have not chosen an appropriate way to cycle through periods with a for loop. But I'm not quite sure. I would certainly appreciate a fresh pair of eyes on this one.
Functions:
# Number of periods used in for loop in "get_Returns" function (period: year, quarter, month)
no_periods = (relativedelta(edate, sdate).years)
no_periods
# get the first valid/available business day (descending direction) if selected date is a weekend
def nearest_date(date_range, reference_date):
# get previous days before the reference date
# reference date is a date that lands on a weekend
prevDate = date_range[date_range < reference_date]
# return the last date of the date range prior to reference date
return prevDate[0]
# get historical returns function
# function input: "period" ('M' month, 'Y' year)
# function input: "number" is number of periods
def get_Returns(df, period, number, end_date):
# get all business days in df data range
df2 = df.reset_index()
existingDates = df2['Date'].unique()
# get the first past date (end date - period offset) on years or some other period (month, week)
if period == 'Y':
past_date = (pd.to_datetime(end_date) - pd.DateOffset(years=number))
elif period == 'M':
past_date = (pd.to_datetime(end_date) - pd.DateOffset(months=number))
elif period == 'W':
past_date = (pd.to_datetime(end_date) - pd.DateOffset(weeks=number))
elif period == 'D':
past_date = (pd.to_datetime(end_date) - pd.DateOffset(days=number))
dates = [] # list of valid dates for return calculation
returns = [] # list of period returns
end_date = pd.to_datetime(end_date)
# check if end_date (E) and past_date (P) were valid business days
# check 4 conditions: E and P valid, E valid/P not, P valid/E not, both P&E not valid.
# Valid means trading day; not a weekend.
# if not, get closest business days with "nearest_date" function
# then, return the price change ([end_date.price / past_date.price] - 1) * 100
for period in range(no_periods):
if end_date in existingDates:
if past_date in existingDates: # existingDates: all business days
dates.append(end_date)
end_price, start_price = df.loc[end_date].Close, df.loc[past_date].Close
returns.append((end_price / start_price - 1) * 100)
elif end_date in existingDates:
if past_date not in existingDates:
closestDate = nearest_date(existingDates, past_date)
dates.append(end_date)
end_price, start_price = df.loc[end_date].Close, df.loc[closestDate].Close
returns.append((end_price / start_price - 1) * 100)
past_date = closestDate
elif past_date in existingDates:
if end_date not in existingDates:
edate = nearest_date(existingDates, end_date)
end_price, start_price = df.loc[edate].Close, df.loc[past_date].Close
returns.append((end_price / start_price - 1) * 100)
end_date = edate
dates.append(end_date)
elif end_date not in existingDates:
if past_date not in existingDates:
closestDate = nearest_date(existingDates, past_date)
edate = nearest_date(existingDates, end_date)
end_price, start_price = df.loc[edate].Close, df.loc[closestDate].Close
returns.append((end_price / start_price - 1) * 100)
end_date = edate
past_date = closestDate
dates.append(end_date)
# offset/update end/past date before next loop.
end_date = (pd.to_datetime(end_date) - pd.DateOffset(years=number))
past_date = (pd.to_datetime(past_date) - pd.DateOffset(years=number))
returns_df = pd.DataFrame(
data=returns,
index=pd.DatetimeIndex(dates, name='Date'),
columns=['Return(%)'])
return returns_df
spx_returns = get_Returns(df, 'Y', 1, '2023-01-13')
spx_returns
This is where my output is missing the following end_date / return pair: 2020/01/13 - Return %.

Remove hours and extract only month and year

I try to keep only month and year in this df. I tried several solutions but it is not working. Can you help me ?
YOu need to do this (as you post no data, you'll need to adapt this to your case):
from datetime import datetime
datetime_object = datetime.now()
print(datetime_object)
2021-11-30 15:57:20.812209
And to get the year and month do this:
new_date_month= datetime_object.month
print(new_date_month)
new_date_year = datetime_object.year
print(new_date_year)
11
2021
If you need them as new columns in you df:
df['year']=datetime_object.year
df['Month']=datetime_object.month
Note that if your column is not a datetime, this will not work. Given to format of date you hve you will need to do this first:
st = '2021-11-30 15:57:20.812209'
datetime.strptime(st, '%Y-%m-%d %H:%M:%S.%f')

Hive SQL Integer YYYYMM previous Months

I want to create an SQL statement that looks for the last 2 months.
For example:
Select *
from x
where sampledate<= YYYYMM-2
currently i am using this:
(year(from_unixtime(unix_timestamp()))*100+month(from_unixtime(unix_timestamp())))-1
but it returns wrong statements for the first 2 months of a year :(
My idea is to calculate with a date and then change it to a yyyymm integer format.
Any ideas?
Could you try this:
SELECT colomn
FROM table
WHERE date > (SELECT add_months(from_unixtime(unix_timestamp()),-2));
or you can use:
SELECT colomn
FROM table
WHERE date > to_date(SELECT year(add_months(from_unixtime(unix_timestamp()),-2))+month(add_months(from_unixtime(unix_timestamp()),-2)));
Combined with regex&substring:
SELECT colomn
FROM table
where sampledate>=substr(regexp_replace(add_months(from_unixtime(unix_timestamp()),-2), '-',''),1,6)
to get a YYYYMM date
If you want to avoid converting an integer, in YYYYMM format, to and from a date, you can just use maths and CASE statements...
For example YYYYMM % 100 will give you MM. Then you can check if it's 2 or less. If it is 2 or less, deduct 100 to reduce by a year, and add 12 to get the month as 13 or 14. Then, deducting 2 will give you the right answer.
Re-arranging that, you get YYYYMM - 2 + (88, if the month is 1 or 2)
sampledate <= YYYYMM - 2 + CASE WHEN YYYYMM % 100 <= 2 THEN 88 ELSE 0 END
The better idea may just be to reshape your data so that you actually have a (real) date field, and just use ADD_MONTHS(aRealDate, -2)...
EDIT:
If your actual issue is generating the YYYYMM value for "two months ago", then deduct the 2 months before you use the YEAR() and MONTH() functions.
year( ADD_MONTHS(from_unixtime(unix_timestamp()), -2) )*100
+
month( ADD_MONTHS(from_unixtime(unix_timestamp()), -2) )
Try something like this.
First, a utility to get the date n months in the future/past:
public Date nMonthsFromDate(Date date, int interval) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
// E.G. to get 2 months ago, add -2
cal.add(Calendar.MONTH, interval);
Date result = cal.getTime();
return result;
}
Criteria query on the entity, here Member:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Member> q = cb.createQuery(Member.class);
Root<Member> memberRoot = q.from(Member.class);
Date theDate = nMonthsFromToday(-2);
Predicate pred = cb.greaterThanOrEqualTo(
memberRoot.<Date>get("timeStamp"), theDate);
q.where(pred);
TypedQuery<Member> theQuery = em.createQuery(q);
String qStr = theQuery
.unwrap(org.apache.openjpa.persistence.QueryImpl.class)
.getQueryString();
LOG.info("Query: " + qStr);
List<Member> results = null;
try {
results = theQuery.getResultList();
} catch (Exception e) {
LOG.severe(e.getMessage());
e.printStackTrace();
}
return results;
Finally, beware of comparing a date [java.util.Date] to a timestamp [util.sql.Date]. Due to a quirk in Java, for equivalent dates, date.equals(timeStamp) returns true, BUT timeStamp.equals(date) returns FALSE. To conform both dates to a java.util.Date:
public java.util.Date getStandardDate(Date date) {
return new java.util.Date(date.getTime());

how can I add n days to a date excluding National holidays odoo

how can I exclude national holidays ?
I used the code below to exclude Sundays
#api.depends('date_request', 'Nbr_days')
def _compute_date_result(self):
for record in self:
business_days_to_add = record.Nbr_days
current_date = fields.Datetime.from_string(record.date_request)
while business_days_to_add > 0:
current_date += timedelta(days=1)
weekday = current_date.weekday()
if weekday >= 6:
continue
business_days_to_add -= 1
record.date_perform=current_date
Since holidays normally span whole dates, you can do the following:
holiday_dates = set([dt.date() for dt in Holidays])
# And a few lines later in your exclusion check
# while ...
if weekday >= 6 or current_date.date() in holiday_dates:
continue

VB.net work out number of days between two dates [duplicate]

This question already has answers here:
How to find the number of days between two dates / DateTimePickers
(3 answers)
Closed 6 years ago.
I am trying to work out the number of days between two dates and whether it is a full month or not.
I currently have this code:
Dim fromdate As Date
Dim todate As Date
Dim timespan
Dim num_days As String
Dim month As DateTime
fromdate = Date.Parse("01/01/2017")
todate = Date.Parse("31/01/2017")
TimeSpan = todate - fromdate
num_days = TimeSpan.Days
MsgBox(num_days)
And then I try to work out if it is a full month:
month = todate
If (month.Month = "02" And num_days = "28") Or num_days = "29" Or num_days = "30" Or num_days = "31" Or num_days = "0" Then
'do code here
Else
'do code here
End If
But this is proving to not work in February because it only sees the num_days as 27
Is there a way I can get the correct number of days between the two dates including the dates themselves being full days?
And how can I check if it is a full, correct month or not
UPDATE
The purpose of this is for a billing system so files are read into a database with from and to dates then it needs to work out the pricing from those dates.
So a product has a specific price, but first of all we need to work out whether to bill for part of a month or a full month (basically part of the product price or the full price)
So these 'Full Month' date range examples will bill the full price
Full Month:
01/01/2017 - 31/01/2017
25/01/2017 - 25/01/2017
18/01/2017 - 18/02/2017
10/01/2017 - 10/01/2018
Whereas, this date range for 'Part Month' will only bill for the number of days between the from and to date (+1 day)
Part Month
15/01/2017 - 31/01/2017
This would get what you specified:
Dim IsOneFullMonth = (d1.Day = 1 And d2 = d1.AddMonths(1).AddDays(-1))
Dim IsOnMonthLater = (d2 = d1.AddMonths(1))
The two states are not really the same thing in my understanding.
The second check is one month and one day.
(The first would match 'Jan 01 - Jan 31', the second one 'Jan 01 - Feb 01'.)
Also consider that neither check would match 'end of months' like 2016-02-29 - 2016-03-31 - you have to really define what you want to achieve in those cases.