I have a date represented as string in the format "2012-10-28" and I want to convert it in the string format of "28/10/2012". Is this possible in C++ MS Visual Studio using a predefined function ?
This will do it:
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
string format_date(string s)
{
char buf[11];
int a, b, c;
sscanf(s.c_str(), "%d-%d-%d", &a, &b, &c);
sprintf(buf, "%02d/%02d/%d", c, b, a);
return buf;
}
int main()
{
cout << format_date("2012-09-28") << endl;
}
I worked it out that way:
Use sscan_f to break date into year, month and day.
Create struct tm with the data above.
Use strftime to convert from tm to string with the desired format.
Please look at COleDateTime::ParseDateTime.
If do not want to use COleDateTime the implementation of the ParseDateTime is just a thin wrapper around VarDateFromStr.
strptime unfortunately does not exist in windows. Seek help here: strptime() equivalent on Windows?
You can then write the date using strftime.
in Qt (some embedded system does not support new timer class yet, so here)
I here just give the idea how to convert a string without much mumbo jumbo.
the timer class has the epoch function anyway.
QString fromSecsSinceEpoch(qint64 epoch)
{
QTextStream ts;
time_t result = epoch;//std::time(NULL);
//std::cout << std::asctime(std::localtime(&result))
// << result << " seconds since the Epoch\n";
ts << asctime(gmtime(&result));
return ts.readAll();
}
qint64 toSecsSinceEpoch(QString sDate)//Mon Nov 25 00:45:23 2013
{
QHash <QString,int> monthNames;
monthNames.insert("Jan",0);
monthNames.insert("Feb",1);
monthNames.insert("Mar",2);
monthNames.insert("Apr",3);
monthNames.insert("May",4);
monthNames.insert("Jun",5);
monthNames.insert("Jul",6);
monthNames.insert("Aug",7);
monthNames.insert("Sep",8);
monthNames.insert("Oct",9);
monthNames.insert("Nov",10);
monthNames.insert("Dec",11);
QStringList l_date = sDate.split(" ");
if (l_date.count() != 5)
{
return 0;//has to be 5 cuz Mon Nov 25 00:45:23 2013
}
QStringList l_time = l_date[3].split(":");
if (l_time.count() != 3)
{
return 0;//has to be 3 cuz 00:45:23
}
struct tm result;
result.tm_mday=l_date[2].toInt();
result.tm_mon=monthNames[l_date[1]];
result.tm_year=l_date[4].toInt()-1900;;
result.tm_hour=l_time[0].toInt();
result.tm_min=l_time[1].toInt();
result.tm_sec=l_time[2].toInt();
time_t timeEpoch=mktime(&result);
qDebug()<<"epochhhh :"<<timeEpoch;
return timeEpoch;
}
Related
I've a std::chrono::milliseconds representing epoch unix time in milliseconds. I need to convert it into a string that follows the ISO 8601 format, like 2020-02-25T00:02:43.000Z.
Using date library I was able to parse it, with following GetMillisecondsFromISO5601String method:
#include "TimeConversion.hpp"
#include <date/date.h>
using std::string;
using std::string_view;
using std::chrono::milliseconds;
string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) {
std::stringstream ss;
date::to_stream(ss, "%FT%T%z", ms);
return ss.str();
}
milliseconds TimeConversion::GetMillisecondsFromISO5601String(string_view s) {
std::istringstream in{ std::move(string(s)) };
in.exceptions(std::ios::failbit);
date::sys_time<milliseconds> tp;
if (*s.rbegin() == 'z') {
in >> date::parse("%FT%T%z", tp);
}
else if (*s.rbegin() == 'Z') {
in >> date::parse("%FT%T%Z", tp);
}
else {
in >> date::parse("%FT%T%", tp);
}
return tp.time_since_epoch();
}
How can I do the inverse? I was trying to_stream in the GetISO8601TimeStringFrom method as you can see but without any results (it returns me an empty string).
The problem is that you're treating a time duration (milliseconds) as a time_point (time_point<system_clock, milliseconds>). All you need to do is convert the duration to time_point with explicit conversion syntax. The date lib has a convenience type alias for this type: sys_time<milliseconds>:
string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) {
date::sys_time<milliseconds> tp{ms};
// continue using tp ...
You may also use the more convenient format function in place of to_stream:
string TimeConversion::GetISO8601TimeStringFrom(const milliseconds& ms) {
return date::format("%FT%T%z", date::sys_time<milliseconds>{ms});
}
In one of my utility programs, localtime() is used to covert unix timestamps to human readable date time.
The following code used to work in VS2010 while it fails to work in VS2019:
std::string sec = "1234123456";
int nsec = atoi(sec.c_str());
tm* t = localtime((time_t*)&nsec); // return null pointer
If I change the code in the following way, it will work also in VS2019:
std::string sec = "1234123456";
int nsec = atoi(sec.c_str());
time_t tt = nsec;
tm* t = localtime(&tt); // works
I have no idea why the additional int to time_t conversion is needed, any suggestion would be appreciated.
On most (if not all) modern compilers time_t is now a 64-bit integer. (time_t*)&nsec is therefore undefined behaviour as you are casting from one pointer type to a different one.
You fixed version is well defined but you will run into the reason that time_t is now 64-bit as 32-bit numbers will only work for times up to 2038 (assuming time_t is using the Unix epoch).
Unfortunately c++ doesn't provide a simple method for converting a string to time_t, to do it properly you'd need something like this:
#include <iostream>
#include <charconv>
time_t str_to_time_t(const std::string& str)
{
auto begin = str.c_str();
auto end = begin + str.size();
time_t time;
auto result = std::from_chars(begin, end, time);
if (result.ec != std::errc())
{
throw std::system_error(std::make_error_code(result.ec));
}
if (result.ptr != end)
{
throw std::invalid_argument("invalid time_t string");
}
return time;
}
int main()
{
std::string sec = "1234123456";
auto nsec = str_to_time_t(sec);
tm* t = localtime((time_t*)&nsec);
if (t)
{
std::cout << "parsed OK\n";
}
}
I have the following function that for the life of me I cannot get to return a string:
void GetDateTimeString()
{
auto t1 = std::time(nullptr);
auto tm1 = *std::localtime(&t1);
stringstream dattim1;
cout << put_time(&tm1, "%Y-%m-%d_%H-%M-%S");
}
I have tried this in vain, which crashes the program:
std::string GetDateTimeString()
{
time_t t1 = std::time(nullptr);
tm tm1 = *std::localtime(&t1);
stringstream dattim1;
dattim1 << put_time(&tm1, "%Y-%m-%d_%H-%M-%S");
std::string returnValue = dattim1.str();
return returnValue;
}
In the end I want to call it like this:
string dateString = GetDateTimeString();
What am I doing wrong?
The first version of your function is of type void so it does not return anything. cout will just print the time e.g. to the console.
In the second function you try to use put_time again, but that is the wrong function for your demand. instead use strftime to copy the time to a char-array and then to a string:
std::string GetDateTimeString()
{
time_t t1 = std::time(nullptr);
tm tm1 = *std::localtime(&t1);
char buffer[80];
strftime(buffer, sizeof(buffer), "%Y-%m-%d_%H-%M-%S", &tm1);
std::string returnValue(buffer);
return returnValue;
}
Since the code works in a simple test, but crashes in your application, I would suggest you look at using localtime_s or localtime_r (system dependent) instead of localtime, which returns a pointer to a static buffer, and is not threadsafe.
I am writing a application which needs the possibility to compare two dates. This is what I have so far:
struct entry {
string text;
string date; // format: dd.mm.yyyy
bool finished;
};
string addNulls(int number, int cols) {
string num = to_string(number);
if (num.size() < cols) {
int count = cols - num.size();
for (int i = 0; i < count; i++) {
num = "0" + num;
}
}
return num;
}
// [...]
entry e = {"here is some text", "21.03.2019", false};
int day2 = atoi(e.date.substr(0, 2).c_str());
int month2 = atoi(e.date.substr(3, 2).c_str());
int year2 = atoi(e.date.substr(6, 4).c_str());
time_t t = time(0);
struct tm * now = localtime(&t);
string date1 = e.date.substr(6, 4) + "-" + e.date.substr(3, 2) + "-" + e.date.substr(0, 2) + " 00:00:00";
string date2 = addNulls(now->tm_year, 4) + "-" + addNulls(now->tm_mon, 2) + "-" + addNulls(now->tm_mday, 2) + " 00:00:00";
if(date2 > date1) {
// do something
}
the code gets an "entry" struct which contains a date. Than the code compares the date with the actual time. The problem is, it does not work! I run some tests with some example content, but the result (date2 > date1) returns false.
Why?
I read this: C++ compare to string dates
I'm not actually answering your question. However I am offering you a solution. Have you considered a date/time library? Boost datetime is very popular.
If you are compiling in C++11 or later, I recommend this date time library, as it is header-only (eliminating the need to link to a library such as boost), and in my opinion, it has cleaner syntax (that is a very subjective and biased viewpoint).
This latter library builds on the C++11 <chrono> library. Here is your example code using this library:
#include "date.h"
#include <iostream>
#include <string>
struct entry {
std::string text;
date::year_month_day date;
bool finished;
};
int
main()
{
entry e = {"here is some text", date::day(21)/3/2019, false};
auto day2 = e.date.day();
auto month2 = e.date.month();
auto year2 = e.date.year();
auto t = std::chrono::system_clock::now();
auto date1 = date::sys_days{e.date};
auto date2 = t;
if (date2 > date1)
std::cout << "It is past " << e.date << '\n';
else
std::cout << "It is not past " << e.date << '\n';
}
Which currently outputs:
It is not past 2019-03-21
In C++14, the chrono literals make specifying literal times very compact:
using namespace std::literals;
auto date1 = date::sys_days{e.date} + 0h + 0min + 0s;
Also on the subject of literals, you can make the construction of entry slightly more compact if you drop in a using namespace date;:
entry e = {"here is some text", 21_d/3/2019, false};
Reusing a date or datetime class, or even creating your own, is easier than trying to use a string to hold a date. Additionally you get the type-safety of not accidentally adding a string to a date, when you meant to add a time duration to a time point.
Why don't you use strptime to parse your date strings, convert them to epoch times and then compare?
#include <time.h>
char *
strptime(const char *restrict buf, const char *restrict format,
struct tm *restrict tm);
I have the milliseconds since epoch (windows/gregorian) for a specific time in long long int and would like to convert it to human time such as yy-mm-dd-hh-mm-ss-milli. (My platform: Windows 7, 64bit)
Unfortunately, all solutions I have found so far can't deal with the milli second (long long int) part.
C++11 API is incomplete, so I had to invent a bicycle:
static long getTs() {
struct timeval tp;
gettimeofday(&tp, NULL);
long int ms = tp.tv_sec * 1000 + tp.tv_usec / 1000;
return ms;
}
static string format(long ts,string fmt,int cutBack=0){
time_t tt = ts/1000;
int microsec = ts%1000;
struct std::tm * ptm = std::localtime(&tt);
string fmtms=std::regex_replace(fmt, std::regex("%ms"), to_string(microsec));
std::stringstream ss;
ss << std::put_time(ptm, fmtms.c_str());
string ret = ss.str();
return ret.substr(0,ret.size()-cutBack);
}
std::cout << CommonUtils::format(CommonUtils::getTs(), "%Y-%m-%dT%H:%M:%S.%ms%Z")<<endl;
gives me: 2020-01-24T11:55:14.375+07, cutBack parameter is optional, it specifies how many characters to remove from the output string. It is useful when timezone format like +0700 is to long, and you just need +07.
Basically, you should be able to take whatever it is that you have that writes the formatted time without milliseconds, and add the remainder of the division of the number of millisconds by 1000. This should work because leap time is always an integer number of seconds.
Assuming C++11, you can try this:
#include <chrono>
#include <iomanip>
using namespace std;
using namespace chrono;
long long int milliSecondsSinceEpoch = ... // this is your starting point
const auto durationSinceEpoch = std::chrono::milliseconds(milliSecondsSinceEpoch);
const time_point<system_clock> tp_after_duration(durationSinceEpoch);
time_t time_after_duration = system_clock::to_time_t(tp_after_duration);
std::tm* formattedTime = std::localtime(&time_after_duration);
long long int milliseconds_remainder = milliSecondsSinceEpoch % 1000;
cout <<put_time(std::localtime(&time_after_duration), "%y-%m-%d-%H-%M-%S-") << milliseconds_remainder << endl;