How to use datetime with leap second strings?

61 views (last 30 days)
James Tursa
James Tursa on 16 Nov 2024 at 4:23
Answered: Shivam Gothi on 17 Nov 2024 at 8:58
Suppose we have the following date time string:
ds1 = "30-Jun-1972 23:59:59.5";
You can convert that to a datetime easily:
datetime(ds1)
ans = datetime
30-Jun-1972 23:59:59
But now suppose you have a string that is in the middle of a leap second:
ds2 = "30-Jun-1972 23:59:60.5";
MATLAB won't convert this:
try
datetime(ds2)
catch
disp('Error')
end
Error
So apparently the seconds value >= 60 is causing this. But what if I tell it to use leap seconds? Still doesn't work:
try
datetime(ds2,'TimeZone','UTCLeapSeconds')
catch
disp('Error')
end
Error
This is disappointing, and quite frankly inconsistent with other ways of creating a datetime within a leap second. E.g., this works fine:
datetime(1972,6,30,23,59,60.5,'TimeZone','UTCLeapSeconds')
ans = datetime
1972-06-30T23:59:60.500Z
So, is there a way to coax datetime( ) into reading a date time string in the middle of a leap second? And at the same time retain full precision of the string? I would like to avoid manually parsing this myself if possible, but currently see no other way. E.g., the precision loss issue with string input illustrated:
format longg
ds3 = "01-Jan-2024";
dt3 = "23:59:01.2345678912345";
d3 = datetime(ds3+" "+dt3)
d3 = datetime
01-Jan-2024 23:59:01
d3.Second
ans =
1.234567891
d3.Second == 1.2345678912345 % LOSES PRECISION!
ans = logical
0
d4 = datetime(ds3) + duration(dt3)
d4 = datetime
01-Jan-2024 23:59:01
d4.Second
ans =
1.23456789124012
d4.Second == 1.2345678912345 % LOSES PRECISION!
ans = logical
0
You can see the loss of precision datetime has when reading strings in general. The duration class has a similar issue. So even if datetime could handle seconds >= 60, there would be a precision loss issue. I would like to avoid that.
At the moment, the only solution I see is to manually parse out the seconds and then piece things together. E.g.,
dt3a = "23:59:00";
dt3b = "00:00:01.2345678912345";
d5 = datetime(ds3) + duration(dt3a) + duration(dt3b)
d5 = datetime
01-Jan-2024 23:59:01
d5.Second
ans =
1.2345678912345
d5.Second == 1.2345678912345
ans = logical
1
Even this approach has problems with duration in the middle of a leap second because it can't handle string seconds >=60 for some reason:
seconds(60.5) % this is OK
ans = duration
60.5 sec
duration("00:00:60.5") % but not this!
Error using duration (line 126)
Could not recognize the format of '00:00:60.5'.
Expected data of the form 'hh:mm:ss' or 'dd:hh:mm:ss'.
So to handle the leap second issue I would be forced to read the seconds manually instead of using duration. (Why???)
I am hoping for a simpler way.

Answers (1)

Shivam Gothi
Shivam Gothi on 17 Nov 2024 at 8:58
As per my understanding, you are trying to save leap-seconds in "datetime" object, in such a way that it does not looses precision. You want to pass the date-time string as an input argument to the "datetime" function.
I also faced similiar issue, but tried to resolve it by using the following work-around.
The documentation of "datetime" function (https://www.mathworks.com/help/matlab/ref/datetime.html#d126e365305) say that:
While passing character string as an input argument to the "datetime" function, we can specify the precision upto 9 decimal places by specifing an additional input argument "infmt", as demonstrated below:
DT_string= "2024-01-01T23:59:01.2345678912345Z"; %Same date and time as used in the above question
t = datetime(DT_string,'InputFormat','uuuu-MM-dd''T''HH:mm:ss.SSSSSSSSS''Z')
t = datetime
01-Jan-2024 23:59:01
format longg;
t.Second
ans =
1.234567891
This says that the maximum precision available is "9". Therefore, "1.2345678912345" is getting truncated to "1.234567891" in your case. Even if we do not explicitely specify the "inputFormat", it will automatically truncate to the maximum 9 digits after decimal.
Therefore, if you want to retain the precision, the below given command works perfectly.
t=datetime(1972,1,1,23,59,01.2345678912345,'TimeZone','UTCLeapSeconds') % same date and time entered manually
t = datetime
1972-01-01T23:59:01.234Z
t.Second %This is not truncated
ans =
1.2345678912345
In this case, instead of passing the date-time string, you have to manually enter the the values of year, months, days and time. This is not favourable as mentioned by you.
I am suggesting one of the possible work-around which I implemented in order to pass date-time string and store it in a "datetime" object which supports leap seconds as well as retains precision.
I have made a user defined function "DateTime" which takes the date-time string and returns a "datetime" object. It is demonstrated below:
format longg
ds3 = "01-Jan-2024";
dt3 = "23:59:01.2345678912345";
stringg=(ds3+" "+dt3);
t=DateTime(stringg)
t = datetime
2024-01-01T23:59:01.234Z
t.Second %this does not losses precision
ans =
1.2345678912345
function out=DateTime(DT_string)
arguments
DT_string string
end
C = textscan(DT_string,'%s %s'); %gives (1 x 2) cell array consisting of date and time
date_string=string(C{1});
time_string=string(C{2});
Date=textscan(date_string,'%f %s %f','delimiter','-'); %save the day, month, year in cell array
Time=textscan(time_string,'%f %f %f','delimiter',':'); %Save hour, minutes and seconds in celll array
DT_object=datetime(date_string);
DT_object.Hour = Time{1}; %extract the hour, minutes and seconds and save them in variable
DT_object.Minute = Time{2};
DT_object.Second = Time{3};
DT_object.TimeZone='UTCLeapSeconds';
out=DT_object;
end
I hope you find this information useful !!

Categories

Find more on Data Type Conversion in Help Center and File Exchange

Products


Release

R2024b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!