How to identify date numbers corresponding to non-business days and replace them with by the next available business day in MATLAB - matlab

I am working with time series data in MATLAB. I have got two vectors of date numbers, one of which relies on a somewhat subjective data source. If both vectors were perfectly accurate, all date numbers should correspond to trading days while one vector would be a 'proper subset' of the other. Unfortunately this is not the case because one of the vectors contains several date numbers which correspond to non-business days. I would like to find a way to replace all non-business days in this vector with the next available business day.
Example:
datenumbers = [736062;736063;736064;736065;736066;736067]
% corresponds to [wed, thu, fri, sat, sun, mon]
This contains [736065;736066] which corresponds to the upcoming weekend. Because these are not working days I would like to identify the date number corresponding to the subsequent monday and change both entries so that:
datenumbers = [736062;736063;736064;736067;736067;736067]
% corresponds to [wed, thu, fri, mon, mon, mon]

One way to do it is simply to loop through all your values and change them if they are Saturday or Sunday.
datenumbers = [736062;736063;736064;736065;736066;736067];
for i = 1:length(datenumbers)
weekDay = mod(datenumbers(i),7);
if weekDay == 1 || weekDay == 2
datenumbers(i) = (3-weekDay) + datenumbers(i);
end
end

Related

UTC to GPS time for finding TOW in Simulink

for my project, I need to calculate TOW (Time of week) in Simulink. I know this can be achieved through conversion of UTC time to GPS time.
I have written a simple m-file in Matlab which does the action for me in Matlab as follow:
date_gps_int = 10000*y + 100*m + d
date_gps_str = int2str(date_gps_int)
date_gps_str_to_serial = datenum(date_gps_str,'yyyymmdd')
date_str_format = datestr(date_gps_str_to_serial,'dd-mmmm-yyyy')
Num_Days = daysact('06-jan-1980',date_str_format)
Num_Weeks = Num_Days/7
TOW = Num_Weeks - 1024
My first intention was to use this as a function in simulink. But apparently because of 'datenum' and 'datestr' it is not possible, since simulink does not handle strings.
Now I am wondering if anyone can help me with this issue. Is there any way to calculate TOW from the UTC date in Matlab without using those predefined functions?
I also tried to write an algorithm for calculating number of days since '6 January 1980' and then calculating number of weeks by dividing that by 7. But since I am not very familiar with leap year calculation and I don't really know the formula for these kinds of calculations, my result differs from real TOW.
I would appreciate if anybody can help me on this.
There are three formats handled by Matlab for time: formatted date strings - what datestr outputs -, serial date - scalar double, what datenum outputs - and date vectors (see datevec). Conversion functions work with these three, and the most convenient way to convert individual variables (year, month, etc) to a date is to build a date vector [yyyy mm dd HH MM SS].
date_gps_str_to_serial = datenum([y m d 0 0 0]); % midnight on day y-m-d
date_Jan_6_1980 = datenum([1980 01 06 0 0 0]); % midnight on Jan 6th, 1980
Num_Days = date_gps_str_to_serial - date_Jan_6_1980;
Now, beware of leap seconds...
GPS time is computed form the time elapsed since Jan 6th 1980. Take the number of seconds elapsed since that day, as measured by the satellites' atomic clocks, divide by (24*3600) to get a number of days, the remainder is the time of the day (in seconds since midnight).
But, once in a while, the International Earth Rotation and Reference Systems Service will decide that a day will last one second longer to accommodate for the slowing of Earth rotation. It may happen twice a year, on June 30th or December 31st. The calculation of GPS time is wrong, because it does not take into account that some days last 86401 seconds (so dividing by 24*3600 does not work) and will advance by 1 second with respect to UTC each time this happens. There has been 18 such days since Jan 6th 1980, so one should subtract 18 seconds from GPS time to find UTC time. The next time a leap second may be added is June 2019.

How to calculate averages for a 3D matrix for the same day of data over multiple years in Matlab?

I am interested in calculating GPH anomalies in Matlab. I have a 3D matrix of lat, lon, and data. Where the data (3rd dimension) is a daily GPH value spaced in one-day increments for 32 years (from Jan. 1st 1979 to Jan. 1st 2011). The matrix is 95x38x11689. How do I compute a daily average across all years for each day of data, when the matrix is 3D?
In other words, how do I compute the average of Jan. 1st dates for all years to compute the climatological mean of all Jan. 1st's from 1979-2010 (where I don't have time information, but a GPH value for each day)? And so forth for each day after. The data also includes leap years. How do I handle that?
Example: Sort, and average all Jan. 1st GPH values for indices 1, 365, 730, etc. And for each day of all years after that in the same manner.
First let's take out all the Feb 29th, because these days are in the middle of the data and not appear in every year, and will bother the averaging:
Feb29=60+365*[1:4:32];
mean_Feb29=mean(GPH(:,:,Feb29),3); % A matrix of 95x38 with the mean of all February 29th
GPH(:,:,Feb29)=[]; % omit Feb 29th from the data
Last_Jan_1=GPH(:,:,end); % for Jan 1st you have additional data set, of year 2011
GPH(:,:,end)=[]; % omit Jan 1st 2011
re_GPH=reshape(GPH,95,38,365,[]);
av_GPH=mean(re_GPH,4);
Now re_GPH is a matrix of 95x38x365, where each slice in 3rd dimension is an average of a day in the year, starting Jan 1st, etc.
If you want the to include the last Jan 1st (Jen 1st 2011), run this line at after the previous code:
av_GPH(:,:,1)=mean(cat(3,av_GPH(:,:,1),Last_Jan_1),3);
For the ease of knowing which slice nubmer corresponds to each date, you can make an array of all the dates in the year:
t1 = datetime(2011,1,1,'format','MMMMd')
t2 = datetime(2011,12,31,'format','MMMMd')
t3=t1:t2;
Now, for example :
t3(156)=
datetime
June5
So av_GPH(:,:,156) is the average of June 5th.
For your comment, if you want to subtract each day from its average:
sub_GPH=GPH-repmat(av_GPH,1,1,32);
And for February 29th, you will need to do that BEFORE you erase them from the data (line 3 up there):
sub_GPH_Feb_29=GPH(:,:,Feb29)-repmat(mean_Feb29,1,1,8);

daily to monthly sum in matlab of multiple years

My data is excel column. In excel sheet one column contain last 50 years date (no missing date; dd/mm/yyyy format) and in other column everyday rainfall (last 50 years; no blank).
I want to calculate what is the sum of monthly rainfall for every month of last 50 years in Matlab. Remember, there four types of month ending date: 30, 31, 28 and 29. Upto now I am able read the dates and rainfall value from excel file like below
filename = 'rainfalldate.xlsx';
% Extracts the data from each column of textData
[~,DateString ]= xlsread(filename,'A:A')
formatIn = 'dd/mm/yyyy';
DateVector = datevec(DateString,formatIn)
rainfall = xlsread(filename,'C:C');
what is the next step so that I can see every months of last fifty years rainfall sum?
I mean suppose July/1986 rainfall sum... Any new solutions?Code or loop base in Matlab 2014a
As #Daniel suggested, you could use accumarray for this.
Since you want the monthly rainfall for multiple years, you could combine year and month into one single variable, ym.
It is possible then to identify if a value belongs to both a determined year and month at once, and "tag" it using histc function. Values with similar "tags" are summed by the accumarray function.
As a bonus, you do not have to worry about the number of days in a month. Take a look at this example:
% Variables initialization
y=[2014 2014 2015 2015 2015 2014 2014 2015 2015];
m=[1 1 1 2 2 3 3 3 3]; % jan, feb and march
values = 1:9;
% Identifyier creation and index generation
ym = y*100+m;
[~,subs]=histc(ym,unique(ym));
% Sum
total = accumarray(subs',values);
The total variable is the monthly rainfall already sorted by year and month (yyyymm).

datenum series to the end of February - Leap year or not

I want to create a list of dates that go until the end of February. However, since the end of February changes from 28 to 29 depending on whether there's a leap year, I'm having trouble with how to consider both options.
Here's what I have so far:
date = datenum(years(i),12,01):1:datenum(years(i)+1,02,29);
This case, when run on a year that is not a leap year, ends up counting March 1st instead of ending on Feb. 28th.
Here's a little hack I came up with. You can check whether a year is a leap year quite easily by calculating the number of days between February 28 and March 1, like so:
datenum(years(i), 3, 1) - datenum(years(i), 2, 28)
Checking whether it's larger than 1 would indicate leap year. This 1 or 0 logical MATLAB convention leads to the second part of the hack: this is exactly the number of days you need to add to Feb 28: 0 if not leap year, 1 if leap year. Here, therefore, is the full hack:
date = datenum(years(i),12,01):datenum(years(i)+1,02, ...
28 + ((datenum(years(i)+1,3,1) - datenum(years(i)+1,2,28))>1) );
UPDATE / IMPROVEMENT:
Answer already accepted, but I came up with an even better solution. I didn't realize that datenum simply counts days. In this case, we can simply say that the last day of February is the day before March 1. This yields the following drastic simplification:
date = datenum(years(i),12,01):1:(datenum(years(i)+1,3,1)-1);
Datenum, for good or ill, takes negative and zero numbers. So the last day of February can be written:
datenum(2015, 3, 0)
With a comment explaining this madness, of course.

Automating a holiday date for any year in Matlab

The code below gives a decimal day for one specific year.
HolidayArrayDate(2) = datenum(2012,01,16,00,00,00); %MartinLutherKingJrBirthday
I am trying to make the holiday more general for an input "dataYear" instead of specifying it as "2012". Martin Luther King Jr Birthday is the third Monday of ever year. When i provide it an input of any year 2010/2011/2012/2013/2014 through "dataYear", it should automatically choose the third Monday in January for me. How would i dot this?
Thank you!
Starting from the first day of the year, 21 days always suffice to find the third Monday. So: get serial date number for first day of the year (with datenum); get day-of-the-week for that and the following 20 days (datestr(..., 'd')); find the first three Mondays (find(...=='M', 3); and finally pick the third one and convert it into date string (datestr):
dataYear = 2012; %// input
f = datenum(dataYear,1,1); %// 1st day of year, in serial date number format
r = find(datestr(f+(0:20), 'd')=='M', 3); %// find three Mondays from that day on
result = datestr(f+r(3)-1); %// third Monday, in date string format