RFC3339 and in UTC/Zulu string to integer C++ - c++

I am writing a C+ application for an embedded ARM device.
My application receives a date and time string in format RFC3339 and in UTC/Zulu. For example "2020-12-14T23:18:13Z"
I need to get the time from this in seconds, compare it to the current time in seconds and take action if there is a difference between those times of greater than 8 seconds.
I've included a third party header file to help, date.h from here : https://howardhinnant.github.io/date/date.html
I have to say i'm still struggling to properly get the seconds from the date and time string as an integer and do comparisons. It is always zero in my case. This is what I have been trying for example so far:
#include <iostream>
#include <string>
#include <sstream>
#include "date.h"
int main()
{
std::string ts = "2020-11-14T22:14:16Z"; // Literal string to test at first
std::istringstream infile1{ts};
sys_seconds tps;
infile1 >> parse("%FT%T%Ez", tps);
auto stampSinceEpoch_s = tps.time_since_epoch();
// Get the current time
auto now = system_clock::now();
auto now_s = time_point_cast<seconds>(now);
auto nowSinceEpoch_s = now_s.time_since_epoch();
if ( (nowSinceEpoch_s .count() - stampSinceEpoch_s.count()) > 8)
{
// Time difference is greater than 8 seconds, take action
}
}
Any help is greatly appreciated.

Related

Java to C++ UTC time - finding the Utc Zone Time Offset in seconds

I need to serialize a UTC date time instance from java to c++ using the minimal length of pure ByteBuffer of unsigned chars.
I need the time point with to be able to support minimum nanoseconds precision.
From the java side i have looked in the classes ZonedDateTime and OffsetDateTime and seen what kind of primitive they are using to store the time and all together this is equal to 17 bytes which is kind of a lot.
Please note that i am here not transferring the zone itself since i have not found a way to map those zone strings from IANA to integers. Thus i guess the zone offset will be enough. Since bought sides will have to convert their time point to a particular offset before sending it to the server lets say that will be UTC 0. I am looking for a solution that is queering the local time i.e. no NTP servers involved!
the java side looks like this:
// 4 byte
Integer year = offsetDateTime.getYear();
// 1 byte
Integer month = offsetDateTime.getMonthValue();
// 1 byte
Integer day = offsetDateTime.getDayOfMonth();
// 1 byte
Integer hour = offsetDateTime.getHour();
// 1 byte
Integer minutes = offsetDateTime.getMinute();
// 1 byte
Integer seconds = offsetDateTime.getSecond();
// 4 byte
Integer nanoSeconds = offsetDateTime.getNano();
// 4 byte
Integer utcZoneTimeTotalSecondsOffset = offsetDateTime.getOffset().getTotalSeconds();
on the c++ side i need to do the same as well as to be able to construct a time point from all those integers above.
I have found how to get the the above information except the utcOffset i.e. the last integer.
i would like to use chrono to consume this buffer and instantiate a time point from it. however i am not able to find a way to to get the time offset in c++. How do i get the time offset with chrono and then construct a time point from the above information?
auto now = std::chrono::system_clock::now();
time_t itt = std::chrono::system_clock::to_time_t(now);
tm utc_tm = *gmtime(&itt);
std::cout << utc_tm.tm_year + 1900 << '-';
std::cout << utc_tm.tm_mon + 1 << '-';
std::cout << utc_tm.tm_mday << ' ';
std::cout << utc_tm.tm_hour << ':';
std::cout << utc_tm.tm_min << ':';
std::cout << utc_tm.tm_sec << '\n';
? wher is the time zoneOffset here ?
if i use
utc_tm.tm_gmtoff
this is giving me the wrong information . at least in my case. So i believe gmtoff is not the way to go , but if gmtoff is not the way then what is?
Not a complete answer, but here is one way one might serialize a C++ local time point using Howard Hinnant's free, open source time zone library.
#include "date/tz.h"
#include <iostream>
#include <sstream>
std::string
to_string(date::zoned_time<std::chrono::nanoseconds> t)
{
using namespace std;
using namespace date;
ostringstream out;
out << t.get_sys_time().time_since_epoch().count()
<< ' ' << t.get_time_zone()->name();
return out.str();
}
date::zoned_time<std::chrono::nanoseconds>
from_string(const std::string& s)
{
using namespace std;
using namespace std::chrono;
using namespace date;
istringstream in{s};
long long ns;
std::string tz_name;
in >> ns >> tz_name;
return {tz_name, sys_time<nanoseconds>{nanoseconds{ns}}};
}
int
main()
{
using namespace std;
using namespace std::chrono;
using namespace date;
zoned_time<nanoseconds> zt{current_zone(), system_clock::now()};
cout << zt << '\n';
auto s = to_string(zt);
cout << s << '\n';
zt = from_string(s);
cout << zt << '\n';
}
I'm using a std::string to represent the serialization, which one might send across a network.
This example begins in main with creating a nanosecond-precision local time point, stored in date::zoned_time<nanoseconds>, using the computer's current local time zone, and the current UTC time. main first simply prints this time stamp out, which for me just output:
2019-09-11 12:37:04.846272000 EDT
which is my current local date/time and time zone abbreviation.
Next the program converts this to a string with a small (but not necessarily minimal) number of ASCII characters to completely describe the local time point. I've chosen the format:
<Number of nanoseconds since epoch> <IANA time zone name>
In this example, that string is:
1568219824846272000 America/New_York
This string is formed in to_string, which simply streams out the "time since epoch" of the system time, of the zoned_time. Then adds a space, and streams out the name of the time zone.
from_string reverses this operation by reading in the number of nanoseconds, and then reading in the time zone name. It then forms a zoned_time<nanoseconds> by pairing the time zone name, and forming a sys_time<nanoseconds> with the integer that was parsed.
main prints out the parsed zoned_time to ensure we have a loss-less round trip:
2019-09-11 12:37:04.846272000 EDT
In order to get a loss-less conversion that includes local time, one really needs to transmit the IANA time zone name, not just the current UTC offset. With only the UTC offset, one can recover the exact UTC time point. But one can not perform any local time arithmetic, or comparison with other local time points because one can not know the rules for when one changes the UTC offset. Only with the full IANA time zone name can one pass the information along about those rules.

How to deal with time in C++

I have a question about managing the date and time in c++. I have two classes Plane and Flight in my program.
My Plane will consist data as:
string tailNumber;//Plane's unique trait
vector<vector<string>> planeSchedule;//2D string vector to contain plane's depature date and arrival date
My Flight class will consist data as:
string tailNumber;//Plane's unique trait
string departureDate;
string arrivalDate;
In my main class, I will input the value for departureDate and arrivalDate in format: "YYYY/MM/DD HH:MM" such as: "2019/04/15 10:30" and "2019/04/16 9:30" (I will use the 24-hour format and time will be GMT).
My question is how do I convert the two strings above to a proper format to store in my planeSchedule, so that I will be able to avoid the time conflict in the planeSchedule.
For example, If the next time I'm adding a flight with departure and arrival date beetween the: 2019/04/15 10:30" and "2019/04/16 9:30" such as: "2019/04/15 13:30" and "2019/04/16 7:30", I will get an error like "Flight conflict, plane is not available to flight."
My professor recommends using an unsigned long int to store time, but I really do not know where to start to solve this problem. Any help/suggestion is appreciated.
The go-to place regarding dates and times in C++ is <chrono>. Some of it has been with us since C++11, some of it we'll see coming with C++20. It works in conjunction with the C-style date and time utilities in <ctime>, which might even suffice for your purposes.
Trying to handle date / time as either integers or strings, parsing them from input, comparing, and converting them to strings for output, will effectively result in you reimplementing parts of what's already in those headers (a.k.a. "reinventing the wheel").
I have two pieces of advice based on long experience with systems that did it badly :-)
The first is to not store date and time information as strings or integral values, especially when C++ has very good support for that in std::chrono. If you use the correct types, comparisons and manipulations become relatively simple.
Second, make sure you use UTC for all times. You should convert local times to UTC as soon as possible after getting them, and convert back to local as late as possible when presenting them. This will also greatly simplify comparisons.
By way of example, here's a complete program which show the simplicity(a) in action:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <chrono>
using std::chrono::system_clock;
using std::chrono::duration_cast;
namespace {
system_clock::time_point getTimePoint(std::string strTime) {
std::tm myTm = {};
std::stringstream ss(strTime.c_str());
ss >> std::get_time(&myTm, "%Y/%m/%d %H:%M");
return system_clock::from_time_t(std::mktime(&myTm));
}
void outputTime(const char *desc, system_clock::time_point &tp) {
std::time_t now = system_clock::to_time_t(tp);
std::cout << desc
<< std::put_time(std::localtime(&now), "%Y-%m-%d %H:%M") << "\n";
}
}
int main() {
std::string startTime = "2019/04/15 10:30";
std::string endTime = "2019/04/16 09:30";
auto startTp = getTimePoint(startTime);
auto endTp = getTimePoint(endTime);
outputTime("Start time: ", startTp);
outputTime(" End time: ", endTp);
auto duration = duration_cast<std::chrono::minutes>(endTp - startTp);
std::cout << "\nThere are " << duration.count() << " minutes between "
<< startTime << " and " << endTime << "\n";
}
The output of that program is:
Start time: 2019-04-15 10:30
End time: 2019-04-16 09:30
There are 1380 minutes between 2019/04/15 10:30 and 2019/04/16 09:30
(a) Yes, the program may seem reasonably big but that's just because of the stuff making it a complete program. The getTimePoint and outputTime functions show how to do the conversion to and from time points, and the meat of the simplicity is the line containing duration_cast to get the number of minutes between the two time points.

How do I write a message timestamp to a log file?

I'm trying to create a logging file for my C++ program. My goal is to put two timestamps at two points of my program and print in a file the CPU time period between these two points. I'm doing this because I want to know which parts of my code are the most time consuming so I can make improvements (so there may be several chunks of code I want to measure). So far, I've made a function that, when called, prints a string that I pass as an argument, to a file:
#define LOGFILE "myprog.log"
void Log (std::string message){
std::ofstream ofs;
ofs.open(LOGFILE, std::ofstream::out | std::ios::app);
ofs << message << std::endl;
ofs.close();
}
However, I'm having difficulty figuring out how to print the CPU timestamp. Firstly, I don't know what time measurement format I should use (should I use the chrono or the time_t types?) I'm trying to print a time period so it would be helpful if there was a type for duration (I've tried chrono::duration but it seems to require C++11 support). Secondly, given I know what type to use, how do I print it to the file? Is there a way to cast that type to a string? Or can I pass it directly to my function and print it somehow?
This has troubled me a lot the last couple of days and I can't seem to figure it out, so any input would be really helpful. Thanks in advance!
Get a CPU Timestamp
You'll want to use std::chrono::system_clock to get this timestamp. Do not use std::chrono::steady_clock or std::chrono::high_resolution_clock, as those are for making high-precision timing measurements, and do not guarantee fidelity or accuracy to wall-clock time.
auto now = std::chrono::system_clock::now();
//now is a time_point object describing the instant it was recorded according to your system clock
Print this CPU Timestamp in a readable format
In C++20, this is pretty trivial.
std::string formatted_time = std::format("{0:%F_%T}", now);
ofs << formatted_time << ": " << message << std::endl;
%F is a substitute for %Y-%m-%D, which will output year-month-day in ISO format, i.e. 2018-10-09.
%T is the same for %H:%M:%S, which will output a time, i.e. 17:55:34.786
See the specification for std::format and std::formatter for more information about how to specify these parameters.
As of December 2020, no major compilers support the <format> library, yet, so as an alternative you can use fmt, which is a standalone implementation of the library.
Prior to C++20
Consider Howard Hinnant's date library, most of which is being incorporated into C++20 as a new part of the chrono library. The format function found in that library uses the same syntax as suggested above for the C++20 version, although without integration with std::format.
I'm usually use my implementation for such things.
#include <chrono>
#include <ctime>
// strftime format
#define LOGGER_PRETTY_TIME_FORMAT "%Y-%m-%d %H:%M:%S"
// printf format
#define LOGGER_PRETTY_MS_FORMAT ".%03d"
// convert current time to milliseconds since unix epoch
template <typename T>
static int to_ms(const std::chrono::time_point<T>& tp)
{
using namespace std::chrono;
auto dur = tp.time_since_epoch();
return static_cast<int>(duration_cast<milliseconds>(dur).count());
}
// format it in two parts: main part with date and time and part with milliseconds
static std::string pretty_time()
{
auto tp = std::chrono::system_clock::now();
std::time_t current_time = std::chrono::system_clock::to_time_t(tp);
// this function use static global pointer. so it is not thread safe solution
std::tm* time_info = std::localtime(&current_time);
char buffer[128];
int string_size = strftime(
buffer, sizeof(buffer),
LOGGER_PRETTY_TIME_FORMAT,
time_info
);
int ms = to_ms(tp) % 1000;
string_size += std::snprintf(
buffer + string_size, sizeof(buffer) - string_size,
LOGGER_PRETTY_MS_FORMAT, ms
);
return std::string(buffer, buffer + string_size);
}
It returns current time in format: 2018-09-23 21:58:52.642.
Yes it requires --std=c++11 or above.
For the record:
If C++20 features are not available, as in my case, you can use the following:
#include <ctime>
#include <iomanip>
#include <iostream>
using namespace std ;
time_t now = time(nullptr) ;
cout << put_time(localtime(&now), "%T") << endl ;
put_time is defined in iomanip library, look at https://en.cppreference.com/w/cpp/io/manip/put_time, and time_t and localtime are from the ctime, https://en.cppreference.com/w/cpp/chrono/c/ctime
If you want a more manual approach, this is what I've used before
char buffer[MAX_BUFFER_SIZE];
time_t t = time(NULL);
struct tm *lt = localtime(&t);
snprintf(buffer, MAX_BUFFER_SIZE, "%02d/%02d/%02d %02d:%02d:%02d", lt->tm_mon+1, lt->tm_mday, lt->tm_year%100, lt->tm_hour, lt->tm_min, lt->tm_sec);
Then just output buffer, which now contains string representation of time, to your file.

Date arithmetic in C++

I have been trying to write a C++ program, that requires me to do date arithmetic.
For example today's date (9-30-2014) minus 4 days and have it return 9-26-2014, or today date plus 3 days returning 10-3-2014.
My original thought process is to use
ctime
which will return the date in seconds from jan 1 1970, I could then add or subtract a set number of seconds for the number of days and pass the result into "put_time" a part of
iomanip
to start I am just trying to get this method to print the correct date, but I can not get the compiler to recognize "put_time"
I am using eclipse version (4.4.0)
with "version 4.1.11(2)-release (x86_64-unknown-cygwin)" as a compiler
From research I have found that "put_time" is only included in certain versions of c++ and I tried running this command
`-std=c++0x`
However I am still receiving the same error "'put_time' was not declared in this scope".
this is the code I am running so far:
//============================================================================
// Name : Date.cpp
// Author : me
// Version :
// Copyright : Your copyright notice
// Description : date calculations
//============================================================================
#include <iostream>
#include <iomanip> // std::put_time
#include <ctime> // std::time_t, struct std::tm, std::localtime
#include <chrono> // std::chrono::system_clock
using namespace std;
int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
time_t timer;
time(&timer);
cout << timer;
struct tm * ptm = localtime(&timer);
cout << put_time(ptm,"%c");
return 0;
}
Why not use asctime? It's prototype is char* asctime (const struct tm * timeptr); and you should not have any problem printing out he char*. The only issue is that the output format is fixed as Www Mmm dd hh:mm:ss yyyy where Www represents the three-letter abbreviation of the day of the week.
If you want more flexibility in the format of the output string, you can use strftime to get custom formatting. It's prototype is size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr );

How do I convert a string in seconds to time in C++

I have a string that stores the no of seconds since a process started. I need to convert this string with the no of seconds to time in C++. I need to subtract this time from the current time to get the time that this process started. I am confused and I do not know how to go about it. Please could someone help me out. I am a bit new to C++
Maybe you could try out Boost Time Library (http://www.boost.org/doc/libs/1_53_0/libs/timer/doc/index.html) or std::chrono if you're using newer compiler (as suggested below) and wish to stay within STL.
Something like that could work:
#include <chrono>
#include <string>
using namespace std::chrono;
std::string elapsed_time_in_s = "123456";
system_clock::time_point then = system_clock::now() -
std::chrono::seconds(std::stoll(elapsed_time_in_s));
time_t then_as_time_t = system_clock::to_time_t(then);
#include <sstream>
///
std::stringstream strs(seconds_string);
unsigned int tempTime=0;
if(!(strs >> tempTime))
//error
//calculate around with tempTime
if(!(strs << tempTime)
//error
if(!(strs >> seconds_string)
//error
//new string with the current time
You can use standard <time.h> routines (time, and gmtime or localtime).
For example:
void PrintProcessStartTimeAndDate(int numOfSeconds)
{
time_t rawtime;
struct tm* ptm;
time(&rawtime);
rawtime -= numOfSeconds;
ptm = gmtime(&rawtime); // or localtime(&rawtime);
printf("Process started at %.2d:%.2d:%.2d on %.2d/%.2d/%.2d\n",
ptm->tm_hour,ptm->tm_min,ptm->tm_sec,ptm->tm_mday,ptm->tm_mon+1,ptm->tm_year+1900);
}
Please note that gmtime and localtime routines are not thread-safe.
This fact is due to the pointer-to-static-structure that each one of them returns.