How can you define custom Quarters in formula without helper columns? - date

I'm trying to calculate how much is left to close in terms of business in this current quarter.
To do this, I need to identify where we are in the quarter, how much has been closed and how much is left until the end of the quarter.
The problem is our Financial Year starts on Feb 1 and ends Jan 31st -
I tried this formula but won't work in my case.
=ROUNDUP(MONTH(*reference or date*)/3;0)
Any thoughts on how I can go around this? Also, how can I identify where in the quarter we are to calculate Quota for Q minus QTD?

The standard formula is
=int((month(A2)+2)/3)
So the adjusted formula (in B2) would be obtained by going back one month:
=int((month(eomonth(A2,-1))+2)/3)
The quarter end is given by multiplying the quarter by 3 to get the month and going forward one month:
=eomonth(date(year(A2),B2*3,1),1)
EDIT
The year for the end quarter of January in C2 is clearly incorrect - you could fix it by putting
=eomonth(date(year(A2)-(month(A2)<2),B2*3,1),1)

our Financial Year starts on Feb 1 and ends Jan 31st
="Q"&QUERY(DATE(YEAR(A1), MONTH(A1)-1, DAY(A1)),
"select quarter(Col1) label quarter(Col1)''")
calculate how much is left to close in terms of business in this current quarter
=VLOOKUP(TODAY(), {DATE(YEAR(TODAY()), 2, 1), DATE(YEAR(TODAY()), 2+3, 1);
DATE(YEAR(TODAY()), 5, 1), DATE(YEAR(TODAY()), 5+3, 1);
DATE(YEAR(TODAY()), 8, 1), DATE(YEAR(TODAY()), 8+3, 1);
DATE(YEAR(TODAY()), 11, 1), DATE(YEAR(TODAY()), 11+3, 1)}, 2, 1)-
DATEVALUE(TODAY())

Rather than #Tom-Sharpe edit for calculating the end of quarter date - in ColC you could just add 3 months and subtract 1 day.
=edate(A2,3)-1

Related

CDO - Resample netcdf files from monthly to daily timesteps

I have a netcdf file that has monthly global data from 1991 to 2000 (10 years).
Using CDO, how can I modify the netcdf from monthly to daily timesteps by repeating the monthly values each day of each month?
for eaxample,
convert from
Month 1, value = 0.25
to
Day 1, value = 0.25
Day 2, value = 0.25
Day 3, value = 0.25
....
Day 31, value = 0.25
convert from
Month 2, value = 0.87
to
Day 1, value = 0.87
Day 2, value = 0.87
Day 3, value = 0.87
....
Day 28, value = 0.87
Thanks
##############
Update
my monthly netcdf has the monthly values not on the first day of each month, but in sparse order. e.g. on the 15th, 7th, 9th, etc.. however one value for each month.
The question is perhaps ambiguously worded. Adrian Tompkins' answer is correct for interpolation. However, you are actually asking to set the value for each day of the month to that for the first day of the month. You could do this by adding a second CDO call as follows:
cdo -inttime,1991-01-01,00:00:00,1day in.nc temp.nc
cdo -monadd -gtc,100000000000000000 temp.nc in.nc out.nc
Just set the value after gtc to something much higher than anything in your data.
You can use inttime which interpolates in time at the interval required, but this is not exactly what you asked for as it doesn't repeat the monthly values and your series will be smoothed by the interpolation.
If we assume your dataset starts on the 1st January at time 00:00 (you don't state in the question) then the command would be
cdo inttime,1991-01-01,00:00:00,1day in.nc out.nc
This performs a simple linear interpolation between steps.
Note: This is fine for fields like temperature and seems to be want you ask for, but readers should note that one has to be more careful with flux fields such as rainfall, where one might want to scale and/or change the units appropriately.
I could not find a solution with CDO but I solved the issue with R, as follows:
library(dplyr)
library(ncdf4)
library(reshape2)
## Read ncfile
ncpath="~/my/path/"
ncname="my_monthly_ncfile"
ncfname=paste(ncpath, ncname, ".nc", sep="")
ncin=nc_open(ncfname)
var=ncvar_get(ncin, "nc_var")
## melt ncfile
var=melt(var)
var=var[complete.cases(var), ] ## remove any NA
## split ncfile by gridpoint (lat and lon) into a list
var=split(var, list(var$lat, var$lon))
var=var[lapply(var,nrow)>0] ## remove any empty list element
## create new list and replicate, for each gridpoint, each monthly value n=30 times
var_rep=list()
for (i in 1:length(var)) {
var_rep[[i]]=data.frame(value=rep(var[[i]]$value, each=30))
}

Clingo: logic OR in integrity constraint

For a lecture exercise, I have to represent in Answer Set Programming (we use Clingo as interpreter) a the following integrity constraint:
"You have to plan the calendar of a Masterclass. Normally, the lectures are on Fridays (8 hours) and Saturday(4 or 5 hours). And the 7th and 16th week are full, which means the lectures goes from Monday to Friday, with 8 hours per day, and on Saturday, with 4 or 5 hours of lecture."
The basic settings for the problem are the following:
#const n_weeks = 2. % for now we limit the problem size to 2 weeks
#const n_days = 6. % days in a fullweek
week(1..n_weeks).
day(1..n_days).
hour(1..8). % from the 1st to the 8th hour of the day
% the second week is a fullweek (lectures from 1st to 8th hour from Monday to Friday)
fullweek(2).
% We number all the weekdays (mon-fri) (we need it for the saturday)
fullday(1..5).
% some professors just for test
prof("prof1").
prof("prof2").
prof("prof3").
prof("prof4").
% subj, total hours, prof
subject("subj1", 8, "prof1").
subject("subj2", 14, "prof2").
subject("subj3", 24, "prof3").
subject("subj4", 11, "prof1").
% The main predicate, to print out at the end.
0 {calendar(W, D, H, W*100+D*10+H, lecture(S, P))} 1 :- week(W), day(D), hour(H), subject(S, _, P).
Now, as mentioned above (the final line in bold), we have some problems with the following constraint:
"In this masterclass the hours of a lecture on Saturday can be 4 or 5."
For now, me and my colleagues represented this constraint like this:
% The Saturday has 4 or 5 hours of lecture
:- #count{I : calendar(W, D, _, I, lecture(_, _))} > 5, week(W), day(D), not fullday(D).
:- #count{I : calendar(W, D, _, I, lecture(_, _))} < 4, week(W), day(D), not fullday(D).
Is it the right way to represent constraint like this? There is a better approach?
I do not believe there is the "right way" to represent the constraint as long as it is technically correct. I suggest to consider the following points:
The way on how to express Saturday is complicated, i.e. you can replace the variable D by 6 and eliminate the predicates day and fullday.
I do not understand why you use "lecture(_, _)" instead of the underscore.
I am not sure why you use the variable I for counting and think you like to count the hours instead.
Maybe it make sense to use disjunction explicitly, i.e. use a predicate like "hours_on_sunday(H)" and write a rule that H must be 4 or 5.

How to get the first business day in a new month after the weekend?

How can I in a smart way get the first business day of a month after the weekend?
To get the first business day of the month (given dateInput), we can do:
firstBusdayMonth = fbusdate(year(dateInput),month(dateInput));
As an example, for November, using the above function will return Thursday November 1 as the first business day. However, the first business day of the month after the first weekend is Monday November 5. How can I get this latter date?
Notes:
The weekend does not have to be in the same month.
If the Monday is not a working day, then I would like it to return the next business day
This function will do the trick. Here is the logic:
Create a datetime array for all days in the given month.
Get the day numbers.
Create a logical array, true from the first Monday onwards (so after the first weekend, accounting for the last day of the previous month being a Sunday).
Create another logical array using isbusday to exclude Mondays which aren't working days.
Finding the first day number where these two logical arrays are true, therefore the first business day after the weekend.
Code:
function d = fbusdateAferWE( y, m )
% Inputs: y = year, m = month
% Outputs: day of the month, first business day after weekend
% Create array of days for the given month
dates = datetime( y, m, 1 ):days(1):datetime( y, m, eomday( y, m ) );
% Get the weekday numbers to find first Monday, 1 = Sunday
dayNum = weekday( dates );
% Create the logical array to determine days from first Monday
afterFirstWeekend = ( cumsum(dayNum==2) > 0 ).';
% Get first day which is afterFirstWeekend and a business day.
d = find( afterFirstWeekend & isbusday( dates ), 1 );
end
You could probably speed this up (although it will be pretty rapid already) by not looking at the whole month, but say just 2 weeks. I used eomday to get the last day of the month, which means I don't have to make assumptions about a low number of holiday days in the first week or anything.
Edit: Working with datenum speeds it up by half (C/O JohnAndrews):
function d = fbusdateAferWE( y, m )
% Inputs: y = year, m = month
% Outputs: day of the month, first business day after weekend
% Create array of days for (first 2 weeks of) the given month
dates = datenum(datetime(y,m,1)):datenum(datetime(y,m,eomday(y,m)))-14;
% Get the weekday numbers to find first Monday, 1 = Sunday
dayNum = weekday( dates );
% Create the logical array to determine days from first Monday
afterFirstWeekend = ( cumsum(dayNum==2) > 0 ).';
% Get first day which is afterFirstWeekend and a business day.
d = find( afterFirstWeekend & isbusday( dates ), 1 );
end
I would add something like this after your statement:
[DayNumber, DayName] = weekday(firstBusdayMonth);
if DayNumber > 2
day = 10 - DayNumber;
else
This works because 'weekday' will return a number between 1 (Sunday) and 7 (Saturday).
The fbusdate() function will never return a 1 or 7, so we can ignore those cases.
If weekday(fbusdate()) == 2, the first is on a Monday and the firstBusdayMonth variable doesn't need to be changed.
If weekday(firstBusdayMonth) returns between 2 and 6, we need to skip to the next week, so we subtract the weekday value from 10 to find the next Monday.
It might not be the most elegant solution, but should work.

Dates from the last month of specific ranges

How can I extract data from the previous month into three sections? I can use the function LASTMONTH but that gives me the whole month.
I need it split into three sections:
1st - 10th of last month
11th - 20th of last month
21st to end of last month
Sounds like a two step problem:
Write a formula which comes up with 3 values based on date
Group and Sort your data based on that formula
The formula in question will look something like the following:
IF {yourDate} in date(year(currentdate),month(currentdate)-1, 1) to date(year(currentdate),month(currentdate)-1, 10)
THEN "A"
ELSE IF {yourDate} in date(year(currentdate),month(currentdate)-1, 11) to date(year(currentdate),month(currentdate)-1, 20)
THEN "B"
ELSE IF {yourDate} in date(year(currentdate),month(currentdate)-1, 21) to date(year(currentdate),month(currentdate),1)-1
THEN "C"
ELSE "D"
Where A, B, and C are valid dates and D is all the invalid ones. Substitute as appropriate.

How to handle with date range in mathematica?

In google trends there is possibility to export data as CSV. Obtained CSV has the following structure:
Week,subject 1, subject 2
2004-01-04 - 2004-01-10,13,6
2004-01-11 - 2004-01-17,9,9
2004-01-18 - 2004-01-24,11,4
I know that there is DateObject[], but it contain only one date. I want to obtain stepped chart of subjects 1 and 2 in time domain, and calculate correlation of them in range between two given dates.
My problem is: how structure of data, should I use to represent time range?
As google trends calls the time variable "week" take
StringTake["2004-01-04 - 2004-01-10", 10]
to get the first day of the range, then use
DateList[{"2004-01-04", {"Year", "Month", "Day"}}]
to create a date list and
DateString[{2004, 1, 4, 0, 0, 0}, {"Week"}]
to express the time in terms of the calendar week of the year. So, the function
RangeToWeek[timerangestring_] := DateString[ DateList[{
StringTake[timerangestring, 10],
{"Year", "Month", "Day"}}], {"Week"}]
gives for the firs date in your list 01, because the time span from 04.01.2004 to 10.01.2004 corresponds to the first callendar week of that year.