Unix timestamp seconds and nanoseconds string conversion in C++
2024-11-29 – 23:25I have recently worked with the PcapPlusPlus library to analyze timestamps from PCAP ethernet captures. And I have fucked up majorly the Unix timestamp to string conversion. This post is meant to
1. remind me of my failure…
2. remember how to do it right the next time
Unix timestamps represent time elapsed since 00:00:00 UTC on Thursday, 1 January 1970, mostly in seconds, in case of .pcap(ng) files with an additional fractional nanoseconds part.
The following timestamp represents Mon Jul 15 2024 17:48:40 GMT+0000 and almost a second full of nanoseconds (the fractional part):1721065720.968918119
In my C++ program I wanted to export stuff as CSV including a row of Unix timestamps. PcapPlusPlus allows getting the timestamp from a parsed packet read from a pcap(ng) file like this:
uint32 seconds = parsedPacket.getRawPacket()->getPacketTimeStamp().tv_sec; uint32 nanosececonds = parsedPacket.getRawPacket()->getPacketTimeStamp().tv_nsec; |
Converting this to string seems to be straight forward using a std::stringstream. The crucial part is that the nanoseconds part can start with one or more zeros such as this:1721065721.008918119
The fractional part represents 0.008918119 seconds. This must be 9 digits long!
Parsing the fractional part of this with a std::stringstream will strip the leading zeros which reduces the length of the nanoseconds fractional part: The fractional part must preserve the 9 digits because 0.8918119 s is much bigger than 0.008918119 s.
To properly parse the fractional part (e.g. to plot it) it must be ensured that the leading zeros also go into the string written into the CSV:
#include <sstream> #include <iomanip> const std::string pcapTimestampToString(const uint32 seconds_, const uint32 nanoseconds_) { std::stringstream ss; ss<<seconds_<<"."; ss<<std::setfill('0')<<std::setw(9)<<nanoseconds_; return ss.str(); } const std::string pcapTimestampString = pcapTimestampToString( parsedPacket.getRawPacket()->getPacketTimeStamp().tv_sec, parsedPacket.getRawPacket()->getPacketTimeStamp().tv_nsec); |
This was partially answered by Stackoverflow but not specifically enough to not deserve a dedicated post.