I have a date string like so YYYYMMDD HHMMSSFFF. I am trying to use Howard Hinnats date library. Snippet of code is like so,
std::chrono::system_clock::time_point tp;
char date[20] = {0};
std::istringstream ss{date};
ss >> date::parse("%Y%m%d %H%M%S%s", tp);
long ts = (std::chrono::time_point_cast<std::chrono::nanoseconds>(tp)
.time_since_epoch() /
std::chrono::nanoseconds(1));
But this code isn't reading the subsecond FFF. I loooked on the documentation here and it states that %s represents fractional of a second time. An example value for date is 20170110 103648340. But when I output ts I get 0. If you are wondering why I convert to nanoseconds its because I need the date in nanoseconds for other operations.
Use %T, it seems to work. Here is an example:
#include <date/date.h>
int main()
{
std::string dt{ "20190501 113001234" };
dt = dt.insert(11, ":");
dt = dt.insert(14, ":");
dt = dt.insert(17, ".");
// now we have "20190501 11:30:01.234"
std::chrono::system_clock::time_point tp;
std::istringstream ss{ dt };
ss >> date::parse("%Y%m%d %T", tp);
long ts = (std::chrono::time_point_cast<std::chrono::nanoseconds>(tp)
.time_since_epoch() /
std::chrono::nanoseconds(1));
}
You could also parse it this way:
sys_seconds tp;
int ims;
ss >> parse("%Y%m%d %H%M%2S", tp) >> ims;
return tp + milliseconds{ims};
The %2S says: parse as much as 2 chars for the seconds. That leaves the trailing three digits yet to be parsed. Pick those up with a integral parse and convert that integer to milliseconds, and you're good.
This won't work if there are trailing digits after the 3 millisecond digits.
Related
I have a string in the form "20190930_141414" which is the date 2019 09 30 14:14:14. How can I convert this to the unix time stamp in utc?
You can use streams with get_time and mktime to convert it to a time_t object (time since the epoch).
struct std::tm lTM;
std::istringstream lTimestamp( "20190930_141414" );
lTimestamp >> std::get_time = ( &lTM, "%Y%m%d_%H%M%S" );
std::time_t lEpoch = mktime( &lTM );
We have string format UTC Time and we need to convert to Your Current time zone and in string format.
string strUTCTime = "2017-03-17T10:00:00Z";
Need to Convert above value to Local time in same string format.
Like in IST it would be "2017-03-17T15:30:00Z"
Got Solution...
1) Convert String formatted time to time_t
2) use "localtime_s" to Convert utc to local time.
3) use "strftime" to convert local time (struct tm format) to string format.
int main()
{
std::string strUTCTime = "2017-03-17T13:20:00Z";
std::wstring wstrUTCTime = std::wstring(strUTCTime.begin(),strUTCTime.end());
time_t utctime = getEpochTime(wstrUTCTime.c_str());
struct tm tm;
/*Convert UTC TIME To Local TIme*/
localtime_s(&tm, &utctime);
char CharLocalTimeofUTCTime[30];
strftime(CharLocalTimeofUTCTime, 30, "%Y-%m-%dT%H:%M:%SZ", &tm);
string strLocalTimeofUTCTime(CharLocalTimeofUTCTime);
std::cout << "\n\nLocal To UTC Time Conversion:::" << strLocalTimeofUTCTime;
}
std::time_t getEpochTime(const std::wstring& dateTime)
{
/* Standard UTC Format*/
static const std::wstring dateTimeFormat{ L"%Y-%m-%dT%H:%M:%SZ" };
std::wistringstream ss{ dateTime };
std::tm dt;
ss >> std::get_time(&dt, dateTimeFormat.c_str());
/* Convert the tm structure to time_t value and return Epoch. */
return _mkgmtime(&dt);
}
I've got an 8601 format time string like so:
std::string strTime("1601-01-01T00:01:53.537Z");
I want to increment the hour and change its value to
"1601-01-01T01:01:53.537Z"
I think the steps are: convert string to a time object, increment the hour by 1, convert the object back to a string.
Of course, it would be helpful if all the normal time considerations and boundaries were taken into account (such as adding an hour to 11:30 pm will move to the next day, etc...). I've been looking at strftime, strptime, std::get_time and others but have not been able to work it out yet.
I'm using VS2012 on Windows. Thanks.
Some pseudo code to get you started.
char *AddHour(char *dest, size_t size, const char *timestamp) {
Initialize struct tm
Scan timestamp into tm
Check scanning success
Check year range validity
Bring into range acceptable by mktime()
Add hour
Call mktime()
Undo range adjustment made beforehand
Print tm to dest
return dest;
}
Even though mktime() uses local timezone, by keeping the tm_isdst == 0 we can use this for the Z timezone (UTC) for all practical purposes.
Simply scan the string into various parts. Add 1 hour and then reform the string
string --> struct tm tm;
// Add hour
if (++tm.tm_hour >= 24) {
tm.tm_hour = 0;
if (++tm.tm_mday > EOM(tm.tm_year, tm.tm_mon)) {
tm.tm_mday = 1;
if (++tm.tm_mon > 12) {
tm.tm_mon = 1;
tm.tm_year++;
}
}
}
struct tm tm --> string
I have written a C library that parses and formats a ISO 8601 calendar date with time and zone designator in extended format. It's available on Github, c-timestamp.
{
timestamp_t ts;
char *str = "1601-01-01T00:01:53.537Z";
timestamp_parse(str, strlen(str), &ts);
ts.sec += 1*60*60;
timestamp_format(str, strlen(str), &ts);
puts(str);
}
Given a decimal values (seconds and fractions thereof) as a string such as
std::string span = "ssss.nnnn" // ssss is value in seconds, nnnn is fractional seconds
What is the best way to convert it to a timeval structure (val.ts_sec and val.ts_usec) or a timespec structure (tv_sec and tv_nsec).
Most of the answers discuss converting values or are not C++. Some answers get very complex or set up classes which really is too much for this usage.
Obviously sscanf or istringstream can be used if the two values are separated by white space. However, is there a simple way of doing this if they are separated by a "." without looping over the character buffer searching for the "."
EDIT: As Borgleader rightly mentioned, simply reading into a double can incur precision loss if the timestamp becomes sufficiently large (larger than a million, give or take). A numerically stable way is
timeval v;
time_t seconds;
double fraction;
std::istringstream parser(span);
if(parser >> seconds >> std::noskipws >> fraction) {
v.tv_sec = seconds;
v.tv_usec = static_cast<suseconds_t>(fraction * 1e6);
}
Since now the fraction part is guaranteed to be small enough that the mantissa of an ieee-754 double will cover more than 9 decimal digits after the comma. One possible addition is
v.tv_usec = static_cast<suseconds_t>(fraction * 1e6 + 0.5); // rounding to nearest instead of down
depending on your use case.
If you decide to use string class and its functions If the number is always decimal, then I would suggest the following solution:
string span = "1234.123";
span += "000000";
size_t pos = span.find('.');
struct timeval val;
val.tv_sec = stol(span.substr(0,pos));
val.tv_usec = stol(span.substr(pos+1,6));
If the string may also get integer value without the dot '.' character then use
string span = "1234";
size_t pos = span.find('.');
struct timeval val;
val.tv_sec = stol( (pos!=string::npos)? span.substr(0,pos):span );
val.tv_usec = (pos!=string::npos)? stol((span+"000000").substr(pos+1,6)):0;
This solution also uses some c++11.
You can use strtok_s to split a string based off a delimiter. In your case would be "."
#include <iostream>
#include <string>
int main()
{
std::string span = "ssss.nnnn";
char * span1 = (char *)span.c_str();
char * pch = NULL;
char * context;
pch = strtok_s(span1, " .", &context);
while (pch != NULL)
{
printf("%s\n", pch);
pch = strtok_s(NULL, " .", &context);
}
return 0;
}
Output:
ssss
nnnn
I just found this as a possible answer. I would still like to find something else as well.
Parse (split) a string in C++ using string delimiter (standard C++)
strtok allows you to pass in multiple chars as delimiters. I bet if
you passed in ">=" your example string would be split correctly (even
though the > and = are counted as individual delimiters).
EDIT if you don't want to use c_str() to convert from string to char*,
you can use substr and find_first_of to tokenize.
string token, mystring("scott>=tiger");
while(token != mystring){
token = mystring.substr(0,mystring.find_first_of(">="));
mystring = mystring.substr(mystring.find_first_of(">=") + 1);
printf("%s ",token.c_str());
}
Update:
#Wintermute pointed out that the following code snippet would not work because of the possibility of leading zeros.
string span;
int sec;
int usec;
timeval inTime;
sscanf(span.c_str(), "%d.%d", &sec, &usec);
inTime.tv_sec = sec;
inTime.tv_usec = usec;
I have a char[] in YYYYMMDDHHMMSS format.
e.g. 2011052504572
I want to retrieve the year, month, date, hour, minute and second from this char. How do I do that?
NOTE:I cant use any third party dll.
Thanks,
Syd
If you're using the STL then just put the string into a std::string and use the substr method:
std::string dateTime=......;
std::string year=dateTime.substr(0,4);
std::string month=dateTime.substr(4,2);
// etc
// etc
Use string::substr() for this purpose. Example,
string date = "20110524112233";
string year = date.substr(0, 4);
string month = date.substr(4, 2);
string day = date.substr(6, 2);
string hour = date.substr(8, 2);
string minute = date.substr(10, 2);
string second = date.substr(12, 2);
It depends on whether you want to extract the values as text, or convert them to numbers. For getting lots of strings, you can use std::string and substr() as thoroughly illustrated in other answers.
If you want to get numbers that you can then calculate with, then one approach is:
int year, month, day, hour, minute, second;
if (sscanf(input, "%.4d%.2d%.2d%.2d%.2d%.2d",
&year, &month, &day, &hour, &minute, &second) == 6)
{
// all 6 conversions worked... can use the values...
int second_in_day = hour * 3600 + minute * 60 + second;
...
}
Another approach is to use strptime() - if your system has it. It parses a string into a broken-down-time structure:
struct tm tm;
strptime(input, "%Y%m%d%H%M%S", &tm);
// parsed values are in tm.tm_year, tm.tm_mon, tm.tm_mday,
// tm.tm_hour, tm.tm_min, tm.tm_sec
// further, tm_wday has day of week, tm_yday has day in year
// i.e. it actually understands the date, not just chopping up numbers/text
Note: sscanf() and strncpy() are C functions callable from C++, and they're not as safe to use as C++-specific functionality (std::string, std::istringstream) in that small misunderstandings and mistakes in handling the data can lead to not just erroneous results, but program crashes. So, read the manual pages for these things carefully if you use them.
Use strncpy... okay, so if it is not homework, then this is the best way. The others using std::string are wasting resources:
static const char *yyyymmddhhmmss = "20110526101559";
char year[5] = { '\0' };
char month[3] = { '\0' };
char day[3] = { '\0' };
char hour[3] = { '\0' };
char minute[3] = { '\0' };
char second[3] = { '\0' };
strncpy(year, yyyymmddhhmmss, 4);
strncpy(month, &yyyymmddhhmmss[4], 2);
strncpy(day, &yyyymmddhhmmss[6], 2);
strncpy(hour, &yyyymmddhhmmss[8], 2);
strncpy(minute, &yyyymmddhhmmss[10], 2);
strncpy(second, &yyyymmddhhmmss[12], 2);
Since you have the input in the form of a char[] (or char*—for
this use, it comes out to the same thing), the simplest solution is
probably using the two iterator constructors for std::string to creat
a string for each field, e.g.:
std::string year ( date , date + 4 );
std::string month( date + 4, date + 6 );
std::string day ( date + 6, date + 8 );
// ...
If you need the numerical values, boost::lexical_cast can be used,
e.g.:
int extractField( char const* string, int begin, int end )
{
return boost::lexical_cast<int>(
std::string( date + begin, date + end ) );
}
int year = extractField( date, 0, 4 );
int year = extractField( date, 4, 6 );
// ...