I'm trying to think of the best way to create a function that avoids using loops/while. Any ideas?
Given a function prototype:
{[sd;n:hols]
/ return list of n number of dates <= SD, excluding weekends and hols
}
Thanks and happy holidays
You can use lists and the fact that dates in kdb+ are built on underlying integers:
{[sd;n;hols] d where not[d in hols]&1<mod[d:sd-til n]7}
This uses a til to generate the list of dates up to today, then filters using mod and at the same time checks to make sure the remaining dates aren't in the holiday filter list, before using true results to index back into the generated date list. These will be in descending order, but you can use
{[sd;n;hols] reverse d where not[d in hols]&1<mod[d:sd-til n]7}
To have an ascending date order.
An alternative solution would exclude the holidays before calculating the modulus:
{[sd;n;hols] d where 1<mod[d:except[;hols]sd-til n]7}
The components here are similar to Ryan's answer, other than using "except" to exclude the holidays.
In order to extract exactly n days, you can initially generate a larger list and return a sublist of the correct length, e.g.
{[sd;n;hols] n#d where 1<mod[d:except[;hols]sd-til 2*n]7}
knowing 2000.01.01 and 2000.01.02 are Saturday and Sunday and that mod those dates are 0 and 1 then excluding all dates who's modular is 0 1 I used:
getBusinessDays:{[Dates;N;Hols] N#(Dates*(Dates mod 7) in 2 3 4 5 6) except 2000.01.01,Hols}
Will return the first N business days you entered excluding holidays you chose.
Related
I am very new at all of this, and I don't know if what I want to do is even possible, but I'm hoping someone can assist me with some formulas if it is.
I am trying to create a spreadsheet for my business's scheduling purposes. I have created a spreadsheet that lists my PO's, start date, end date, location, project hours, and total days.
I currently have a couple formulas on the sheet. When I enter the project hours in column e the formula =roundup(E2/24) inputs the expected total days of work into column f.
I have a starting date of 7/1/2022 entered in b2 then have a formula that looks at column c (end date) and adds the amount of days from column f (total days) to the end date. Each line there after copies the end date from the row above to the start date and then adds the total days from f to that to complete the next row.
What I would like to do is have the dates only reflect workdays (M-F) instead of returning all dates. Is this even possible?
Take a look at spreadsheet example, but it is pretty basic.
Thank you in advance for any help you can provide!
I understand that you want to add "Total days" to the "Start Date" to get the "End Date" excluding weekends, in this case Sundays and Saturdays.
Paste this formula in cell C2 "End Date" column.
=ArrayFormula(IF(E2:E="",,WORKDAY.INTL(B2:B,F2:F,"0000011",)))
Breakdown:
1 - ArrayFormula output's values into several rows and/or columns, and to make the formula dynamic.
2 - WORKDAY.INTL determines the date after a certain number of workdays, excluding certain number of weekends and holidays.
3 - [weekend] argument using string method of ones and zeros "0000011" to specify workdays and weekends, 0 workday, 1 weekends starting from Monday to Sunday.
here is the link to the spreadsheet, hope that answerd your question.
In a graph I'm trying to show last month with this expression:
=If( [SH_historico_1.ANOMES] >= '$(=Max([SH_historico_1.ANOMES])-1)' and [SH_historico_1.ANOMES] <= '$(=Max([SH_historico_1.ANOMES]))', [SH_historico_1.ANOMES])
When I write [SH_historico_1.ANOMES] I'm referring to Period, Like 'YYYYMM'
And when I subtract -1 I'm just substact 1 to, example: 202002 -1 = 202001, so works, because It will calculate the correct period.
But... If the month it is january? YYYY01? example 202001 -1 = 202000 00 month number it does not exist. The 00 it should be 12.
So I'm wondering what if I treat the number as a date?
I'm trying to use Date() function but I'm little stuck.
How it could be with correct syntax?
Another solution I'm thinking it is to set some code in editor code, but still developing the idea.
Any help it is welcome.
When you want to add/subtract months its better to use AddMonths() function: AddMonths( DateField, NumberOfMonths). This function will deal with the January issue
In your case will be: =AddMonths(Max([SH_historico_1.ANOMES]), -1) (as you can see the number of months can be negative number which will subtract the months from the date)
And a bit on advice: If you are planning to use this calculation in expression then consider using Set Analysis instead of if..then..else statement. if statements are slower and they are consuming more resources when used in expressions
I want to backfill from a particular date to the latest date(say last working day).
Considering I have total 671 partitions
count .Q.pv / 671j
And we need to backfill for last 10 days
{//backfill function; 0n!x}#'660 11 sublist .Q.pv
Is there any other/better way to provide partition dates to backfill function other then using sublist.
You can use -10#date to get last 10 dates in your hdb.
Another "safer" option would be to use sublist as this will work in the occurrence of you having less than 10 dates in your hdb:
-10 sublist date
To list all dates between two dates you could use the following formula;
q)daterange:{[date1;date2] 1+date1+til date2-date1}
q)daterange[2019.05.29;2019.06.03]
2019.05.30 2019.05.31 2019.06.01 2019.06.02 2019.06.03
This will increment from date1 until as many days as there are between date1 and date2.
Hope this helps
I have a table
t:`date xasc ([]date:100?2018.01.01+til 100;price:100?til 100;acc:100?`a`b)
and would like to have a new column in t which contains the counts of entries in t where date is in the daterange of the previous 14 days and the account is the same as in acc. For example, if there is a row
date price acc prevdate prevdate1W countprev14
2018.01.10 37 a 2018.01.09 2018.01.03 ?
then countprev14 should contain the number of observations between 2018.01.03 and 2018.01.09 where acc=a
The way I am currently doing it can probably be improved:
f:{[dates;ac;t]count select from t where date>=(dates 0),date<=(dates 1),acc=ac}[;;t]
(f')[(exec date-7 from t),'(exec date-1 from t);exec acc from t]
Thanks for the help
Another method is using a window join (wj1):
https://code.kx.com/q/ref/joins/#wj-wj1-window-join
dates:exec date from t;
d:(dates-7;dates-1);
wj1[d;`acc`date;t;(`acc`date xasc t;(count;`i))]
I think you're looking for something like this:
update count14:{c-0^(c:sums 1&x)y bin y-14}[i;date] by acc from t
this uses sums to get the running counts, bin to find the running count from 14 days prior, and then indexes back into the list of running counts to get the counts from that date.
The difference between the counts then and now are those from the latest 14 days.
Note the lambda here allows us to store the result from the sums easily and avoid unnecessary recomputation.
I need to filter my query with different time intervals like that:
...
where
date >= '2011-07-01' and date <='2011-09-30'
and date >='2012-07-01' and date >='2012-09-30'
I suppose such code is not good, because these dates conflicts with each other. But how to filter only these two intervals, skipping everything else? Is it even possible? Because if I query like this, I don't get any results.I tried to use BETWEEN, but it does same thing.
I bypassed this by extracting quarters from years and calculating only third quarter. But then other quarters sum is showed as zero and I can't ignore these rows that have sum column with zero value. I tried to filter where price > 0 (column where sum goes), but it says that column do not exist. So I put it whole FROM under '('')' brackets to make it calculate sum before where clause, but it still does give me error that such column do not exist.
Also if you need to see query I have now, I can post it, just tell me if it is needed.
I want to do this, because I need to compare third quarter of two different years (maybe I should use another approach).
You're not going to get any results because you can't have a date that's both within 7/1/2011 through 9/30/11 and after 7/1/2012 and after 9/30/12.
You can have a date that is either between 7/1/20122 and 9/30/2011 or between 7/1/2012 and 9/30/2012.
SELECT col1 FROM table1
WHERE date BETWEEN '7/1/2011' AND '9/30/2011' OR date BETWEEN '7/1/2012' AND '9/30/2012';