Convert decimal dates in loop

17 views (last 30 days)
C G
C G on 18 Jul 2018
Edited: Stephen23 on 14 Sep 2022
I need help with converting a decimal date to Day/Month/Year AND MATLAB serial date. (Yes this is the same question I asked in another post. That one diverged from the intended question and was not likely to get answered judging by the comments. I am asking in a simpler manner.)
What I need is a robust method that can take one input and give me two outputs.
Input - decimal date
Output 1 - Day/month/Year
Output 2 - MATLAB date code
Example: Input - 1998.95...(long string of values)
Output 1 - 16/Dec/1998
Output 2 - 730105
I can achieve a loop from Input to output 1, but not to output 2. I can get to output 2 with some fiddling. I need to import the data from loop 1 in to a separate variable, then run a separate loop. This method is not worthwhile as it means I will need to do extra steps and there it can lead to mistakes.
Again, what I need is a loop that works directly. Input to output 1 AND output 2.
I can get to input 2 individually, but not in a loop. With a long list of decimal dates (think well over 5000), it would help to have a single loop that can do it, but this apparently does not exist.
Here is what I have to get me from my input to a Day/Month/Year:
A = xlsread('Example.xlsx');
B = num2cell(A);
[fid,msg] = fopen(sprintf('Example3.txt'),'wt');
assert(fid>=0,msg)
for q = 1:5555
DecDate = B{q,5}; %This is the column with the decimal dates in it.
n = datestr(datenum(DecDate,1,0));
fprintf(fid,'%s\n', n);
%DateString = datestr(datenum(DecDate,1,0)); %This line is optional?
%formatIn = 'dd-mmm-yyyy HH:MM:SS';
%p = datenum(n,formatIn); %This is where the problem is.
%p = datenum(DateString,formatIn); %This line also caused problems.
%fprintf(fid,'%s', ' ');
%fprintf(fid,'%s', p);
end
fclose(fid);
  5 Comments
C G
C G on 19 Jul 2018
This is a similar question to another one I asked. I simplified the comments as most of them are not relevant or unhelpful.

Sign in to comment.

Answers (2)

C G
C G on 19 Jul 2018
This doesn't really answer my question, but it will get consistent values. Uses the function [doy,fraction] = date2doy(inputDate). It can be found here. date2doy function There are a lot of other functions that seem to go transcribe julian dates to date and back, but none that work with decimal dates.
[doy] = date2doy(datenum('1/25/2004'));
[doy] = date2doy(datenum(numeric array of values));
%From there, just add up the dates to create your own serial date, "number of days since..."
%This will convert your decimal dates to a long row of matlab serial dates.
A = [numeric array of values];
yr=fix(A);
secs=(A-yr).*(365+isleapyr(yr)).*24.*3600;
dn=fix(datenum(yr,1,0,0,0,secs)).'; %This line makes a single row, not a single column.
dn=fix(datenum(yr,1,0,0,0,secs)); % This makes one column.
%This converts the decimal dates to a date string (The values are not consistent. They like to jump around.).
n = datestr(datenum(numericarrayofvalues,1,0));
%Better to use the loop. This will have consistent values. They might be wrong, but they are consistent.
%And no need to import the values separately.
A = xlsread('Excelspreadsheet.xlsx');
B = num2cell(A);
[fid,msg] = fopen(sprintf('Example3.txt'),'wt');
assert(fid>=0,msg)
for q = 1:numberofrows
DecDate = B{q,5}; %The column the decimal dates are in
n = datestr(datenum(DecDate,1,0)); %Same as above, but the values are consistent. And sharable.
fprintf(fid,'%s\n', n);
end
fclose(fid);

Steven Lord
Steven Lord on 19 Jul 2018
I assume the integer part of x is the year, and the fractional part is the fraction of the way through that year representing the date and time you want? If so use datetime.
x = 1998.95918367347;
dt = datetime(floor(x), 1, 1) + years(x-floor(x))
[Y, M, D] = ymd(dt)
n = datenum(dt)
I think x corresponds to a time on December 17th not December 16th, since you'd want x = 1998 to correspond to midnight on January 1st not January 0th.
Unless you have a strong need to work with the serial date numbers, however, I'd strongly recommend working with the datetime array instead. There are many operations implemented for datetime that you'd have to create yourself if you work with the serial date numbers or that are more difficult to perform with the serial date numbers.
  1 Comment
Stephen23
Stephen23 on 14 Sep 2022
Edited: Stephen23 on 14 Sep 2022
Note that by using YEARS this approach incorrectly assumes that a year has exactly
format long G
365.2425 * 24 % hours
ans =
8765.82
whereas in fact the length of a calendar year is a) never equal to this value and b) depends on the year. The bug in this approach can be clearly demonstrated at the very end of a non-leap year, where this incorrect calculation returns a date in the following year (due to the flawed usage of YEARS):
x = 2021.9999999; % well within floating point precision
dt = datetime(floor(x), 1, 1) + years(x-floor(x)) % oops, we jumped into the future!
dt = datetime
01-Jan-2022 05:49:08
To get the correct year length for any specific year (required for that fraction), something like CALYEARS or DATESHIFT or two DATETIMES or similar would be required:
Z = datetime(floor(x),1,1);
Z = Z + mod(x,1).*((Z+calyears(1))-Z) % much better!
Z = datetime
31-Dec-2021 23:59:56
Y = datetime(floor(x)+[0;1],1,1);
Y = Y(1) + mod(x,1).*diff(Y) % this also works!
Y = datetime
31-Dec-2021 23:59:56
etc.etc.

Sign in to comment.

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!