Loss of precision with netcdf time when using datenum
    5 views (last 30 days)
  
       Show older comments
    
Hi there,
I am trying to read the time variable in from an netcdf file and convert it to datenum values but the end time always seems to fall short (26-11-2005 instead of 01-01-2006).
The time variable from the netcdf file is in 'days since 1860-01-01 00:00:00' and in '365_day' format but I am having trouble getting the proper datenum for the data. The time format is also 'double' precision so I am not sure why I am going wrong when I use the following for example:
time1980_05 = timestamp1980_05' + datenum('1860-01-01 00:00:00');
Any ideas?
1 Comment
  Campion Loong
    
 on 4 Feb 2016
				Hi Mashtine,
It is a little difficult to know what's going on without some sample input and codes from your attempt. In general though, the datetime type (available for R2014b and up) is preferred to datenum - for one it has much better precision. You may want to give it a try.
Accepted Answer
  Kelly Kearney
      
 on 4 Feb 2016
        
      Edited: Kelly Kearney
      
 on 4 Feb 2016
  
      I wrote a function, daynoleap2datenum, that does the conversion that Peter suggested (in a slightly simpler manner... I just figure out which years need a leap day and bump the numbers up one at those locations). It converts the output to either datenumbers or datetime objects, so it can work regardless of Matlab version.
As you can see in this example, the missing leap days are what lead to your simple addition method coming up a bit short:
t = [0 58:60 364]';
t1 = datetime(2000,1,1) + t
t2 = daynoleap2datenum(t, 2000, 'dt')
t1 = 
     01-Jan-2000 00:00:00
     28-Feb-2000 00:00:00
     29-Feb-2000 00:00:00
     01-Mar-2000 00:00:00
     30-Dec-2000 00:00:00
t2 = 
     01-Jan-2000 00:00:00
     28-Feb-2000 00:00:00
     01-Mar-2000 00:00:00
     02-Mar-2000 00:00:00
     31-Dec-2000 00:00:00
0 Comments
More Answers (1)
  Peter Perkins
    
 on 4 Feb 2016
        Mashtine, I'm not super familiar with netCDF, but "365 day format" and this
>> dt = between(datetime(2005,11,26),datetime(2006,1,1),'days')
dt = 
   36d
>> (2006-1860)/4
ans =
         36.5
suggests that this is a leap day issue. I imagine you could solve this using datetime, if you have R2014b or later. This might be something like what you are looking for:
>> y = [datetime(1860,1,0) datetime(1860,2,28) + calyears(0:5)]
y = 
Columns 1 through 6
   31-Dec-1859   28-Feb-1860   28-Feb-1861   28-Feb-1862   28-Feb-1863   28-Feb-1864
Column 7
   28-Feb-1865
>> % how many days from Feb 28 in year(i) to Feb 28 in year(i+1)
>> d = caldiff(y,'days')
d = 
    59d   366d   365d   365d   365d   366d
>> d = caldays(d)
d =
    59   366   365   365   365   366
>> % which years have leap days?
>> hasLeapDay = (d == 366)
hasLeapDay =
     0     1     0     0     0     1
>> adjust = cumsum(hasLeapDay)
adjust =
     0     1     1     1     1     2
>> breakPoints = [1 cumsum(d)+1]
breakPoints =
           1          60         426         791        1156        1521        1887
% try it out on some "365 day" dates
>> netcdfDay = [(58:61) (58:61)+365 (58:61)+2*365  (58:61)+3*365]
netcdfDay =
  Columns 1 through 7
          58          59          60          61         423         424         425
  Columns 8 through 14
         426         788         789         790         791        1153        1154
  Columns 15 through 16
        1155        1156
>> realDay = netcdfDay + discretize(netcdfDay,breakPoints,adjust)
>> realDay =
  Columns 1 through 7
          58          59          61          62         424         425         426
  Columns 8 through 14
         427         789         790         791         792        1154        1155
  Columns 15 through 16
        1156        1157
>> datestr(realDay + datenum([1860,1,0]))
ans =
27-Feb-1860
28-Feb-1860
01-Mar-1860
02-Mar-1860
27-Feb-1861
28-Feb-1861
01-Mar-1861
02-Mar-1861
27-Feb-1862
28-Feb-1862
01-Mar-1862
02-Mar-1862
27-Feb-1863
28-Feb-1863
01-Mar-1863
02-Mar-1863
5 Comments
  Kelly Kearney
      
 on 16 Feb 2016
				The datetime object and associated functions were introduced in R2014b, so if you're running an older version, you won't be able to use Peter's code. But I really suggest giving my daynoleap2datenum function a try... it's pretty simple, version independent, and accounts for the 365-day calendar:
S = load('sampledata.mat');
dn = daynoleap2datenum(S.timestamp1980_05, 1860);
datestr(dn([1 end]))
ans =
01-Jan-1980 03:00:00
01-Jan-2006 00:00:00
See Also
Categories
				Find more on Dates and Time in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


