NTP timestamp is not correctly parsed c++ - c++

I want to send an SNTP req and then parse the response, hence I started by simply creating a timestamp convert it to ntp and then try to read the seconds and the fractional part. The issue is that the seconds part is not correctly parsed in the first place, always shifted by a few seconds. This is what I have done:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <iostream> // Needed to perform IO operations
#include <ctime>
constexpr auto SECONDS_SINCE_FIRST_EPOCH = (2208988800ULL);
constexpr auto NTP_SCALE_FRAC = (4294967296ULL);
using namespace std;
int main()
{
std::time_t _timeEpoch = std::time(nullptr);
unsigned long long tv_ntp, tv_usecs, tv_time;
tv_ntp = _timeEpoch + SECONDS_SINCE_FIRST_EPOCH;
tv_usecs = (NTP_SCALE_FRAC * _timeEpoch) / 1000000UL;
tv_time = (tv_ntp << 32) | tv_usecs;
std::cout << "GetUtcTimeMilliSeconds UTC sec: " << _timeEpoch << " 1900: " << tv_ntp << " fraction of second " << tv_usecs << " tv_time " << tv_time << std::endl;
uint32_t msw = (tv_time >> 32) & 0xFFFFFFFF;
uint32_t lsw = tv_time & 0xFFFFFFFF;
std::cout << "GetUtcTimeMilliSeconds msw " << msw << " lsw: " << lsw << std::endl;
return 0;
}
I expected msw to be equal to tv_ntp and lsw to tv_usecs but they are not
GetUtcTimeMilliSeconds UTC sec: 1572103823 1900: 3781092623 fraction of second 6752134505701 tv_time 16239671495839982821
GetUtcTimeMilliSeconds msw 3781093167 lsw: 445916389

Related

How to convert seconds to hh:mm:ss.millisecond format c++?

I need to convert seconds in to hh:mm:ss.milliseconds and I need that this format must be respected. I mean that hours, minutes and seconds must have 2 digits and milliseconds 3 digits.
For example, if seconds = 3907.1 I would to obtain 01:05:07.100
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <stdio.h>
#include <sstream>
#include <math.h>
using namespace std;
int main()
{
double sec_tot = 3907.1;
double hour = sec_tot/3600; // seconds in hours
double hour_int;
double hour_fra = modf(hour, &hour_int );//split integer and decimal part of hours
double minutes = hour_fra*60; // dacimal hours in minutes
double minutes_int;
double minutes_fra = modf(minutes, &minutes_int); // split integer and decimal part of minutes
double seconds = minutes_fra*60; // decimal minutes in seconds
stringstream ss;
ss << ("%02lf", hour_int) << ":" << ("%02lf", minutes_int) << ":" << ("%02lf", seconds);
string time_obs_def = ss.str();
cout << time_obs_def << endl;
return 0;
}
but the output is 1:5:7.1
Thank you.
Nowadays you should probably use the chrono duration std::chrono::milliseconds for such a task, but if you'd like make our own type to support formatting, something like this should do it:
#include <iomanip> // std::setw & std::setfill
#include <iostream>
// your own type
struct seconds_t {
double value;
};
// ostream operator for your type:
std::ostream& operator<<(std::ostream& os, const seconds_t& v) {
// convert to milliseconds
int ms = static_cast<int>(v.value * 1000.);
int h = ms / (1000 * 60 * 60);
ms -= h * (1000 * 60 * 60);
int m = ms / (1000 * 60);
ms -= m * (1000 * 60);
int s = ms / 1000;
ms -= s * 1000;
return os << std::setfill('0') << std::setw(2) << h << ':' << std::setw(2) << m
<< ':' << std::setw(2) << s << '.' << std::setw(3) << ms;
}
int main() {
seconds_t m{3907.1};
std::cout << m << "\n";
}
Coming in C++20:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int
main()
{
double sec_tot = 3907.1;
cout << format("{:%T}\n", round<milliseconds>(duration<double>{sec_tot}));
}
printf style format specifiers do not work. You will need to use the stream manipulators to set the width and fill character.
ss << std:setw(2) << std::setfill('0') << hour_int;
This will also add a leading zero to enforce hh:mm:ss format.
If hh is 00, returns only mm:ss.
ms are left out from this example, but easy to add.
#include <iostream>
std::string convertSecondsToHHMMSS (int value) {
std::string result;
// compute h, m, s
std::string h = std::to_string(value / 3600);
std::string m = std::to_string((value % 3600) / 60);
std::string s = std::to_string(value % 60);
// add leading zero if needed
std::string hh = std::string(2 - h.length(), '0') + h;
std::string mm = std::string(2 - m.length(), '0') + m;
std::string ss = std::string(2 - s.length(), '0') + s;
// return mm:ss if hh is 00
if (hh.compare("00") != 0) {
result = hh + ':' + mm + ":" + ss;
}
else {
result = mm + ":" + ss;
}
return result;
}
int main() {
std::cout << convertSecondsToHHMMSS(3601) << "\n";
std::cout << convertSecondsToHHMMSS(1111) << "\n";
std::cout << convertSecondsToHHMMSS(60) << "\n";
std::cout << convertSecondsToHHMMSS(12) << "\n";
std::cout << convertSecondsToHHMMSS(0) << "\n";
}

Function mktime returns -1 on my computer, but correct result executed by online compiler

I'm trying to read a wstring which contains some random date, add some minutes and then compare it with my computers date. I've tried the same code on this site and it works just fine, but when I try to run it in Visual Studio 2013 t1 is set to -1 and diff to 0.
My code:
#include <iostream>
#include <fstream>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <thread>
int main()
{
std::wstring updateTime(L"Thu Dec 14 15:06:00 2016");
std::wstring updatePeriod(L"30");
std::string timeUpdate(updateTime.begin(), updateTime.end());
std::istringstream ss{ timeUpdate };
struct tm dateUp ={};
ss >> std::get_time(&dateUp, "%a %b %d %X %Y");
std::time_t t1 = std::mktime(&dateUp);
//time_t t1 = std::mktime(&dateUp); // Contine data la care se porneste testul
int periodUpdate = std::stoi(updatePeriod); // Contine numarul de minute
std::cout <<"Data inainte de a se adauga minutele = "<< 1900 + dateUp.tm_year << " " << dateUp.tm_mon << " " << dateUp.tm_mday << " " << dateUp.tm_hour << ":" << dateUp.tm_min << "\n\n";
// Adaug minutele la data la care se porneste testul si apoi refac structura de tip time_t (minutele se convertesc automat in ore, zile..)
dateUp.tm_min += periodUpdate;
t1 = std::mktime(&dateUp);
std::cout <<"Data dupa ce s-au adaugat minutele = "<< 1900 + dateUp.tm_year << " " << dateUp.tm_mon << " " << dateUp.tm_mday << " " << dateUp.tm_hour << ":" << dateUp.tm_min << "\n\n";
// Retin data curenta a calculatorului
time_t now = time(NULL);
struct tm now_tm = *localtime(&now);
time_t t2 = std::mktime(&now_tm);
std::cout << "Data curenta = "<<1900 + now_tm.tm_year << " " << now_tm.tm_mon << " " << now_tm.tm_mday << " " << now_tm.tm_hour << ":" << now_tm.tm_min << "\n\n";
//Compar cele 2 date. Pentru a se face update programat diferenta trebuie sa fie pozitiva. Adica data actuala sa fie mai mare decat data la care ar trebui sa se faca update
double diff = difftime(t2, t1);
std::cout << diff << "\n";
}

Outputting date in ISO 8601 format

How can I get a date in the following format in C++:
2016-04-26T19:50:48Z
#include <chrono>
#include <ctime>
time_t _tm = time(NULL);
struct tm*curtime = localtime(&_tm);
And outputting as asctime(curtime)
The current output is: "Thu Apr 28 16:02:41 2016\n"
Documentation is your friend:
std::time_t t
= std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::cout << std::put_time( std::localtime( &t ), "%FT%T%z" );
in my system yields
2016-04-29T02:48:56+0200
Based on #Uri's answer which fixes a few bugs and shows the time in the proper timezone along with the milliseconds in ISO8601 format:
auto now = std::chrono::system_clock::now();
std::time_t time = std::chrono::system_clock::to_time_t(now);
std::tm* now_tm = std::localtime(&time);
long long timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
std::cout << std::setfill('0')
<< std::put_time(now_tm, "%FT%H:%M:")
<< std::setw(2) << (timestamp / 1000) % 60 << '.'
<< std::setw(3) << timestamp % 1000
<< std::put_time(now_tm, "%z");
I'm combining the std::localtime which gives me calendar values, with std::chrono functions that gives me the precise methods. Here is my code:
#include <ctime>
#include <chrono>
...
auto now = std::chrono::system_clock::now();
auto now_c = std::chrono::system_clock::to_time_t(now)
auto now_tm = std::localtime(&now_c);
auto now_since_epoch = now.time_since_epoch(); // since 1970
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now_since_epoch).count();
std::cout << std::setfill('0') <<
std::setw(4) << now_tm->tm_year + 1900 << '-' <<
std::setw(2) << now_tm->tm_mon + 1 << '-' <<
std::setw(2) << now_tm->tm_mday << 'T' <<
std::setw(2) << now_ms % (24*60*60*1000) << ':' <<
std::setw(2) << now_ms % (60*60*1000) << ':' <<
std::setw(2) << now_ms % (60*1000) << '.' <<
std::setw(3) << now_ms % (1000);
Although verbose, it is actually doing less than strftime.

What is an intelligent way to determine max size of a strftime char array?

How can I size the char array for strftime without trial and error? Using mktime, the timestamp size N in the example has to be greater 86, otherwise I get arbitrary dates back.
e.g.
N = 86 : 2013-07-13 02:41
N = 82 : 1979-05-18 13:23
How do I efficiently scale N without prior knowledge of the date? The check >0 does not help.
#include <iostream>
#include <cstring>
#include <ctime>
#define N 86
using namespace std;
int main(void)
{
time_t t;
struct tm ts;
char timestamp[N] ;
ts.tm_min = 41;
ts.tm_hour = 2;
ts.tm_mday = 13;
ts.tm_mon = 7 - 1;
ts.tm_year = 13 - 1900 + 2000;
t = mktime(&ts);
if (strftime(timestamp, sizeof(timestamp)-1, "%Y-%m-%d %H:%M", &ts) > 0)
cout << timestamp;
else {
cerr << "strftime failed." <<endl;
return 1;
}
return 0;
}
From the documentation for strftime:
If the length of the resulting C string, including the terminating null-character, doesn't exceed maxsize, the function returns the total number of characters copied to ptr (not including the terminating null-character). Otherwise, it returns zero, and the contents of the array pointed by ptr are indeterminate.
That means if you don't know the size and can dynamically allocate a string you can do something along the lines of:
int size = N; // Some starting size
char *timestamp = malloc(size);
// Your time stuff
int result = strftime(timestamp, size - 1, "%Y-%m-%d %H:%M", &ts);
// While there isn't enough room to store the result
while (result == 0)
{
free(timestamp); // Free old data
size *= 2; // Double the size (should be more than enough)
timestamp = malloc(size); // Allocate the new size. You can check for failed allocations here as well.
// Retry
result = strftime(timestamp, size - 1, "%Y-%m-%d %H:%M", &ts);
}
std::cout << timestamp;
Because you tagged this as C++, perhaps you might consider the following.
--> Note that there is no struggle with the string size here.
// function to create a timestamp style string
std::string yyDmmDdd_hhCmmGet(time_t tt)
{
std::stringstream ss;
// goal - something like: "%Y-%m-%d %H:%M"
{
struct tm mybdtod; // linux api: my broken down time of day
// the following is a relatively slow function
::localtime_r (&tt, &mybdtod);
// linux api - convert time_t to tm as local time
ss << std::setw(4) << (mybdtod.tm_year+1900)
<< "-"
<< std::setfill('0') << std::setw(2) << mybdtod.tm_mon+1
<< "-"
<< std::setfill('0') << std::setw(2) << mybdtod.tm_mday
<< " ";
ss << std::dec << std::setfill('0') << std::setw(2)
<< mybdtod.tm_hour
<< ":"
<< std::setfill('0') << std::setw(2)
<< mybdtod.tm_min;
}
return(ss.str());
}
int t186(void)
{
struct tm ts; // linux api: time struct
::memset(&ts, 0, sizeof(tm));
ts.tm_min = 41;
ts.tm_hour = 3-1;
ts.tm_mday = 13;
ts.tm_mon = 7 - 1;
ts.tm_year = 13 - 1900 + 2000;
time_t tt = mktime(&ts); // linux api: Convert tm struct to time_t
// format time_t to string
std::string s = yyDmmDdd_hhCmmGet(tt); // timestamp style
std::cout << "\n" << s
<< "\n s.size(): "
<< s.size() << " chars" << std::endl;
// now we know how many chars timestamp needs
// add 1 to size because ?strftime seems to need it?
char timestamp[s.size()+1];
(void)strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M", &ts);
// linux api: format time_t to string
std::cout << "\n" << timestamp << std::endl;
std::cout << " sizeof(timestamp): "
<< sizeof(timestamp) << " chars" << std::endl;
return(0);
}

How to implement serialization and de-serialization of a double?

I am trying to solve the relatively simple problem of being able to write a double to a file and then to read the file into a double again. Based on this answer I decided to use the human readable format.
I have successfully circumvented the problems some compilers have with nan and [-]infinity according to this question. With finite numbers I use the std::stod function to convert the string representation of a number into the number itself. But from time to time the parsing fails with numbers close to zero, such as in the following example:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
stream << small;
std::cout << "serialized: " << stream.str() << std::endl;
double out = std::stod(stream.str());
std::cout << "de-serialized: " << out << std::endl;
return 0;
}
On my machine the result is:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
terminate called after throwing an instance of 'std::out_of_range'
what(): stod
The program has unexpectedly finished.
That is, the number is too close to zero to be properly parsed. At first I thougth that the problem is that this number is denormal, but this doesn't seem to be the case, since the mantissa starts with a 9 and not a 0.
Qt on the other hand has no problems with this number:
#include <cmath>
#include <limits>
#include <QString>
#include <QTextStream>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
QString string = QString::number(small, 'g', maxPrecision);
QTextStream stream(stdout);
stream.setRealNumberPrecision(maxPrecision);
stream << "serialized: " << string << '\n';
bool ok;
double out = string.toDouble(&ok);
stream << "de-serialized: " << out << '\n' << (ok?"ok":"not ok") << '\n';
return 0;
}
Outputs:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
de-serialized: 9.2263152681638151025201733115952403273156653201666065e-318
ok
Summary:
Is this a bug in the gcc implementation of standard library?
Can I circumvent this elegantly?
Should I just use Qt?
Answering question #2:
This is probably my "C-way" kind of thinking, but you could copy the double into a uint64_t (mem-copying, not type-casting), serialize the uint64_t instead, and do the opposite on de-serialization.
Here is an example (without even having to copy from double into uint64_t and vice-versa):
uint64_t* pi = (uint64_t*)&small;
stringstream stream;
stream.precision(maxPrecision);
stream << *pi;
cout << "serialized: " << stream.str() << endl;
uint64_t out = stoull(stream.str());
double* pf = (double*)&out;
cout << "de-serialized: " << *pf << endl;
Please note that in order to avoid breaking strict-aliasing rule, you actually do need to copy it first, because the standard does not impose the allocation of double and uint64_t to the same address-alignment:
uint64_t ismall;
memcpy((void*)&ismall,(void*)&small,sizeof(small));
stringstream stream;
stream.precision(maxPrecision);
stream << ismall;
cout << "serialized: " << stream.str() << endl;
ismall = stoull(stream.str());
double fsmall;
memcpy((void*)&fsmall,(void*)&ismall,sizeof(small));
cout << "de-serialized: " << fsmall << endl;
If you're open to other recording methods you can use frexp:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
int exp;
double x = frexp(small, &exp);
//std::cout << x << " * 2 ^ " << exp << std::endl;
stream << x << " * 2 ^ " << exp;
int outexp;
double outx;
stream.seekg(0);
stream >> outx;
stream.ignore(7); // >> " * 2 ^ "
stream >> outexp;
//std::cout << outx << " * 2 ^ " << outexp << std::endl;
std::cout << small << std::endl << outx * pow(2, outexp) << std::endl;
return 0;
}