Reputation: 737
I am trying to use Matlab to generate a string which contains a Unix timestamp in nanoseconds (i.e nanoseconds since 01-Jan-1970 00:00:00, the Unix epoch) from an input date string.
For example, if my input is only 1 ns after the start of the epoch, then the following code works:
t0 = datetime('01-Jan-1970 00:00:00.000000000','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS');
t1 = datetime('01-Jan-1970 00:00:00.000000001','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS');
dt_ns = seconds(t1 - t0)*1e9
dt_ns_string = sprintf('%.0f',dt_ns)
dt_ns_string =
'1'
and I have the nanosecond precision that I need.
However, if I instead for t1
use a date around today:
t1 = datetime('16-Jun-2020 00:00:00.000000001','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS');
then the output is the following:
dt_ns_string =
'1592265600000000000'
and I have lost the final nanosecond precision on the end of the string (final character should be a "1").
How can I solve this?
EDIT
As suggested in the comments there is also the Matlab function posixtime()
which eliminates the need to manually subtract the datetime corresponding to 01-Jan-1970. However, this results in the same problem:
dt_ns_posix = posixtime(t1)*1e9
sprintf('%.0f',dt_ns_posix)
'1592265600000000000'
Upvotes: 1
Views: 360
Reputation: 112699
Here's an approach that sideteps the loss of precision inherent to double
:
between
with the optional third input to get the time difference as a calendarDuration
scalar indicating days, hours, minutes and seconds.char
and extract the individual numbers of days, hours, minutes and seconds.1e9
and convert to uint64
. Note that each individual value multiplied by 1e9
gives an integer that is well within the limits of floating-point precision (i.e. is not larger than 2^53
).sum
with the 'native'
option to obtain the total number of nanoseconds as a uint64
value. t0 = datetime('01-Jan-1970 00:00:00.000000000','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS');
t1 = datetime('16-Jun-2020 00:00:00.000000001','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS');
b = between(t0, t1, {'Days', 'Time'});
t = str2double(regexp(char(b), '(?<=(^| )).+?(?=[dhms$])', 'match')); % split d, h, m, s
if numel(t)==3 % if the number of days is 0 it will not be present
t = [0 t];
end
result = sum(uint64(t*1e9).*uint64([86400 3600 60 1]), 'native'); % sum as uint64
This gives
result =
uint64
1592265600000000001
Upvotes: 1