How to parse date/time from string? - c++

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.

Related

How to get the current time and date C++ UTC time not local

I would like to know how I can get the UTC time or any other timezone (NOT just local time) in C++ Linux.
I would like to do something like: int Minutes = time.now(Minutes) to get and store the year, month, day, hour, minute and second at that exact time.
How I can do so?
I will need to repeat this process many time; I want to know the newest and best way to do so.
You are looking for the gmtime function in the time.h library, which give you UTC time. Here's an example:
#include <stdio.h> /* printf */
#include <time.h> /* time_t, struct tm, time, gmtime */
int main ()
{
time_t rawtime;
struct tm * ptm;
// Get number of seconds since 00:00 UTC Jan, 1, 1970 and store in rawtime
time ( &rawtime );
// UTC struct tm
ptm = gmtime ( &rawtime );
// print current time in a formatted way
printf ("UTC time: %2d:%02d\n", ptm->tm_hour, ptm->tm_min);
return 0;
}
Look at these sources:
https://www.cplusplus.com/reference/ctime/gmtime/
https://www.cplusplus.com/reference/ctime/time_t/
You can use system command in c++ if you want linux oriented solution
e.g.
#include <iostream>
#include <sstream> //for stringstream function to store date and time
using namespace std;
int main()
{
const char *date_now = "date -u"; //linux command to get UTC time is "date -u"
stringstream s;
s << system(date_now); //to store output of system("date_now") to s;
cout << s.str() << endl; //to print the string in s
return 0;
}
Check out "date --help" for more date and time related commands in linux terminal.

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

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.

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.