QtCustomPlot is plotting different times that what im passing in - c++

I am trying to pass in time values on a range of a single day(9:30 - 4:00), i use an api and libcurl to retrieve a .json for me that gives me "date: 2020-06-04" and "minute: 09:30" and i have them read into a vector like so:
//Reads in data from json(historical data 1 day delayed)
for(Json::Value::ArrayIndex i = 0 ; i != chartData.size(); i++)
{
if(chartData[i].isMember("average"))
{
value.push_back(chartData[i]["average"].asDouble());
time.push_back(chartData[i]["date"].asString());
auto timeDate = QDate::fromString(time[i].c_str(), Qt::ISODate);
minute.push_back(chartData[i]["minute"].asString());
auto minuteDate = QTime::fromString(minute[i].c_str(), "hh:mm");
timeInEpoch.push_back(QDateTime(timeDate, minuteDate).toSecsSinceEpoch());
if((value[i] == 0) && (i != chartData.size() - 1))
{
value[i] = value[i-1];
}
if(value[i] > maxAvg)
{
maxAvg = value[i];
}
else if(value[i] < minAvg)
{
minAvg = value[i];
}
}
}
I then have them converted to a date and time so they should be like "2020-06-04 09:30" and then converted into SecsSinceEpoch().
After that they should be plotted but when they are plotted its like all of the times are shifted hours to the right, like so
Does anyone have any ideas what would be causing this? Thank you in advance!

fromString() will give back you the datetime in local time, while toSecsSinceEpoch() is converting the datetime value to UTC. So either you have to set specifically the timezone of the input string (for example to UTC), or you can use offsetFromUtc() (https://doc.qt.io/qt-5/qdatetime.html#offsetFromUtc) to adjust the result of toSecsSinceEpoch()

Related

Checking a date is in an interval given by partial/periodic dates

I can define an interval with start and end in the format YYMMDD, but they can also be partial/periodic - meaning some elements (day, month or year) can be left blank.
For example, start = " 1115" and end = " 0115" the interval is 15th nov to 15th jan every year.
I want to check if a non-partial date is in the interval.
int compareParial(const char* first, const char* second)
{
for (int i = 0; i < 6; ++i)
{
if (first[i] != ' ' && second[i] != ' ' && first[i] != second[i])
return first[i] > second[i] ? 1 : -1;
}
return 0;
}
bool isDateInInterval(const char* start, const char* end, const char* searchDate)
{
int firstCompare = compareParial(start, searchDate);
int endCompare = compareParial(end, searchDate);
if (firstCompare <= 0 && endCompare >= 0)
return true;
// the date can still be in the interval if the start of the interval is in one year, but end in the next year
bool switched = 0 < compareParial(start, end);
if (switched && (firstCompare <= 0) != (endCompare >= 0))
return true;
return false;
}
int main()
{
cout << boolalpha << isDateInInterval(" 1115", " 0115", "251110") << endl;
return 0;
}
Update: If the dates are reversed check again if searchDate is in.
A problem I notice is what if start and end are reversed but the year is provided. For example: isDateInInterval("200105", "190601", "251110") would be true
C++20 contains types which can represent partial dates: year, month, day, year_month, month_day, etc.2
For example:
auto start = November/15;
auto end = January/15;
By using actual calendrical types, as opposed to strings, the logic you have to deal with can be greatly simplified. A complete year_month_day might be compared against an interval defined by a pair of month_day like this:
bool
compare_partial(std::chrono::month_day start, std::chrono::month_day end,
std::chrono::year_month_day searchDate)
{
using namespace std::chrono;
// Guess that both start and end fall in the same year
auto trial_start = start/searchDate.year();
auto trial_end = end/searchDate.year();
if (trial_start <= trial_end)
{
return trial_start <= searchDate && searchDate <= trial_end;
}
// start/y > end/y
// Otherwise guess that searchDate comes after trail_start:
if (trial_start <= searchDate)
{
// trial_end must be in the next year
trial_end += years{1};
return trial_start <= searchDate && searchDate <= trial_end;
}
// Otherwise searchDate < start/y && start/y > end/y
// trial_start must be in the previous year
trial_start -= years{1};
return trial_start <= searchDate && searchDate <= trial_end;
}
Be forewarned that even this answer is somewhat wrong1. However by using actual calendrical types to do things like add/subtract a year, and do the comparisons, one makes the code cleaner, easier to read, and thus less likely to contain errors.
This answer also only addresses the month_day partial date. You might also have a year_month partial date, or a mixture of month_day and year_month.
std::chrono has no type year_day, and I'm not sure what that would mean anyway. If you have an idea of what it would mean, I have no doubt that C++20 chrono could help you model it.
In any event:
cout << boolalpha << compare_partial(November/15, January/15, 2025y/November/10) << endl;
will output:
false
Even if you don't use C++20 chrono (or it's free preview), modeling this using calendrical types (perhaps of your own making), as opposed to strings, is highly recommended for creating a robust, error-free solution.
1 Expressions such as trial_end += years{1}; aren't guaranteed to be valid dates. For example what if trial_end has the value 2020-02-29. Adding a year to that will give you 2021-02-29. To make this correct, you must decide how you want to handle such situations (e.g. map it to 2021-02-28?).
2 There also exists a free, open-source, header-only preview of this part of C++20 which works with C++11/14/17: https://github.com/HowardHinnant/date
If year is set, and the dates are switched, you must return false, since it is an empty interval.
bool switched = 0 < compareParial(start, end);
if (start[0]==' ' && switched && (firstCompare <= 0) != (endCompare >= 0))
return true;
return false;

How to convert each of my vector strings to a epoch time date

I am using a qvector to store my x values in my qcustom chart and i directly parse a json format in which my x values should be coming from a {date} value in the json format, so i store the {date} as a string but how can i convert all of the time values which are strings into epoch formats to then be represented as dates in my qcustom plot? Below is my code:
//Retrieves json format of data
Json::Value chartData = IEX::stocks::chartYtd(symbolSearchedStd);
//Stores x and y values
QVector<double> closePrice(365);
QVector<string> time(365);
int n = chartData.size();
//Finds max and min for range
float maxAvg = closePrice[0];
float minAvg = closePrice[0];
//Reads in data from json(historical data 1 day delayed)
for(Json::Value::ArrayIndex i = 0 ; i != chartData.size(); i++)
{
if(chartData[i].isMember("close"))
{
if((closePrice[i] == 0) && (i != chartData.size() - 1))
{
closePrice[i] = closePrice[i-1];
}
closePrice[i] = (chartData[i]["close"].asDouble());
time[i] = (chartData[i]["close"].asString());
}
if(closePrice[i] > maxAvg)
{
maxAvg = closePrice[i];
}
else if(closePrice[i] < minAvg)
{
minAvg = closePrice[i];
}
}
JSON dates are often stored in ISO8601 (for Javascript).
Since you use Qt for your data types I think your best option is to use QDateTime::fromString and specify the format to Qt::ISODate
Once you got your QDateTime you can call the method QDateTime::toSecsSinceEpoch
qint64 secsSinceEpoch = QDateTime::fromString(time[i].c_str(), Qt::ISODate).toSecsSinceEpoch();

Best way to run through the entire sheet looking for a text in Google Sheets

I want to create a script that needs to find a certain string and replace it automatically. I've managed to do that, but it takes over 1 minute to run through all rows and columns to find it.
This is what I'm doing now:
for (i=1; i<=rows; i++) {
for (j=1; j<=cols; j++) {
cell = content.getCell(i, j).getValue();
if (content.getCell(i, j).getFormula()) {continue;}
try {
cell = cell.replace (find, replace);
content.getCell(i, j).setValue(cell);
}
catch (err) {continue;}
}
}
The built-in method replaces a text instantly, so I assume there is a better way to approach this. Any ideas?
Instead of retrieving each cell from the sheet one by one, use getDataRange() and getValues() to get all of the data in an array in one call, then perform your search on the array.
Then, depending on if you might have live users editing at the same time your script is run or not, you can either replace the values within the array and re-write the entire sheet with setValues(), or you can use setValue() to update the specific cells with matches one by one as you are currently doing.
See:
https://developers.google.com/apps-script/reference/spreadsheet/sheet#getdatarange
https://developers.google.com/apps-script/reference/spreadsheet/range#getvalues
Try this...
for (i=1; i<=rows; i++) {
for (j=1; j<=cols; j++) {
cellLoc = content.getCell(i, j);
cellValue = cellLoc.getValue();
if (cellLoc.getFormula()) {continue;}
try {
cellValue = cellValue.replace (find, replace);
cellLoc.setValue(cell);
}
catch (err) {continue;}
}
}
I took off every instance of content.getCell(i,j) and instead stored it into cellLoc. That way every time you need content.getCell(i,j), the program doesn't have to find the cell in the content, it can just look what the value of cellLoc is. Let me know if it works and if time has improved...
Well, I don't see much difference between this approach and my first one, but it replaces all matches instantly now:
function findReplace() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getDataRange();
var values = range.getValues();
var i, j, find, replace;
find = "hello";
replace = "bravo!!";
for (i = 0; i < values.length; i++) { //Run through all rows
for (j = 0; j < values[i].length; j++) { //Run through all columns
if (values[i][j] == find){
values[i][j] = replace;
}
}
}
range.setValues(values);
}

Increment the value of a map

need your help and better if you can help me fast. It is very trivial problem but still can't understand what exactly i need to put in one line.
The following code i have
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i));
}
else
{
how can i increment "i" if the key of my statation is already in the map.
}
}
Just briefly what i do , i take the first busrequest go to the second loop take the first station and find the minimum distance. After i go over the second loop , i add that station with minimum distance to my map . After i proceed with all my loops and if there is the same station , i need to increment it , so it means that that station is using two times and etc.
I need the help just give me hint or provide the line that i need to add.
I thank you in advance and waiting for your help.
And I think you meant Min Distance instead of i? Check and let me know.
for (busRequest = apointCollection.begin(); busRequest != apointCollection.end(); busRequest++)
{
double Min = DBL_MAX;
int station = 0;
for (int i = 0; i < newStations; i++)
{
distance = sqrt(pow((apointCollection2[i].x - busRequest->x1), 2) + pow((apointCollection2[i].y - busRequest->y1), 2));
if (distance < Min)
{
Min = distance;
station = i;
}
}
if (people.find(station) == people.end())
{
people.insert(pair<int, int>(station, i)); // here???
}
else
{
// This routine will increment the value if the key already exists. If it doesn't exist it will create it for you
YourMap[YourKey]++;
}
}
In C++ you can directly access a map key without inserting it. C++ will automatically create it with default value.
In your case, if a station is not present in people map and you will access people[station] then people[station] will automatically be set to 0 ( default value of int is 0 ).
So you can just do this:
if (people[station] == 0)
{
// Do something
people[station] = station; // NOTE: i is not accessible here! check ur logic
}
else
{
people[station]++;
}
Also: In your code i cannot be accessed inside IF condition to insert into people map.

Byte length of a MySQL column in C++

I am using C++ to write a program for a MySQL database. I am trying to check a condition by comparing the length of a column (in bytes) to pass/fail. Here is the code:
while (row = mysql_fetch_row(result))
{
lengths = mysql_fetch_lengths(result);
num_rows = mysql_num_rows(result);
for (i = 0; i < num_fields; i++)
{
if (strstr(fields[i].name, "RSSI") != NULL)
{
if (lengths[*row[i]] == ??)
printf("current value is %s \t", row[i]);
}
}
}
So basically what i am trying to do is to look for the string "RSSI" in the columns and if the string is present i want to print that value. The values in each column are 3 bytes in length if present . So how do i check if lengths [*rows[i]] is 3 bytes in length? Thanks
According to the official MySQL documentation mysql_fetch_lengths returns an array of unsigned long with the lengths of the columns of the current row. Although the description isn't clear whether it's in bytes or something else, the example shown clarifies it.
So you should be checking directly to 3.
Also, there are some syntactic and semantic errors, and a possible refactoring in your code, among them the following:
Given the lengths variable is an array with the current rows' lengths, the expression lengths[*row[i]] should just be lengths[i] because i is the index of the current column.
The two ifs inside the for could be merged with the && operator for better readability.
Some variables are not defined or used correctly.
The code would look like this:
// Properly assign a value to fields variable.
fields = mysq_fetch_fields(result);
// Getting the number of fields outside the loop is better.
num_fields = mysql_num_fields(result);
while (row = mysql_fetch_row(result))
{
lengths = mysql_fetch_lengths(row);
for (i = 0; i < num_fields; i++)
if (strstr(fields[i].name, "RSSI") != NULL && lengths[i] == 3)
printf("current value is %s \t", row[i]);
printf("\n"); // For better output print each row in a new line.
}
You should really read the documentation carefully in order to avoid compilation or logic errors for using the wrong function.
I think there is a typo:
dev docs states:
(http://dev.mysql.com/doc/refman/5.0/en/mysql-fetch-lengths.html)
...
num_fields = mysql_num_fields(result);
lengths = mysql_fetch_lengths(result);
for(i = 0; i < num_fields; i++)
NOT
lengths = mysql_fetch_lengths(row);