Problem : I have a plot covering over a 30 year period. At this range, QCPAxisTickerDateTime successsfully generates ticks at 1 year intervals.
My program also has a zoom feature which resets the range. However at a range of about 4 years and setTickCount() set for 50, the tick interval is about 1 month.
QCPAxisTickerDateTime though appears to skip tics for several months, leaving large gaps between ticks. The plot curve itself looks OK.
Root Cause : I debugged the problem and isolated it to qcustomplot.cpp, line 6739,
QCPAxisTickerDateTime::createTickVector(double tickStep, const QCPRange &range).
At line 6756, mTickOrigin = 0, i.e. Jan 1, 1970 0:00 UTC.
However, by default, keyToDateTime(mTickOrigin) translates this to local day/time.
In my case on the US Pacific West Coast, the local time is -8:00 UTC.
So keyToDateTime(mTickOrigin) translates the day/time to Dec 31, 1969 16:00
At line 6762, thisUniformDay = uniformDateTime.date().day(), which is set to 31.
In most cases, tickDateTime is usually the first day of the month.
This results in thisUniformDay - tickDateTime.date().day() > 15, which in turn causes the month to be pushed back to the previous month.
line 6766 tickDateTime = tickDateTime.addMonths(-1);
tickDateTime is then recalculated using the new month and thisUniformDay
line 6767, tickDateTime.setDate(QDate(tickDateTime.date().year(), tickDateTime.date().month(), thisUniformDay));
In most cases, there is no problem.
For example, tickDateTime = August 1, 2012 becomes July 31, 2012
But in some cases tickDateTime is recalculated to a month with less than 31 days
For example, tickDateTime = October 1, 2012 becomes September 31, 2012, which is an invalid date.
Therefore :
line 6768 result[ i ] = dateTimeToKey(tickDateTime); is set to 0
With the resulting tick set to 0, the tick is not displayed.
Work Around: The work around I settled on was to prevent invalid days being used.
I've modified the code, which includes extra variables for the MSVC debugger, starting at line 6739 :
QVector<double> QCPAxisTickerDateTime::createTickVector(double tickStep, const QCPRange &range) { QVector<double> result = QCPAxisTicker::createTickVector(tickStep, range); if (!result.isEmpty()) { if (mDateStrategy == dsUniformTimeInDay) { QDateTime uniformDateTime = keyToDateTime(mTickOrigin); // the time of this datetime will be set for all other ticks, if possible QDateTime tickDateTime; for (int i=0; i<result.size(); ++i) { tickDateTime = keyToDateTime(result.at(i)); tickDateTime.setTime(uniformDateTime.time()); result[i] = dateTimeToKey(tickDateTime); } } else if (mDateStrategy == dsUniformDayInMonth) { QDateTime uniformDateTime = keyToDateTime(mTickOrigin); // this day (in month) and time will be set for all other ticks, if possible uniformDateTime.setTimeZone(QTimeZone(QTimeZone::UTC)); QDateTime tickDateTime; int uniformDateTime_time_hour = uniformDateTime.time().hour(); int uniformDateTime_time_minute = uniformDateTime.time().minute(); int uniformDateTime_time_second = uniformDateTime.time().second(); int uniformDateTime_time_msec = uniformDateTime.time().msec(); int uniformDateTime_date_day = uniformDateTime.date().day(); int uniformDateTime_date_year = uniformDateTime.date().year(); int uniformDateTime_date_month = uniformDateTime.date().month(); int uniformDateTime_date_daysInMonth = uniformDateTime.date().daysInMonth(); int tickDateTime_time_hour; int tickDateTime_time_minute; int tickDateTime_time_second; int tickDateTime_time_msec; int tickDateTime_date_year; int tickDateTime_date_month; int tickDateTime_date_day; int tickDateTime_date_daysInMonth; for (int i=0; i<result.size(); ++i) { tickDateTime = keyToDateTime(result.at(i)); tickDateTime.setTime(uniformDateTime.time()); tickDateTime_date_daysInMonth = tickDateTime.date().daysInMonth(); int thisUniformDay; if(uniformDateTime.date().day() <= tickDateTime.date().daysInMonth()) { thisUniformDay = uniformDateTime.date().day(); } else { thisUniformDay = tickDateTime.date().daysInMonth(); // don't exceed month (e.g. try to set day 31 in February) } tickDateTime_time_hour = tickDateTime.time().hour(); tickDateTime_time_minute = tickDateTime.time().minute(); tickDateTime_time_second = tickDateTime.time().second(); tickDateTime_time_msec = tickDateTime.time().msec(); tickDateTime_date_year = tickDateTime.date().year(); tickDateTime_date_month = tickDateTime.date().month(); tickDateTime_date_day = tickDateTime.date().day(); //if (thisUniformDay - tickDateTime.date().day() < -15) // with leap years involved, date month may jump backwards or forwards, and needs to be corrected before setting day if (thisUniformDay - tickDateTime_date_day < -15) // with leap years involved, date month may jump backwards or forwards, and needs to be corrected before setting day tickDateTime = tickDateTime.addMonths(1); else if (thisUniformDay - tickDateTime_date_day > 15) // with leap years involved, date month may jump backwards or forwards, and needs to be corrected before setting day tickDateTime = tickDateTime.addMonths(-1); tickDateTime_time_hour = tickDateTime.time().hour(); tickDateTime_time_minute = tickDateTime.time().minute(); tickDateTime_time_second = tickDateTime.time().second(); tickDateTime_time_msec = tickDateTime.time().msec(); tickDateTime_date_year = tickDateTime.date().year(); tickDateTime_date_month = tickDateTime.date().month(); tickDateTime_date_day = tickDateTime.date().day(); bool tickDateTime_date_leap_year = ((tickDateTime_date_year % 4) == 0); if ( (tickDateTime_date_month == 2) && tickDateTime_date_leap_year && ((tickDateTime_date_day > 29) || (thisUniformDay > 29))) { tickDateTime_date_day = 29; tickDateTime.setDate(QDate(tickDateTime_date_year, tickDateTime_date_month, tickDateTime_date_day)); } else if ((tickDateTime_date_month == 2) && ((tickDateTime_date_day > 28) || (thisUniformDay > 28))) { tickDateTime_date_day = 28; tickDateTime.setDate(QDate(tickDateTime_date_year, tickDateTime_date_month, tickDateTime_date_day)); } else if ( ((tickDateTime_date_month == 4) || (tickDateTime_date_month == 6)|| (tickDateTime_date_month == 9)|| (tickDateTime_date_month == 11)) && ((tickDateTime_date_day > 28) || (thisUniformDay > 30))) { tickDateTime_date_day = 30; tickDateTime.setDate(QDate(tickDateTime_date_year, tickDateTime_date_month, tickDateTime_date_day)); } else { tickDateTime.setDate(QDate(tickDateTime_date_year, tickDateTime_date_month, thisUniformDay)); } //tickDateTime.setDate(QDate(tickDateTime.date().year(), tickDateTime.date().month(), thisUniformDay)); tickDateTime_time_hour = tickDateTime.time().hour(); tickDateTime_time_minute = tickDateTime.time().minute(); tickDateTime_time_second = tickDateTime.time().second(); tickDateTime_time_msec = tickDateTime.time().msec(); tickDateTime_date_year = tickDateTime.date().year(); tickDateTime_date_month = tickDateTime.date().month(); tickDateTime_date_day = tickDateTime.date().day(); result[i] = dateTimeToKey(tickDateTime); } } } return result; }