Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert Matlab Datenum to Datetime

-I wish to convert Matlab serial time (datenum, as in t_matlab=now)
to c# Datetime (as in var t_cs = DateTime.Now.Ticks).

Any idea how to do so?

[Edit] I found a way of doing it, but still not sure if it's the best way.
[Edit2] Fixed the wrong DateTimes, thanks Jonas!

function cstime = datenum2datetime( matlabSerialTime )
%Convert matlab serial time (datenum) to .net datenum.
%
%   Example:
%   ntTime = datenum2datetime(now)
%   cstime = datenum2datetime([734539.4717013890 734539.5051388888]);
%
%   See also datenum.

%   using System.DateTime.Parse(string).Ticks to convert to DateTime format.
%   t1 = now; t2 = now+1; matlab_times = [t1 t2];
%   cs_times = [System.DateTime.Parse(datestr(t1)).Ticks ...
%            System.DateTime.Parse(datestr(t2)).Ticks]
%   aver = diff(cs_times)/diff(matlab_times);
%   offver = cs_times(1) - matlab_times(1)*aver;

a = 10^7*60*60*24;
offset = -367*10^7*60*60*24;
cstime = a*matlabSerialTime + offset;
like image 982
shahar_m Avatar asked May 02 '11 08:05

shahar_m


2 Answers

Edit: Surprised by jarr's answer I investigated further. Turns out that the example time points sharhar_m gives in the question are wrong (sorry for not checking that earlier).

In summary, the function given in the question is off by 367-281=86 days and should be corrected to

function cstime = datenum2datetime( matlabSerialTime )
cstime = 10^7*60*60*24*(matlabSerialTime - 367);

Now on to the details, in case anyone is interested: You claim

% {05-Feb-2011 11:19:15} in System.DateTime is 634399319550000000

but in MATLAB R2010b

sdt =System.DateTime(634399319550000000); 
[sdt.Day sdt.Month]

returns [2 5], so your DateTime value is actually for May 2nd, not Feb 5th!! To calculate the correct values set

cs_times = [System.DateTime.Parse('05-Feb-2011 11:19:15').Ticks ...
            System.DateTime.Parse('05-Feb-2011 12:07:24').Ticks]

which gives [634325015550000000 634325044440000000].

Time unit scaling

Your factor a is 10^7*60*60*24 i.e. MATLAB stores the date/time in units "days" (with time as fractional days) and C# stores time as "ticks", i.e. number of "10^-7 seconds". You can probably avoid some rounding errors by putting in the precise value for a.

Difference in reference time point

The offset b expressed in days (b/a) tells you that their "origin of time" is 367 days apart; with your old value for b this came out to 281 days. The MATLAB documentation for datestr states

"A serial date number represents the whole and fractional number of days from 1-Jan-0000 to a specific date. The year 0000 is merely a reference point and is not intended to be interpreted as a real year in time."

(even though running datestr(0,'dd-mm-yyyy HH-MM-SS') reveals that the reference point is actually 0-Jan-0000). C# ticks are the

"number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001, which represents DateTime.MinValue. It does not include the number of ticks that are attributable to leap seconds."

So in summary, the "origin in time" between both systems differs by one leap year and one day, hence 367 days. If you actually wanted to deal with real dates that far back, you would have to take the Gregorian calendar reform and Augustus' correction to the incorrect application of leap years in the Julian calendar before the year 8 into account... but I doubt this is of interest here ;-).

like image 108
Jonas Heidelberg Avatar answered Sep 22 '22 00:09

Jonas Heidelberg


Use this to convert matlab serial date number to System.DateTime ticks:

function datetimeticks = mt2dt(matlabserialtime) 
    datetimeticks = (matlabserialtime - 367)*86400/1e-7;  
end

And an example (in Matlab):

mdt = datenum('8/6/1901 07:50:13');  
sdt = System.DateTime(mt2dt(mdt));

>> sdt.ToString

ans = 

8/6/1901 07:50:13

The counterpart conversion from System.DateTime to Matlab serial date number is just as easy:

function matlabserialtime = dt2mt(datetimeticks)
    matlabserialtime = double(datetimeticks) * 1e-7/86400 + 367;
end

And an example (in Matlab):

sdt = System.DateTime.Parse('8/6/1901 07:50:13');
mdt = datenum(dt2mt(sdt.Ticks));

>> datestr(mdt)

ans =

06-Aug-1901 07:50:13

Note, that you lose DateTimeKind info once converted to Matlab from DateTime ticks.
You may want to hold on to that and later use it with SpecifyKind or DateTime ctor.

like image 45
jbarr Avatar answered Sep 19 '22 00:09

jbarr