Convert SQLite Date Field to C++ Time_T - c++

How Do I Convert A SQLite Date in the following format to a C++ Time_T Variable?
YYYY-MM-DD HH:MM:SS

You may wish to read this question, which discusses a few approaches. In particular, if you have access to Boost, you can use <boost/date_time/posix_time/posix_time.hpp> and create a boost::posix_time::ptime object from a string of the format in your question. (See the first answer in that question.)
Alternatively, you can use strptime().
Example:
#include <ctime>
#include <iostream>
std::size_t timestamp_to_seconds(const char* timestamp)
{
std::tm tm_struct;
strptime(timestamp, "%Y-%m-%d %H:%M:%S", &tm_struct);
// You can control daylight savings time if necessary.
tm_struct.tm_isdst = 1;
std::size_t t = std::mktime(&tm_struct);
return t;
}
int main()
{
std::cout << timestamp_to_seconds("2013-07-05 12:34:56") << std::endl;
return 0;
}
Running this example gives the following output:
$ ./a.out
1373042096
$ date -d "2013-07-05 12:34:56" +%s
1373042096
As you can see, it agrees with the date utility. (I assuming you are on a platform with access to strptime.) You may have to be careful when handling daylight savings or timezone info...I had to use tm_struct.tm_isdst = 1 to force recognition of daylight savings and get agreement with date.

time_t is a Unix timestamp (seconds since 1970-01-01), so you have to convert with strftime:
SELECT strftime('%s', '2013-07-05 12:34:56');
The result is a string, but you can read it as an integer value.

Related

Conversion of date from human-readable format to epoch fails

I'd like to create a program that converts the date of a specific human-readable format to epoch.
So far I have the following code the first part of which creates this human-readable format and the second one converts it to epoch.
#include <time.h>
#include <iostream>
#include <ctime>
#include <string>
#include <cstring>
using namespace std;
int main(int argc, char const *argv[])
{
time_t timeNow;
struct tm *ltm = NULL;
time(&timeNow);
ltm = localtime(&timeNow);
char buffer[100];
strftime(buffer, sizeof(buffer), "%c %Z", ltm);
cout << "human readable timestamp is " << buffer << endl;
std::tm tmNow;
memset(&tmNow, 0, sizeof(tmNow));
strptime(buffer, "%c %Z", &tmNow);
cout << "epoch timestamp is " << mktime(&tmNow) << endl;
return 0;
}
So the printouts I get are the following :
human readable timestamp is Thu Sep 16 10:23:06 2021 EEST
epoch timestamp is 1631780586
My time zone is EEST as one can see but the epoch one is wrong because it is one hour ahead. The correct should have been 1631776986. I assume I'm doing wrong something with the local time. I've found third-party libraries examples like boost or poco that do this conversion, but I'd prefer the above conversion to be done by using native C++.
Does anyone see what I'm missing?
The C timing/calendrical API is very difficult to use correctly (which is why C++ is moving away from it).
From the C standard:
The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and negative if the information is not available.
Set tmNow.tm_isdst = -1; prior to the call to mktime.

Unable to convert string with seconds from epoch to date_time

I have a string containing the seconds from the epoch, how do i convert this string to a format
as such -
YEAR-MONTH-DAY HH:MM:SS
Here MONTH should display the month number and DAY gives the day number. Also the time needs to be in 24 hour format.
For example :
2019-06-26 11:14:25
I have tried using strptime but havent been successful in doing so, could someone help me in what I am doing wrong.
This is what i have tried so far
int main()
{
string timee = "12341234534";
const char *ptr = timee.c_str();
struct tm tim;
strptime(ptr, "%S", &tim);
time_t abcd = mktime(&tim);
cout<<abcd;
return 0;
}
Found this code snippet on another stackoverflow link
How to convert a string variable containing time to time_t type in c++?
Your question is a little confusing, but I think I figured out what you want...
If the time is in a time_t compatible format, then just read it directly into a time_t variable, and convert it through std::localtime so you can output it in the wanted format using std::put_time.
Something like
std::time_t time;
std::cin >> time;
std::cout << std::put_time(std::localtime(&time), "%F %T") << '\n';

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.

convert number of seconds since 1970 to DateTime for a specific time zone?

I want to convert seconds since 1970 to datetime for a specific time zone.
I have the time in milisecond and the timezone for a server.
I am getting these values by calling an API. I want to know the year,month, day of that time zone.
int milisecond = 12347586484;
zone = "GMT +8.00";
How can I do that?
Thanks,
Syd
Edit: Will I get the right date if I use gmtime()?
timeinmilisecond + 8*360000;
struct tm *jobCreationtm;
time_t t = (time_t)(timeinmilisecond);
jobCreationtm = gmtime(&t);
Note: I dont want to use third party dlls.
You can set the TZ environment variable to the timezone you want (see the manual page for tzset), and then call localtime.
Something like (now tested):
#include <iostream>
#include <stdlib.h>
#include <time.h>
int main()
{
::putenv("TZ=GMT+8");
time_t t = ::time(0);
tm* x = ::localtime(&t);
char buf[1024];
::strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", x);
std::cout << ::getenv("TZ") << std::endl;
std::cout << "[" << buf << "]" << std::endl;
return 0;
}
Output:
GMT+8
[Thu, 17 Feb 2011 02:22:41 -0800]
What format is the timezone from your server? Is it a GMT offset or formatted like "America\Los Angeles". It's tough w/o a 3rd party library because the result is different based time of year (day light savings) and changes with time (certain counties in Midwest for example change from EST to CST every few years).
Consider installing the ICU library. Given time stamps and a locale (or GMT offset) you can get formatted time / date strings very easily using the TimeZone class.

How to parse date/time from string?

Input: strings with date and optional time. Different representations would be nice but necessary. The strings are user-supplied and can be malformed. Examples:
"2004-03-21 12:45:33" (I consider this the default layout)
"2004/03/21 12:45:33" (optional layout)
"23.09.2004 04:12:21" (german format, optional)
"2003-02-11" (time may be missing)
Needed Output: Seconds since Epoch (1970/01/01 00:00:00) or some other fixed point.
Bonus: Also, reading the UTC-offset of the local system time would be great.
The input is assumed to be a local time on the machine in question.
The output needs to be UTC. System is Linux only (Debian Lenny and Ubuntu needed).
I have tried to use boost/date_time, but must admit I can't wrap my head around the documentation. The following works without the needed conversion from system local time to UTC:
std::string date = "2000-01-01";
boost::posix_time::ptime ptimedate = boost::posix_time::time_from_string(date);
ptimedate += boost::posix_time::hours(Hardcoded_UTC_Offset);// where to get from?
struct tm = boost::posix_time::to_tm(ptimedate);
int64_t ticks = mktime(&mTmTime);
I think boost::date_time can provide the needed UTC offset, but I wouldn't know how.
Although I don't know how to format a single-digit month input in boost, I can do it after the two-digit edit:
#include <iostream>
#include <boost/date_time.hpp>
namespace bt = boost::posix_time;
const std::locale formats[] = {
std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%Y/%m/%d %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%d.%m.%Y %H:%M:%S")),
std::locale(std::locale::classic(),new bt::time_input_facet("%Y-%m-%d"))};
const size_t formats_n = sizeof(formats)/sizeof(formats[0]);
std::time_t pt_to_time_t(const bt::ptime& pt)
{
bt::ptime timet_start(boost::gregorian::date(1970,1,1));
bt::time_duration diff = pt - timet_start;
return diff.ticks()/bt::time_duration::rep_type::ticks_per_second;
}
void seconds_from_epoch(const std::string& s)
{
bt::ptime pt;
for(size_t i=0; i<formats_n; ++i)
{
std::istringstream is(s);
is.imbue(formats[i]);
is >> pt;
if(pt != bt::ptime()) break;
}
std::cout << " ptime is " << pt << '\n';
std::cout << " seconds from epoch are " << pt_to_time_t(pt) << '\n';
}
int main()
{
seconds_from_epoch("2004-03-21 12:45:33");
seconds_from_epoch("2004/03/21 12:45:33");
seconds_from_epoch("23.09.2004 04:12:21");
seconds_from_epoch("2003-02-11");
}
note that the seconds-from-epoch output will be assuming the date was in UTC:
~ $ ./test | head -2
ptime is 2004-Mar-21 12:45:33
seconds from epoch are 1079873133
~ $ date -d #1079873133
Sun Mar 21 07:45:33 EST 2004
You could probably use boost::posix_time::c_time::localtime() from #include <boost/date_time/c_time.hpp> to get this conversion done assuming the input is in the current time zone, but it is rather inconsistent: for me, for example, the result will be different between today and next month, when daylight saving ends.
boost::gregorian has some of the stuff you need without you doing any more work:
using namespace boost::gregorian;
{
// The following date is in ISO 8601 extended format (CCYY-MM-DD)
std::string s("2000-01-01");
date d(from_simple_string(s));
std::cout << to_simple_string(d) << std::endl;
}
There is an example on how to use UTC offsets with boost::posix_time here.
You can provide generation of date and time from custom input string formats using date_input_facet and time_input_facet. There is an I/O tutorial on this page that should help you get going.
If c-style is acceptable: strptime() is the way to go, because you can specify the format and it can take locale in account:
tm brokenTime;
strptime(str.c_str(), "%Y-%m-%d %T", &brokenTime);
time_t sinceEpoch = timegm(brokenTime);
Different layouts will have to be checked with the return value (if possible).
Timezone will have to be added to by checking the system clock (localtime_r() with time(), tm_zone)
the simplest, portable solution is to use scanf:
int year, month, day, hour, minute, second = 0;
int r = 0;
r = scanf ("%d-%d-%d %d:%d:%d", &year, &month, &day,
&hour, &minute, &second);
if (r == 6)
{
printf ("%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute,
second);
}
else
{
r = scanf ("%d/%d/%d %d:%d:%d", &year, &month, &day,
&hour, &minute, &second);
// and so on ...
Initialize a struct tm with the int values and pass it to mktime to get a calendar time as time_t. For timezone conversions, please see information on gmtime.