How to achieve this specific datetime format using boost? - c++

I want to format a datetime like this:
YYYYMMDD_HHMMSS
eg, 4 digit year, followed by 2 digit months, followed by 2 digit day, underscore, 24-hour hour, 2 digit minutes, 2 digit seconds.
e.g.: 16th of February 2011, 8:05 am and 2 seconds would be:
20110216_080502
What format string should I use in the following code to achieve this? (And, if necessary, what code changes are needed):
//...#includes, namespace usings...
ptime now = second_clock::universal_time();
wstringstream ss;
time_facet *facet = new time_facet("???"); //what goes here?
ss.imbue(locale(cout.getloc(), facet));
ss << now;
wstring datetimestring = ss.str();
Here are some strings I've tried so far:
%Y%m%d_%H%M%S : "2011-Feb-16 16:51:16"
%Y%m%d : "2011-Feb-16"
%H%M%S : "16:51:16"
Here's another one:
%Y : "2011-Feb-16 16:51:16" huh??

I believe you need to use wtime_facet, not time_facet. See the working program I posted on your other question.

From date/time facet format flags:
"%Y%m%d_%H%M%S"

time_facet *facet = new time_facet("%Y%m%d_%H%M%S");

Related

How to convert string ( Thu Oct 3 18:45:10 2019) to time_t format in cpp? [duplicate]

This question already has an answer here:
C++ Converting A String to a time_t variable
(1 answer)
Closed 3 years ago.
Stored that time format in some other file. And retrieve this as string. How to change this to time format again.
You can use strptime to parse the time, and then mktime to convert it to a time_t
const char *time_details = "Thu Oct 3 18:45:10 2019";
struct tm tm;
// %a or %A
// The weekday name according to the current locale, in abbreviated form or the full name.
// %b or %B or %h
// The month name according to the current locale, in abbreviated form or the full name.
// the field descriptors must match the string format you are providing.
strptime(time_details, "%a %b %d %H:%M:%S %Y", &tm);
time_t t = mktime(&tm);
You can find the detailed usage of input field descriptors at strptime(3)

How can I get several characters from a std::string

I want to name a file according to the date and the time it was created. I'm using this code to get the date and time:
auto time = std::chrono::system_clock::now();
std::time_t end_time = chrono::system_clock::to_time_t(time);
std::string finaltime = std::ctime(&end_time);
I now want to eliminate all spaces and informations that I dont need from the finaltime-string . For this purpose I found out which characters I need. I need all except 11, 14, 17 (counter started at 0 for the first character).
In python there is a very simple way to do something like that, if you need all characters from 2 to 5 you can say mystring[2:5]. Is there somethig similar in c++ or is there another way to delete the chars I need
use the substr(a, b) function
std::string str2 = finaltime.substr (3,5); // 12:00

String tokenisation, split by token not separator

I see how to tokenise a string in the traditional manner (i.e. this answer here How do I tokenize a string in C++?) but how can I split a string by its tokens, also including them?
For example given a date/time picture such as yyyy\MMM\dd HH:mm:ss, I would like to split into an array with the following:
"yyyy", "\", "MMM", "\", "dd", " " , "HH", ":", "mm", ":", "ss"
The "tokens" are yyyy, MMM, dd, HH, mm, ss in this example. I don't know what the separators are, only what the tokens are. The separators need to appear in the final result however. The complete list of tokens is:
"yyyy" // – four-digit year, e.g. 1996
"yy" // – two-digit year, e.g. 96
"MMMM" // – month spelled out in full, e.g. April
"MMM" // – three-letter abbreviation for month, e.g. Apr
"MM" // – two-digit month, e.g. 04
"M" // – one-digit month for months below 10, e.g. 4
"dd" // – two-digit day, e.g. 02
"d" // – one-digit day for days below 10, e.g. 2
"ss" // - two digit second
"s" // - one-digit second for seconds below 10
"mm" // - two digit minute
"m" // - one-digit minute for minutes below 10
"tt" // - AM/PM designator
"t" // - first character of AM/PM designator
"hh" // - 12 hour two-digit for hours below 10
"h" // - 12 hour one-digit for hours below 10
"HH" // - 24 hour two-digit for hours below 10
"H" // - 24 hour one-digit for hours below 10
I've noticed the standard library std::string isn't very strong on parsing and tokenising and I can't use boost. Is there a tight, idiomatic solution? I'd hate to break out a C-style algorithm for doing this. Performance isn't a consideration.
Perhaps http://www.cplusplus.com/reference/cstring/strtok/ is what you're looking for, with a useful example.
However, it eats the delimiters. You could solve that problem with comparing the base pointer and the resulting string, moving forward by the string length.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <sstream>
int main()
{
char data[] = "yyyy\\MMM\\dd HH:mm:ss";
std::vector<std::string> tokens;
char* pch = strtok (data,"\\:"); // pch holds 'yyyy'
while (pch != NULL)
{
tokens.push_back(pch);
int delimeterIndex = static_cast<int>(pch - data + strlen(pch)); // delimeter index: 4, 8, ...
std::stringstream ss;
ss << delimeterIndex;
tokens.push_back(ss.str());
pch = strtok (NULL,"\\:"); // pch holds 'MMM', 'dd', ...
}
for (const auto& token : tokens)
{
std::cout << token << ", ";
}
}
This gives output of:
yyyy, 4, MMM, 8, dd HH, 14, mm, 17, ss, 20,

Decompose an ISO8601 format time stamp with regular expressions

I want to extract the minutes and seconds from an time stamp of ISO8601 format. I made some tries with regexp but I have no experience on that.
Could you please help me on this?
Examples:
PT1M46S --> 1 minute, 46 seconds
PT36S --> 36 seconds
Thanks!
getPart = #(str, c) str2double(['0' regexp(str, ['\d*(?=' c ')'], 'match', 'once')]);
str = 'PT36S';
seconds = getPart(str, 'S');
minutes = getPart(str, 'M');
hours = getPart(str, 'H');
This looks for character c, finds the digits behind it and converts them to a double. It adds character '0' in the beginning because if regexp can't find a match it returns an empty string. Adding this converts empty strings to zero while not affecting other numbers. If you want to restrict it to the parts after PT, you can remove that from original string using
str = regexprep(str, '^.*PT', '');
Use datevec to turn strings representing hours, minutes etc into corresponding numeric values. See "help datestr" to understand rules for symbols used in second input to datevec, ie. the format string. Here's how you can convert the two examples given, I leave it to you to extend it to cover the entire format.
str = 'PT36S';
str = strrep(str, 'PT', ''); % PT have to go.
if ~ismember('M', str)
% To use a single format string, we must write zero minutes if none are there already
str = ['00M', str];
end
% Date string cannot contain characters y,m,d,H,M or S, so remove these
str = strrep(str, 'S', ' ');
str = strrep(str, 'M', ' ');
% Call datevec with appropriate format string
[~, ~, ~, ~, min, sec] = datevec(str, 'MM SS')
You can extend this to manage hours, days etc by including additional if loops similar to that above. I am not familiar with this standard beyond the examples given so let me know if it's not as simple as that.

Matching algorithm or regular expression?

I have a huge log file with different types of string rows, and I need to extract data in a "smart" way from these.
Sample snippet:
2011-03-05 node32_three INFO stack trace, at empty string asfa 11120023
--- - MON 23 02 2011 ERROR stack trace NONE      
For instance, what is the best way to extract the date from each row, independent of date format?
You could make a regex for different formats like so:
(fmt1)|(fmt2)|....
Where fmt1, fmt2 etc are the individual regexes, for yor example
(20\d\d-[01]\d-[0123]\d)|((?MON|TUE|WED|THU|FRI|SAT|SUN) [0123]\d [01]\d 20\d\d)
Note that to prevent the chance to match arbitrary numbers I restricted year, month and day numbers accordingly. For example, a day number cannot start with 4, neither can a month number start with 2.
This gives the following pseudo code:
// remember that you need to double each backslash when writing the
// pattern in string form
Pattern p = Pattern.compile("..."); // compile once and for all
String s;
for each line
s = current input line;
Matcher m = p.matcher(s);
if (m.find()) {
String d = m.group(); // d is the string that matched
....
}
Each individual date pattern is written in () to make it possible to find out what format we had, like so:
int fmt = 0;
// each (fmt) is a group, numbered starting with 1 from left to right
for (int i = 1; fmt == 0 && i <= total number of different formats; i++)
if (m.group(i) != null) fmt = i;
For this to work, inner (regex) groups must be written (?regex) so that they do not count as capture-groups, look at updated example.
If you use Java, you may want to have a look at Joda time. Also, read this question and related answers. I think Joda DateTimeFormat should give you all the flexibility that you need to parse the various date/time format of your log file.
A quick example:
String dateString = "2011-04-18 10:41:33";
DateTimeFormatter formatter =
DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dateTime = formatter.parseDateTime(dateString);
Just define a String[] for the formats of you date/time, and pass each element to DateTimeFormat to get the corresponding DateTimeFormatter. You can use regex just separate date strings from other stuff in the log lines, and then you can use the various DateTimeFormatters to try and parse them.