teeeeee
teeeeee

Reputation: 737

How can we convert a datetime into a string representing a Unix timestamp in nanoseconds using Matlab?

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

Answers (1)

Luis Mendo
Luis Mendo

Reputation: 112699

Here's an approach that sideteps the loss of precision inherent to double:

  1. Use between with the optional third input to get the time difference as a calendarDuration scalar indicating days, hours, minutes and seconds.
  2. Convert to char and extract the individual numbers of days, hours, minutes and seconds.
  3. Multiply each value by 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).
  4. Use multiplication and 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

Related Questions