I try to convert strings in specific formats to TDateTime using C++Builder 2009:
TDateTime dt, dt2;
TFormatSettings FS, FS2;
UnicodeString datestring = "17/10/2017 13:24:33";
UnicodeString datestring2 = "2017.17.10 13:24:33";
FS.DateSeparator = '/';
FS.ShortDateFormat = "dd/mm/yyyy";
FS.LongTimeFormat = "hh:nn:ss";
FS.TimeSeparator = ':';
FS2.DateSeparator = '.';
FS2.ShortDateFormat = "yyyy.dd.mm";
FS2.LongTimeFormat = "hh:nn:ss";
FS2.TimeSeparator = ':';
try{
dt = StrToDateTime(datestring, FS);
dt2 = StrToDateTime(datestring2,FS2);
}catch(EConvertError& e)
{
int a = 2;
}
Conversion of dt is ok, but conversion of dt2 throws an exception :
''2017.17.10 13:24:33'' is not a valid date and time
Per the documentation of StrToDate() (which also applies to StrToDateTime()):
S must consist of two or three numbers, separated by the character defined by the DateSeparator global variable or its TFormatSettings equivalent. The order for month, day, and year is determined by the ShortDateFormat global variable or its TFormatSettings equivalent--possible combinations are m/d/y, d/m/y, and y/m/d.
The date that is failing is in y/d/m format, which these RTL functions do not support. The date that works is in d/m/y format, which is supported.
Thank you all!
Ok now I know that, this date formats are unsupported by StrToDateTime. Solution of this problem is, convert and merge Windows ShortDateFormat and LongTimeFormat to format string accepted by strptime() from time.h. Then I use strptime() and create TDateTime from tm struct from time.h. I try to link docs but, in docs isn't any strptime func. I find this func in time.h from CodeGear RTL ver 13. I think this is equivalent to strptime
Related
I have a COleDateTime object and I want to parse a date string in the format YYYY-MM-DD.
The string variable, for example, is:
std::string strDate = "2022-07-04";
COleDateTime allows me to use ParseDateTime to parse a string, but I see no way to tell it what format the components of the date string are. In C# I can do such with DateTime.Parse....
Why not just a simple formatted input.
std::stringstream ss(strDate);
int year, month, day;
char dash;
ss >> year >> dash >> month >> dash >> day;
COleDateTime(year, month, day, 0, 0, 0);
Based on the suggestion by #xMRi in the comments I have decided to use:
CString strDutyMeetingDate = CString(tinyxml2::attribute_value(pDutyWeek, "Date").c_str());
int iDay{}, iMonth{}, iYear{};
if(_stscanf_s(strDutyMeetingDate, L"%d-%d-%d", &iYear, &iMonth, &iDay) == 3)
{
const auto datDutyMeetingDate = COleDateTime(iYear, iMonth, iDay, 0, 0, 0);
}
COleDateTime::ParseDateTime uses default parameter LANG_USER_DEFAULT, it can be called as
COleDateTime dt;
dt.ParseDateTime("2022-07-04");
Or
dt.ParseDateTime("2022-07-04", VAR_DATEVALUEONLY, LANG_USER_DEFAULT);
"2022-07-04" uses long date format so it should be safe, because it is clear that the year is at the start, and month is expected to be in the middle. I believe any LCID should return 2022-July-4th (I am 60% sure!)
If the date string was short, it could get confused with MM/DD/YY format, but that's not a problem here.
To make the lcid manually, see the English-US example below, although it should not be necessary in this case.
LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
I have attempted to find an answer to this question but the sources I have found do not properly convert the time. Originally I have the timestamp in a string as I am getting the timestamp from a .json web scraping program but want to convert it to a readable date/time. My latest attempt to do the conversion was to convert the string into a long and the long to time_t and then use strftime() but that does not produce the correct answer.
Here is the code where I converted the string to a long and then to time_t and then used strftime()
std::string timeStampToRead(const time_t rawtime)
{
struct tm *dt;
char buffer [30];
dt = localtime(&rawtime);
strftime(buffer, sizeof(buffer), "%m%d %H%M", dt);
return std::string(buffer);
}
int main()
{
std::string epochT = "1604563859000";
long e = atol(epochT.c_str());
const time_t rawtime = (const time_t)e;
std::string time = timeStamptToRead(rawtime);
return 0;
}
The result of this code is 0808 1703
I also attempted to do something very similar to above but changed timeStampToRead to the following
std::string timeStampToRead(const time_t rawtime)
{
struct tm *dt;
char buffer [30];
dt = localtime(&rawtime);
return asctime(dt);
}
This returns Mon Aug 8 17:03:20 which is also incorrect
The correct answer should be Thursday, November 5, 2020 8:10:59 UTC or Thursday, November 5, 2020 1:10:59 locally (not necessarily in that exact format just the correct month, day, and time is important)
I have tested the outcome of converting the string to a long and that is working correctly so I am thinking the error is either in converting the long to time_t or the process of using the time_t to get a readable format of the time. Of the two options, I think it is more likely the conversion from long to time_t is the issue but can't find another way to do the conversion.
I was hoping there was an easy way to directly take the string and convert it but I cannot find any information on that anywhere so that is why I resulted to converting the string to long and then to time_t. Basically, I can't figure out how to convert a string or long unix epoch timestamp to time_t to convert it to a readable format, or at least that is where I am assuming the error is. If anyone could point me in the right direction to get this conversion code working I would greatly appreciate it.
After some further digging, I have found my error and determined the best route
std::string epochT = "1604563859000";
long e atol(epochT.c_str());
const time_t rawtime = e/1000;
struct tm * dt;
dt = localtime(&rawtime);
std::string readable = asctime(dt);
This code will be inside a for loop that iterates through vectors of strings so epochT will be dependent on the elements in the vector and the current element, but this works and outputs the correct answer of Thu Nov 5 01:10:59 2020 local time.
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.
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);
}
I have a c++ time double that records seconds since 1 Jan 1970.
I want to convert this double and store it in a MySQL database, so here is my code to convert it firstly to a datetime format: *NOTE: ss.time is the double..
/* do the time conversion */
time_t rawtime;
struct tm * timeinfo;
rawtime = (time_t)ss.time;
timeinfo = localtime(&rawtime);
This code converts it to the following format: Thu Jul 24 05:45:07 1947
I then attempt to write it to the MySQL database as follows:
string theQuery = "UPDATE readings SET chng = 1, time = CAST('";
theQuery += boost::lexical_cast<string>(asctime(timeinfo));
theQuery += "' AS DATETIME) WHERE id = 1";
It does not work, but updates the time DATETIME variable in the table with NULL.
Can someone tell me how to do a correct conversion and update the SQL table?
Your c++ double is just a standard Unix timestamp, which MySQL can convert using its FROM_UNIXTIME function:
UDPATE ... SET ... time=FROM_UNIXTIME(rawtime)