Convert std::string to std::time_t using only C++98 - c++

My main problem is to compare current time (const std::time_t now = std::time(NULL);) with the given time (e.g., "2017-12-14") which is std::string object. So, I am using std::difftime(end, start) function. But the problem is that at first I have to convert std::string to std::time_t object.
Is it possible convert it (format is 'yyyy-mm-dd') to std::time_t object using already known functions (using only C++98)?
I found a function strptime here: https://linux.die.net/man/7/feature_test_macros, but this is POSIX function. I need multi-platform code.
Also I think that it is a bad solution to gain 'yyyy', 'mm', 'dd' strings, convert those to int and assign to std::tm's tm_year, tm_mon, tm_mday members correspondingly. (then convert std::tm to std::time_t)

Related

String to date not working in C++ when using the %d%m%y format to create am std::time_t

I am trying to get a date from a string, which is a question that's been asked a thousand times before, but for some reason, even though all the examples are the same when I follow them, it doesn't work.
Here is my code:
struct std::tm tm;
std::istringstream stringStream("191121");
stringStream >> std::get_time(&tm, "%d%m%y");
std::time_t time = mktime(&tm);
I think I am using the correct format, which I found here: https://www.boost.org/doc/libs/1_77_0/doc/html/date_time/date_time_io.html#date_time.format_flags
Even though it is from boost, as far as I know, those flags are pretty standard.
Whenever I run this code, the variable time is always -1.
std::get_time may only fill in the fields of tm which are present in the string (it is unspecified whether implementations set unused fields to zero).
As tm is uninitialised this likely leads to an invalid time which causes mktime to fail. Initialising tm at the start of the code fixes the problem. It's also a good idea to check that stream operations succeed before using their results.
std::tm tm{};
std::istringstream stringStream("191121");
stringStream >> std::get_time(&tm, "%d%m%y");
if (!stringStream) {
throw std::invalid_argument("invalid date string");
}
std::time_t time = mktime(&tm);

Get the current date and time with milliseconds with only the standard library in C++

I'm trying to print a timestamp like this.
2018-05-24T20:16:07.339271
I don't want to use Boost or any third party libraries. I want to only use the standard library. I'm using Clang 6, so I should be able to use C++ 17 if necessary.
I started looking at chrono and have something like this.
auto now = std::chrono::high_resolution_clock::now();
But, I'm unsure how to get the datetime format that I want from above.
guess your best bet is using std::localtime + std::put_time
The following code uses standard C++ only. The data contained in *loc_time and milli_secs can be used to produce the desired output in local time. To get the output in UTC, use std::gmtime instead of std::localtime.
// get actual system time
const auto now = std::chrono::system_clock::now();
// get seconds since 1970/1/1 00:00:00 UTC
const auto sec_utc = std::chrono::system_clock::to_time_t(now);
// get pointer to tm struct (not thread safe!)
const auto loc_time = std::localtime(&sec_utc);
// get time_point from sec_utc (note: no milliseconds)
const auto now_s = std::chrono::system_clock::from_time_t(sec_utc);
// get milliseconds (difference between now and now_s
const auto milli_secs = std::chrono::duration<double, std::milli>(now - now_s).count() * .001;
standard library c++ does not provide a proper date type, so you can use
structs and functions from c which is inherited on c++. <ctime> header
file need to include in c++ program. i think below code will help you.
time_t now = time(0);
cout<<now<<endl;
tm *lt = localtime(&now);

C++ Standard library that supports time arithmetic

I have a lot of strings that are in the form "HH:MM" and I constantly have to do arithmetic on them (for example add 5 minutes, add 24 hours, etc).
I am wondering if there is any built in class in the standard library that can handle such arithmetic instead of having to manually change the string and handle corner cases?
If you don't have strptime available, and if you have <chrono> and don't want to fool around with the C API, you can use Howard Hinnant's free, open-source, portable datetime library to write helpers to convert to and from std::chrono::minutes.
So convert from string to minutes, do whatever computation you need, and then convert back to string:
#include "date.h"
#include <iostream>
#include <string>
#include <sstream>
std::chrono::minutes
to_minutes(const std::string& s)
{
std::istringstream in{s};
in.exceptions(std::ios::failbit);
std::chrono::minutes m;
in >> date::parse("%H:%M", m);
return m;
}
std::string
to_string(std::chrono::minutes m)
{
return date::format("%H:%M", m);
}
int
main()
{
using namespace std::chrono_literals;
std::cout << to_string(to_minutes("5:47") + 2h + 168min) << '\n';
}
Output:
10:35
This library has been ported to recent versions of VS, gcc and clang.
You can also use this library to work with different precisions quite seamlessly, for example seconds, or even milliseconds, and even mix all the precisions you need together:
std::chrono::milliseconds
to_milliseconds(const std::string& s)
{
std::istringstream in{s};
in.exceptions(std::ios::failbit);
std::chrono::milliseconds ms;
in >> date::parse("%T", ms);
return ms;
}
std::string
to_string(std::chrono::milliseconds ms)
{
return date::format("%T", ms);
}
// ...
std::cout << to_string(to_minutes("5:47") + 2h + 168min +
122s + 465ms + to_milliseconds("1:23:02.123")) << '\n';
Output:
12:00:04.588
Using <ctime> you can convert your HH:MM string to a struct tm as follows:
struct tm time_components;
memset(&time_components, 0, sizeof(struct tm));
time_components.tm_year = 2017;
strptime("01:45", "%H:%M", &time_components);
This assumes you have strptime available. If not, use sscanf or something similar to extract your hour and minute components--I'm sure you're doing this already. I'm setting tm_year there because otherwise it's zero, which is not a valid year for the conversion to time_t later on.
We can easily convert the tm struct back into a HH:MM string using strftime.
char buf[6];
strftime(buf, 6, "%H:%M", &time_components);
printf("time_components before manipulation: %s\n", buf);
But how about manipulating it? My first thought was 'just convert to time_t and add/subtract however many seconds you want'. But time_t isn't guaranteed to be in seconds, so don't do that. Instead, add whatever number of minutes you like to the tm_min component of the tm struct, then call mktime with it, which will correctly handle any values that are outside the normal bounds of hours/minutes/seconds. At that point you have a time_t, which we don't want to mess with, so just convert that back into a tm using localtime. localtime will mirror the conversion that occurred in mktime, so you shouldn't have to worry about time zones and so on. Now you've essentially normalized the tm structure, and your overflowing minutes have been converted to hours, and your overflowing hours have been converted to days.
time_components.tm_min += 65; // Add 65 minutes. Negative values work as expected too!
time_t temp_time = mktime(&time_components);
struct tm* adjusted_time = localtime(&temp_time);
strftime(buf, 6, "%H:%M", adjusted_time);
printf("adjusted_time: %s\n", buf);
That adjusted_time pointer seems to point to an internal tm struct that will change in any subsequent calls to mktime or gmtime, FYI.
There's no doubt this is a fairly hellish approach. If all you need to do is handle minute/hour overflow and simple arithmetic, I'd be tempted to roll my own or look elsewhere.
http://en.cppreference.com/w/cpp/chrono/duration supports the arithmetic and types you want, but I don't think you can construct from strings.
However you can with Boost Chrono. I tend to prefer it for most cases, because if I'm dealing with the problem of hours and minutes, I'll probably end up dealing with dates too in the future.

Convert 32 bit unix timestamp to std::string using std::chrono

I am trying to use std::chrono to make a std::string but running into issues.
Here is the C(-ish) code I want to mimick:
std::uint32_t time_date_stamp = 1484693089;
char date[100];
struct tm *t = gmtime(reinterpret_cast<const time_t*>(&time_date_stamp));
strftime(date, sizeof(date), "%Y-%m-%d %I:%M:%S %p", t);
My starting point is always this std::uint32_t, it is from a data format I do not control.
Sorry I do not have any C++ as a starting point, I do not even know how to make a std::chrono::time_point correctly.
Here's an easy way to do it without dropping down to C's tm using this portable C++11/14 free, open-source, header-only library.
#include "date.h"
#include <iostream>
#include <string>
int
main()
{
std::uint32_t time_date_stamp = 1484693089;
date::sys_seconds tp{std::chrono::seconds{time_date_stamp}};
std::string s = date::format("%Y-%m-%d %I:%M:%S %p", tp);
std::cout << s << '\n';
}
This outputs:
2017-01-17 10:44:49 PM
This does not have the thread-safety issues associated with the ancient gmtime C function.
date::sys_seconds above is a typedef for std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>.
<chrono> is not a library for formatting datetimes into strings. It is useful for converting different time representations (milliseconds to days, etc), adding timestamps together and such.
The only datetime formatting functions in the standard library are the ones inherited from the C standard library, including the std::strftime which you already used in the "C(-ish)" version. EDIT: As pointed out by jaggedSpire, C++11 introduced std::put_time. It provides a convenient way to stream formatted dates with the same API as used by the C functions.
Since std::gmtime (and std::localtime if you were to use that) take their argument as a unix timestamp, you don't need <chrono> to convert the time. It is already in the correct representation. Only the underlying type must be converted from std::uint32_t to std::time_t. That is not implemented portably in your C version.
A portable way to convert the timestamp, with std::put_time based formatting:
std::uint32_t time_date_stamp = 1484693089;
std::time_t temp = time_date_stamp;
std::tm* t = std::gmtime(&temp);
std::stringstream ss; // or if you're going to print, just input directly into the output stream
ss << std::put_time(t, "%Y-%m-%d %I:%M:%S %p");
std::string output = ss.str();

c++ convert time_t to string and back again

I want to convert a time_t to a string and back again.
I'd like to convert the time to a string using ctime().
I can't seem to find anything on google or the time.h header file, any ideas?
Basically what I'm trying to do is store a date in a file, and then read it back so I can use it as a time_t again.
Also, no library references outside of std,mfc.
One more note, this will have to function on Windows xp and above and that's it.
Edit
All I want to do is convert a time_t into a string(I don't care if it's human readable) and then convert it back to a time_t. I'm basically just trying to store the time_t into a file and read it again(but I don't want any code for that, as there will be more info in the file besides a time_t).
You'll have to write your own function to do that. These functions convert any primitive type (or any type which overloads operator<< and/or operator>>) to a string, and viceversa:
template<typename T>
std::string StringUtils::toString(const T &t) {
std::ostringstream oss;
oss << t;
return oss.str();
}
template<typename T>
T StringUtils::fromString( const std::string& s ) {
std::istringstream stream( s );
T t;
stream >> t;
return t;
}
ctime() returns a pointer to a character buffer that uses a specific formatting. You could use sprintf() to parse such a string into its individual portions, store them in a struct tm, and use mktime() to convert that to a time_t.
The time_t Wikipedia article article sheds some light on this. The bottom line is that the type of time_t is not guaranteed in the C specification. Here is an example of what you can try:
Try stringstream.
#include <string>
#include <sstream>
time_t seconds;
time(&seconds);
std::stringstream ss;
ss << seconds;
std::string ts = ss.str();
A nice wrapper around the above technique is Boost's lexical_cast:
#include <boost/lexical_cast.hpp>
#include <string>
time_t t;
time(&t);
std::string ts = boost::lexical_cast<std::string>(seconds);
Wikipedia on time_t:
The time_t datatype is a data type in
the ISO C library defined for storing
system time values. Such values are
returned from the standard time()
library function. This type is a
typedef defined in the standard
header. ISO C defines
time_t as an arithmetic type, but does
not specify any particular type,
range, resolution, or encoding for it.
Also unspecified are the meanings of
arithmetic operations applied to time
values.
Unix and POSIX-compliant systems implement the time_t type as a signed
integer (typically 32 or 64 bits wide)
which represents the number of seconds
since the start of the Unix epoch:
midnight UTC of January 1, 1970 (not
counting leap seconds). Some systems
correctly handle negative time values,
while others do not. Systems using a
32-bit time_t type are susceptible to
the Year 2038 problem.
Convert the time_t to struct tm using gmtime(), then convert the struct tm to plain text (preferably ISO 8601 format) using strftime(). The result will be portable, human readable, and machine readable.
To get back to the time_t, you just parse the string back into a struct tm and use mktime().