Conversion of date from human-readable format to epoch fails - c++

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.

Related

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 );

Convert SQLite Date Field to C++ Time_T

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.

Cross Platform way to get the time of day?

Is there a simple way to get time time of day (17:30, 01:20...etc) that would work on iOS, OSX, Linux and Windows?
If not is there a Windows way and a posix way or something?
Thanks
You can retrieve the time with time_t now = time(NULL); or time(&now);
You then usually convert to local time with struct tm *tm_now = localtime(&now);. A struct tm contains fields for the year, month, day, day of week, hour, minute, and second. If you want to produce printable output, strftime supports that directly.
Both of these are in the C and C++ standards, so they are available on most normal platforms.
If you really only care about C++, you can use std::put_time, which is similar to strftime, but a little bit simpler to use for the typical case of writing the output to a stream.
with C++11 you can use
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t t = std::time(nullptr);
std::cout << "UTC: " << std::put_time(std::gmtime(&t), "%c %Z") << '\n'
<< "local: " << std::put_time(std::localtime(&t), "%c %Z") << '\n';
}
which should produce on (any platform)
UTC: Wed Dec 28 11:47:03 2011 GMT
local: Wed Dec 28 06:47:03 2011 EST
though std::put_time() (from iomanip) is not yet implemented in, say, gcc 4.7.0.

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.