How can we convert a datetime into a string that represents a Unix timestamp in nanoseconds?
Mostrar comentarios más antiguos
I am trying to use Matlab to generate a string which contains a Unix timestamp in nanoseconds (i.e number of 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)
% Output:
dt_ns_string =
'1'
and I have the nanosecond precision that I need.
However, for later dates this does not work. For example, 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").
I believe this may be due to working with double types, and I might need to use uint64, but I can't figure out how to make the change.
How can I solve this?
Respuesta aceptada
Más respuestas (3)
Peter Perkins
el 26 de Jun. de 2020
There's an easier way already built into datetime:
>> dt = datetime(["16-Jun-2020 00:00:00.000000001" "16-Jun-2020 00:00:00.000000002" "16-Jun-2020 00:00:00.000000003"],'Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSS')
dt =
1×3 datetime array
16-Jun-2020 00:00:00.000000001 16-Jun-2020 00:00:00.000000002 16-Jun-2020 00:00:00.000000003
>> convertTo(dt,'epochtime','TicksPerSecond',1e9)
ans =
1×3 int64 row vector
1592265600000000001 1592265600000000002 1592265600000000003
teeeeee, for reasons that may become apparent below, I'm wondering what you are doing with these values. If you are really needing that kind of precision over spans of decades, the obvious questions might be, "how are you measuring that precisely?" and "are you forgetting about leap seconds?" You may only care about order, not the actual values.
You shouldn't rely too much on the internals of datetime, but I will say that while datetime has a very wide range and precision, duration has the same behavior as double. So as the magnitude of a duration increases, the precision decreases. That's what allows you to create both of these:
>> seconds(1e-15)
ans =
duration
1e-15 sec
>> seconds(1e15)
ans =
duration
1e+15 sec
To represent ns since 1970, you'll need
>> ceil(log2(seconds(datetime('now') - datetime(1970,1,1))*1e9))
ans =
61
bits, which is more precision that duration has. With duration, you get about +/- 104 days at ns precision. or about 285 My at ms precision. This is completely independent of the display format, which might show units of s, min, hr, days (exact 86400s days, not calendar days), or years (exact 365.2425*86400s years, not calendar years). It would be interesting to hear about your use case for ns precision of elapsed times on the order of decades.
3 comentarios
@teeeeee: the convertTo documentation states at the bottom "Introduced in R2018b", which is a shame because this seems to be quite a neat solution to your original question.
in the "Convert Datetime Arrays to Numeric Values" section would not go amiss. It is one of the first pages returned by [major internet search engine] when searching for "MATLAB convert date to number", but no sign of this useful function (or for that matter exceltime and posixtime, all of which have numeric outputs).
Peter Perkins
el 28 de Jul. de 2020
Noted, thanks.
James Tursa
el 15 de Mayo de 2024
Movida: Stephen23
el 16 de Nov. de 2024
0 votos
@Stephen23 You need to be very careful using between() to produce calendarDuration types for these calculations since this type is fuzzy and the actual durations can morph into different durations depending on the dates involved. Frankly, I would avoid ...
James Tursa
el 22 de Jun. de 2024
Editada: James Tursa
el 22 de Jun. de 2024
Another workaround that avoids the lossy duration type issues and doesn't need the messy struct solution for this particular case where the t0 variable is known to have a 0 seconds part. The crude answer is derived in two parts as seconds + nanoseconds (where the ns might actually be large enough to spill over into some seconds):
format longg
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');
ns = t1.Second * 1e9 % pick off the seconds separately
t1.Second = 0;
sec = seconds(t1 - t0)
If you want a single ns variable:
int64(sec)*1e9 + int64(ns)
If you don't like the fact that ns can be larger than 1e9, you can always mod the result and adjust sec and ns accordingly.
This approach can also recover fractional nanoseconds, as long as you get them into the datetime variable correctly. E.g.,this doesn't work because the datetime input format is limited to nine S's and we need twenty-two S's:
t1 = datetime('16-Jun-2020 00:00:00.0000000012345678912345','Format','dd-MMM-yyyy HH:mm:ss.SSSSSSSSSSSSSSSSSSSSSS');
ns = t1.Second * 1e9 % WRONG result ... original fractional part never got read into the variable
t1.Second = 0;
sec = seconds(t1 - t0)
But these two methods do work:
t1 = datetime('16-Jun-2020') + duration('00:00:00.0000000012345678912345');
ns = t1.Second * 1e9
t1.Second = 0;
sec = seconds(t1 - t0)
And
t1 = datetime(2020,6,16,0,0,0.0000000012345678912345);
ns = t1.Second * 1e9
t1.Second = 0;
sec = seconds(t1 - t0)
A more generic solution would need to cover differences that could be negative, arbitrary seconds associated with t0, etc.
Categorías
Más información sobre Data Type Conversion en Centro de ayuda y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!