Vectorising Date Array Calculations - matlab

I simply want to generate a series of dates 1 year apart from today.
I tried this
CurveLength=30;
t=zeros(CurveLength);
t(1)=datestr(today);
x=2:CurveLength-1;
t=addtodate(t(1),x,'year');
I am getting two errors so far?
??? In an assignment A(I) = B, the number of elements in B and
Which I am guessing is related to the fact that the date is a string, but when I modified the string to be the same length as the date dd-mmm-yyyy i.e. 11 letters I still get the same error.
Lsstly I get the error
??? Error using ==> addtodate at 45
Quantity must be a numeric scalar.
Which seems to suggest that the function can't be vectorised? If this is true is there anyway to tell in advance which functions can be vectorised and which can not?

To add n years to a date x, you do this:
y = addtodate(x, n, 'year');
However, addtodate requires the following:
x must be a scalar number, not a string.
n must be a scalar number, not a vector.
Hence the errors you get.
I suggest you use a loop to do this:
CurveLength = 30;
t = zeros(CurveLength, 1);
t(1) = today; % # Whatever today equals to...
for ii = 2:CurveLength
t(ii) = addtodate(t(1), ii - 1, 'year');
end
Now that you have all your date values, you can convert it to strings with:
datestr(t);
And here's a neat one-liner using arrayfun;
datestr(arrayfun(#(n)addtodate(today, n, 'year'), 0:CurveLength))

If you're sequence has a constant known start, you can use datenum in the following way:
t = datenum( startYear:endYear, 1, 1)
This works fine also with months, days, hours etc. as long as the sequence doesn't run into negative numbers (like 1:-1:-10). Then months and days behave in a non-standard way.

Here a solution without a loop (possibly faster):
CurveLength=30;
t=datevec(repmat(now(),CurveLength,1));
x=[0:CurveLength-1]';
t(:,1)=t(:,1)+x;
t=datestr(t)
datevec splits the date into six columns [year, month, day, hour, min, sec]. So if you want to change e.g. the year you can just add or subtract from it.
If you want to change the month just add to t(:,2). You can even add numbers > 12 to the month and it will increase the year and month correctly if you transfer it back to a datenum or datestr.

Related

How to display datetime() value up to milliseconds

I have two questions:
In the following MATLAB code x is a date time value of the format "datetime(Y,M,D,H,MI,S,MS)". The display(x) command displays '00:00:00'. However the 'if condition' displays 'Well received!' which means the real value of x is greater than 0 as opposed to '00:00:00' displayed by the display(x) command. Please suggest how I could display the full value of x up to milliseconds or microseconds.
How can I save '0000,00,00,00,00,00,200' as a date time value?
send = datetime(2016,08,31,06,01,00,00);
receive=datetime(2016,08,31,06,01,00,100);
x=receive-send;
display(x);
if (x>0)
disp('Well received!')
else
disp('Late!')
end
The solution of your first question is, that you might convert your datetime-variable to a formatted string:
disp(datestr(x,'HH:MM:SS:FFF'));
This gives you the output 00:00:00:100, because F is the symbolic identifier for milliseconds.
Furthermore it seems, datetime doesn't support milliseconds. In this case you should use the MATLAB serial date number:
http://de.mathworks.com/help/matlab/ref/datenum.html
The variable x created in your example is a duration object. You can specify the display of milliseconds (as well as smaller decimal fractions of seconds) by setting the Format property.
>> x.Format = 'hh:mm:ss.SSS';
>> display(x);
x = 00:00:00.100
This is presumably also what you want when you ask about saving '0000,00,00,00,00,00,200' as a date time value. It's not really a date and time but a duration, and can be created using the duration constructor.
>> duration(00,00,00,200,'Format','hh:mm:ss.SSS')
ans =
00:00:00.200
Most operations acting on these duration objects will work as expected, such as comparison with the > operator:
>> x > duration(00,00,00,200)
ans =
0

split a double into parts - matlab

I have a date vector in form
20140117
20130325
20130530
etc.
There are 5,000,000 lines in the double vector.
How can I transfer it to a datevector recognized by matlab?
I don't like changing it to string and putting the parts in separately. It takes too long!
Please Help!
a combination of fix and mod let's you extract the digits you want:
%Matrix Columns YY,MM,DD,hh,mm,ss
[mod(fix(x/10000),100000),mod(fix(x/100),100),mod(x,100),zeros(size(x,1),3)]
%datenum
datenum(mod(fix(x/10000),10000),mod(fix(x/100),100),mod(x,100))
If you really want to avoid casting to string then back to number then you can use this method:
D = [20140117; 20130325; 20130530];
YY = fix( D./10000 ) ;
MM = fix( (D-YY.*10000) /100 ) ;
DD = fix( (D-YY.*10000-MM.*100 ) );
DateInMatlabformat = datenum( YY , MM , DD ) ;
You can package that in a one liner if you want, but basically what it does is:
Divide by 10000 to get the year in the variable YY
Remove this part from your original date ((D-YY.*10000)), then divide by 100 to get the month.
remove all of that, you obtain the day.
The last line merge all of that in a Matlab standard time serial format. Read the doc on datenum and datestr for more information.

subtracting one from another in matlab

My time comes back from a database query as following:
kdbstrbegtime =
09:15:00
kdbstrendtime =
15:00:00
or rather this is what it looks like in the command window.
I want to create a matrix with the number of rows equal to the number of seconds between the two timestamps. Are there time funcitons that make this easily possible?
Use datenum to convert both timestamps into serial numbers, and then subtract them to get the amount of seconds:
secs = fix((datenum(kdbstrendtime) - datenum(kdbstrbegtime)) * 86400)
Since the serial number is measured in days, the result should be multiplied by 86400 ( the number of seconds in one day). Then you can create a matrix with the number of rows equal to secs, e.g:
A = zeros(secs, 1)
I chose the number of columns to be 1, but this can be modified, of course.
First you have to convert kdbstrendtime and kdbstrbegtime to char by datestr command, then:
time = datenum(kdbstrendtime )-datenum(kdbstrbegtime )
t = datestr(time,'HH:MM:SS')

Convert numerous date and time values into serial number

I need to convert date and time into a numerical value. for example:
>> num = datenum('2011-05-07 11:52:23')
num =
7.3463e+05
How would I write a script to do this for numerous values without inputting the date and time manually?
You can store your date strings first in a cell array (or a matrix, provided they are of fixed format), and feed it straight to datenum. For example:
C = {'2011-05-07 11:52:23'
'2011-03-01 20:30:01'};
vals = datenum(C)

find mean or median date of event

I have a dataset for which I have extracted the date at which an event occurred. The date is in the format of MMDDYY although MatLab does not show leading zeros so often it's MDDYY.
Is there a method to find the mean or median (I could use either) date? median works fine when there is an odd number of days but for even numbers I believe it is averaging the two middle ones which doesn't produce sensible values. I've been trying to convert the dates to a MatLab format with regexp and put it back together but I haven't gotten it to work. Thanks
dates=[32381 41081 40581 32381 32981 41081 40981 40581];
You can use datenum to convert dates to a serial date number (1 at 01/01/0000, 2 at 02/01/0000, 367 at 01/01/0001, etc.):
strDate='27112011';
numDate = datenum(strDate,'ddmmyyyy')
Any arithmetic operation can then be performed on these date numbers, like taking a mean or median:
mean(numDates)
median(numDates)
The only problem here, is that you don't have your dates in a string type, but as numbers. Luckily datenum also accepts numeric input, but you'll have to give the day, month and year separated in a vector:
numDate = datenum([year month day])
or as rows in a matrix if you have multiple timestamps.
So for your specified example data:
dates=[32381 41081 40581 32381 32981 41081 40981 40581];
years = mod(dates,100);
dates = (dates-years)./100;
days = mod(dates,100);
months = (dates-days)./100;
years = years + 1900; % set the years to the 20th century
numDates = datenum([years(:) months(:) days(:)]);
fprintf('The mean date is %s\n', datestr(mean(numDates)));
fprintf('The median date is %s\n', datestr(median(numDates)));
In this example I converted the resulting mean and median back to a readable date format using datestr, which takes the serial date number as input.
Try this:
dates=[32381 41081 40581 32381 32981 41081 40981 40581];
d=zeros(1,length(dates));
for i=1:length(dates)
d(i)=datenum(num2str(dates(i)),'ddmmyy');
end
m=mean(d);
m_str=datestr(m,'dd.mm.yy')
I hope this info to be useful, regards
Store the dates as YYMMDD, rather than as MMDDYY. This has the useful side effect that the numeric order of the dates is also the chronological order.
Here is the pseudo-code for a function that you could write.
foreach date:
year = date % 100
date = (date - year) / 100
day = date % 100
date = (date - day) / 100
month = date
newdate = year * 100 * 100 + month * 100 + day
end for
Once you have the dates in YYMMDD format, then find the median (numerically), and this is also the median chronologically.
You see above how to present dates as numbers.
I will add no your issue of finding median of the list. The default matlab median function will average the two middle values when there are an even number of values.
But you can do it yourself! Try this:
dates; % is your array of dates in numeric form
sdates = sort(dates);
mediandate = sdates(round((length(sdates)+1)/2));