# Split a target date interval into seasons and find the percentile of days for each season

5 views (last 30 days)
DIMITRIS GEORGIADIS on 11 Jul 2021
Answered: Peter Perkins on 27 Jul 2021
I have the following seasons:
• Spring: {01-March , 31-May}
• Summer: {01-June, 31-August}
• Autumn: {01-Sep, 30-Nov}
• Winter: {01-Dec, 28-Feb}
and I also have as a data a reference period, e.g. 01-Jan until 15-Sep (254 days).
What I want is to compute what is the percentile of the days of reference period that belong to each season.
For example, in the present case, we have:
• Winter: 01-Jan until 28-Feb --> 59 days / 254 days = 23.5%
• Spring: 01-Mar until 31-May --> 90 days / 254 days = 35%
• Summer: 01-Jun until 31-Aug --> 90 days / 254 days = 35%
• Autumn: 01-Sep until 15-Sep --> 15 days /254 days = 6.5%
So the requested values would be {23.5, 35, 35, 6.5}.

Scott MacKenzie on 11 Jul 2021
There might be a way to shorten this, but I think it achieves what you are after. You didn't mention the year, so I set this up as a variable (change, as necessary). This script accommodates leap years. BTW, the number of reference days below is 259. Not sure why this differs from your count of 254.
yr = 2020; % change, as necessary
% reference days of interest
r1= datetime(yr,1,1):datetime(yr,2,eomday(yr,2));
r2= datetime(yr,3,1):datetime(yr,5,31);
r3= datetime(yr,6,1):datetime(yr,8,31);
r4= datetime(yr,9,1):datetime(yr,9,15);
n = length([r1 r2 r3 r4]) % number of reference days
n = 259
percentDays = [length(r1), length(r2), length(r3), length(r4)] /n * 100
percentDays = 1×4
23.1660 35.5212 35.5212 5.7915
DIMITRIS GEORGIADIS on 11 Jul 2021
Thank you again @Scott MacKenzie. I did generalize it.

Seth Furman on 14 Jul 2021
To add to Scott's answer, this kind of grouped calculation on timestamped data lends itself well to timetable and groupsummary.
isWinter = @(dt) dt.Month == 12 | dt.Month <= 2;
isSpring = @(dt) 3 <= dt.Month & dt.Month <= 5;
isSummer = @(dt) 6 <= dt.Month & dt.Month <= 8;
isAutumn = @(dt) 9 <= dt.Month & dt.Month <= 11;
referencePeriod = timetable('RowTimes',datetime(2020,1,1):caldays(1):datetime(2020,9,15));
referencePeriod.Season(isWinter(referencePeriod.Time)) = categorical("Winter");
referencePeriod.Season(isSpring(referencePeriod.Time)) = categorical("Spring");
referencePeriod.Season(isSummer(referencePeriod.Time)) = categorical("Summer");
referencePeriod.Season(isAutumn(referencePeriod.Time)) = categorical("Autumn");
counts = groupsummary(referencePeriod,"Season")
counts = 4×2 table
Season GroupCount ______ __________ Winter 60 Spring 92 Summer 92 Autumn 15
counts.Percentages = counts.GroupCount ./ sum(counts.GroupCount)
counts = 4×3 table
Season GroupCount Percentages ______ __________ ___________ Winter 60 0.23166 Spring 92 0.35521 Summer 92 0.35521 Autumn 15 0.057915
DIMITRIS GEORGIADIS on 16 Jul 2021
Dear @Seth Furman thank you very much for your very interesting and elegant answer!

Peter Perkins on 27 Jul 2021
Another possibility:
>> yr = 2020;
>> edges = datetime(yr,[1 3 6 9 12,12],[1 1 1 1 1 32])
edges =
1×6 datetime array
01-Jan-2020 01-Mar-2020 01-Jun-2020 01-Sep-2020 01-Dec-2020 01-Jan-2021
>> t = datetime(yr,1,1:259)';
>> tf = isbetween(t,edges(1:end-1),edges(2:end),'openright'); % uses implicit expansion
>> tf(:,1) = tf(:,1) + tf(:,end);
>> tf(:,end) = [];
>> 100*sum(tf,1)/length(t)
ans =
23.166 35.521 35.521 5.7915