- more work to avoid QDate. helper::date is improved.
This commit is contained in:
parent
8c13869e9c
commit
fbbb98cb8d
@ -13,12 +13,12 @@
|
|||||||
|
|
||||||
char* __strlcpy_chk (char* dest, const char* src, int len, int destcapacity)
|
char* __strlcpy_chk (char* dest, const char* src, int len, int destcapacity)
|
||||||
{
|
{
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* __strlcat_chk (char* dest, const char* src, int len, int destcapacity)
|
char* __strlcat_chk (char* dest, const char* src, int len, int destcapacity)
|
||||||
{
|
{
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -62,11 +62,16 @@ time_t date::toTimestamp() const
|
|||||||
return mktime(&t);
|
return mktime(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
date date::fromTimestamp(time_t timestamp)
|
date date::fromTimestamp(time_t timestamp, int options)
|
||||||
{
|
{
|
||||||
struct tm t;
|
struct tm t;
|
||||||
memset(&t, 0, sizeof t);
|
memset(&t, 0, sizeof t);
|
||||||
t = *localtime(×tamp);
|
switch (options)
|
||||||
|
{
|
||||||
|
case To_GmtTime: t = *gmtime(×tamp); break;
|
||||||
|
case To_LocalTime: t = *localtime(×tamp); break;
|
||||||
|
}
|
||||||
|
|
||||||
date r;
|
date r;
|
||||||
r.mDay = t.tm_mday;
|
r.mDay = t.tm_mday;
|
||||||
r.mMonth = t.tm_mon + 1;
|
r.mMonth = t.tm_mon + 1;
|
||||||
@ -74,6 +79,31 @@ date date::fromTimestamp(time_t timestamp)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int date::daysInMonth(int y, int m)
|
||||||
|
{
|
||||||
|
switch (m)
|
||||||
|
{
|
||||||
|
case 2:
|
||||||
|
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
|
||||||
|
return 29;
|
||||||
|
else
|
||||||
|
return 28;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
case 5:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
case 10:
|
||||||
|
case 12:
|
||||||
|
return 31;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string chrono::secondsToDisplay(int seconds, bool showSeconds)
|
std::string chrono::secondsToDisplay(int seconds, bool showSeconds)
|
||||||
{
|
{
|
||||||
int hours = seconds / 3600;
|
int hours = seconds / 3600;
|
||||||
@ -98,7 +128,8 @@ std::string chrono::timeToStr(time_t timestamp)
|
|||||||
std::string chrono::timeToLocalStr(time_t timestamp)
|
std::string chrono::timeToLocalStr(time_t timestamp)
|
||||||
{
|
{
|
||||||
char buf[128];
|
char buf[128];
|
||||||
strftime(buf, sizeof buf, "%FT%TZ", localtime(×tamp));
|
struct tm t = localtime(timestamp);
|
||||||
|
strftime(buf, sizeof buf, "%FT%TZ", &t);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,8 +23,22 @@ namespace helper
|
|||||||
|
|
||||||
// Timestamp is always UTC! But date is always local!
|
// Timestamp is always UTC! But date is always local!
|
||||||
time_t toTimestamp() const;
|
time_t toTimestamp() const;
|
||||||
static date fromTimestamp(time_t timestamp);
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
To_LocalTime,
|
||||||
|
To_GmtTime
|
||||||
};
|
};
|
||||||
|
static date fromTimestamp(time_t timestamp, int options);
|
||||||
|
static date today();
|
||||||
|
static date fromTm(struct tm& t);
|
||||||
|
static int daysInMonth(int y, int m);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator < (const date& lhs, const date& rhs);
|
||||||
|
bool operator > (const date& lhs, const date& rhs);
|
||||||
|
bool operator == (const date& lhs, const date& rhs);
|
||||||
|
bool operator >= (const date& lhs, const date& rhs);
|
||||||
|
|
||||||
class chrono
|
class chrono
|
||||||
{
|
{
|
||||||
@ -34,6 +48,7 @@ namespace helper
|
|||||||
static std::string timeToLocalStr(time_t timestamp);
|
static std::string timeToLocalStr(time_t timestamp);
|
||||||
static time_t strToTime(const std::string& s);
|
static time_t strToTime(const std::string& s);
|
||||||
static struct tm localtime(time_t timestamp);
|
static struct tm localtime(time_t timestamp);
|
||||||
|
static int daysInMonth(int m, int y);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
119
client/task.cpp
119
client/task.cpp
@ -9,6 +9,8 @@
|
|||||||
# include <uuid/uuid.h>
|
# include <uuid/uuid.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace helper;
|
||||||
|
|
||||||
// -------- WorldId ------
|
// -------- WorldId ------
|
||||||
WorldId::WorldId()
|
WorldId::WorldId()
|
||||||
{
|
{
|
||||||
@ -72,7 +74,7 @@ TimeRecord::TimeRecord()
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
TimeRecord::TimeRecord(const time_t &startTime, const time_t &endTime, Id taskId)
|
TimeRecord::TimeRecord(const time_t &startTime, const time_t &endTime, Id taskId)
|
||||||
:mId(0), mTaskId(taskId), mSaved(false), mStartTime(startTime), mEndTime(endTime)
|
:mId(0), mTaskId(taskId), mStartTime(startTime), mEndTime(endTime), mSaved(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +170,7 @@ void TimeRecord::deleteRecord()
|
|||||||
|
|
||||||
// -------------------- TimeLine --------------------
|
// -------------------- TimeLine --------------------
|
||||||
TimeLine::TimeLine()
|
TimeLine::TimeLine()
|
||||||
:mTaskId(0), mActiveTimeRecord(nullptr), mTotalTime(0), mActive(false)
|
:mTaskId(0), mActive(false), mActiveTimeRecord(nullptr), mTotalTime(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
TimeLine::~TimeLine()
|
TimeLine::~TimeLine()
|
||||||
@ -457,7 +459,7 @@ void TimeLine::flush(bool saveToDb, time_t currentUtc)
|
|||||||
|
|
||||||
if (mActiveTimeRecord)
|
if (mActiveTimeRecord)
|
||||||
{
|
{
|
||||||
int delta = currentUtc - mActiveTimeRecord->endTime();
|
long delta = currentUtc - mActiveTimeRecord->endTime();
|
||||||
mActiveTimeRecord->setEndTime(currentUtc);
|
mActiveTimeRecord->setEndTime(currentUtc);
|
||||||
|
|
||||||
TimeRecord* tr = hasTimePoint(currentUtc);
|
TimeRecord* tr = hasTimePoint(currentUtc);
|
||||||
@ -485,7 +487,7 @@ void TimeLine::flush(bool saveToDb, time_t currentUtc)
|
|||||||
void TimeLine::load()
|
void TimeLine::load()
|
||||||
{
|
{
|
||||||
SQLite::Statement q(Storage::instance().database(), "select id, starttime, endtime from timeline where (taskid = :taskid) and ((removed is null) or (removed != 1)) order by id asc");
|
SQLite::Statement q(Storage::instance().database(), "select id, starttime, endtime from timeline where (taskid = :taskid) and ((removed is null) or (removed != 1)) order by id asc");
|
||||||
q.bind(":taskid", (sqlite3_int64)mTaskId);
|
q.bind(":taskid", mTaskId);
|
||||||
while (q.executeStep())
|
while (q.executeStep())
|
||||||
{
|
{
|
||||||
time_t start = helper::chrono::strToTime(q.getColumn(1).getText());
|
time_t start = helper::chrono::strToTime(q.getColumn(1).getText());
|
||||||
@ -526,82 +528,93 @@ TimeArray& TimeLine::data()
|
|||||||
return mData;
|
return mData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeLine::getYears(std::set<int>& years)
|
std::set<int> TimeLine::getYears()
|
||||||
{
|
{
|
||||||
|
std::set<int> r;
|
||||||
if (mData.empty())
|
if (mData.empty())
|
||||||
return;
|
return r;
|
||||||
|
|
||||||
time_t starttime_1 = mData.front().startTime(), starttime_2 = mData.back().startTime();
|
date t1 = date::fromTimestamp(mData.front().startTime(), date::To_LocalTime),
|
||||||
struct tm t1 = *localtime(&starttime_1), t2 = *localtime(&starttime_2);
|
t2 = date::fromTimestamp(mData.back().startTime(), date::To_LocalTime);
|
||||||
|
|
||||||
// Find lower bound of years - it is first time record
|
r.insert(t1.mYear);
|
||||||
int year1 = t1.tm_year + 1900;
|
|
||||||
years.insert(year1);
|
|
||||||
|
|
||||||
// Find higher bound of years - it is last time record
|
// Find higher bound of years - it is last time record
|
||||||
int year2 = t2.tm_year + 1900;
|
if (t1.mYear == t2.mYear)
|
||||||
|
return r;
|
||||||
if (year1 == year2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Try to find next year by binary search
|
// Try to find next year by binary search
|
||||||
for (int year = year1+1; year <= year2; year++)
|
for (int year = t1.mYear + 1; year <= t2.mYear; year++)
|
||||||
{
|
{
|
||||||
QDate yearStart(year, 1, 1);
|
date yearStart(year, 1, 1);
|
||||||
TimeArray::iterator iter = std::lower_bound(mData.begin(), mData.end(), yearStart,
|
TimeArray::iterator iter = std::lower_bound(mData.begin(), mData.end(), yearStart,
|
||||||
[&](const TimeRecord& lhs, time_t rhs)
|
[&](const TimeRecord& lhs, date rhs)
|
||||||
{ return lhs.endTime() < rhs; });
|
{
|
||||||
|
return date::fromTimestamp(lhs.endTime(), date::To_LocalTime) < rhs;
|
||||||
|
});
|
||||||
|
|
||||||
if (iter != mData.end())
|
if (iter != mData.end())
|
||||||
{
|
{
|
||||||
// Get current year
|
// Get found year
|
||||||
struct tm ct = helper::chrono::localtime(iter->startTime());
|
date found_date = date::fromTimestamp(iter->startTime(), date::To_LocalTime);
|
||||||
if (ct.tm_year + 1900 <= year)
|
if (found_date.mYear <= year)
|
||||||
years.insert(year);
|
r.insert(year);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeLine::getMonthes(int year, std::set<int>& result)
|
std::set<int> TimeLine::getMonthes(int year)
|
||||||
{
|
{
|
||||||
|
std::set<int> r;
|
||||||
|
|
||||||
for (int month = 1; month <= 12; month++)
|
for (int month = 1; month <= 12; month++)
|
||||||
{
|
{
|
||||||
QDate monthBegin(year, month, 1);
|
date monthBegin(year, month, 1);
|
||||||
QDate monthEnd(year, month, monthBegin.daysInMonth());
|
date monthEnd(year, month, date::daysInMonth(year, month));
|
||||||
|
|
||||||
// Find range for every month in year [lowest, higher)
|
// Find range for every month in year [lowest, higher)
|
||||||
TimeArray::iterator lowest = std::lower_bound(mData.begin(), mData.end(), monthBegin,
|
TimeArray::iterator lowest = std::lower_bound(mData.begin(), mData.end(), monthBegin,
|
||||||
[] (const TimeRecord& tr, const QDate& d)
|
[] (const TimeRecord& tr, const date& d)
|
||||||
{ return tr.endTime() < QDateTime(d).toTime_t();});
|
|
||||||
|
{
|
||||||
|
return date::fromTimestamp(tr.endTime(), date::To_LocalTime) < d;
|
||||||
|
});
|
||||||
|
|
||||||
//TimeArray::iterator higher = std::upper_bound(mData.begin(), mData.end(), monthEnd, [] (const TimeRecord& tr, const QDate& d) { return tr.startTime().toLocalTime().date() < d;});
|
//TimeArray::iterator higher = std::upper_bound(mData.begin(), mData.end(), monthEnd, [] (const TimeRecord& tr, const QDate& d) { return tr.startTime().toLocalTime().date() < d;});
|
||||||
if (lowest != mData.end())
|
if (lowest != mData.end())
|
||||||
{
|
{
|
||||||
// Current date is local time!
|
// Current date is local time!
|
||||||
helper::date currentDate = helper::date::fromTimestamp(lowest->startTime());
|
helper::date currentDate = helper::date::fromTimestamp(lowest->startTime(), helper::date::To_LocalTime);
|
||||||
if (currentDate.mYear > year)
|
if (currentDate.mYear > year)
|
||||||
continue;
|
continue;
|
||||||
if (currentDate.mYear == year && currentDate.mMonth > month)
|
if (currentDate.mYear == year && currentDate.mMonth > month)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result.insert(month);
|
r.insert(month);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimeLine::getDays(int year, int month, std::set<int>& result)
|
std::set<int> TimeLine::getDays(int year, int month)
|
||||||
{
|
{
|
||||||
QDate monthBegin(year, month, 1);
|
std::set<int> r;
|
||||||
for (int day = 1; day <= monthBegin.daysInMonth(); day++)
|
date monthBegin(year, month, 1);
|
||||||
|
for (int day = 1; day <= date::daysInMonth(year, month); day++)
|
||||||
{
|
{
|
||||||
QDate currentDay(year, month, day);
|
date currentDay(year, month, day);
|
||||||
|
|
||||||
TimeArray::iterator lowest = std::lower_bound(mData.begin(), mData.end(), currentDay,
|
TimeArray::iterator lowest = std::lower_bound(mData.begin(), mData.end(), currentDay,
|
||||||
[] (const TimeRecord& tr, const QDate& d)
|
[] (const TimeRecord& tr, const date& d)
|
||||||
{
|
{
|
||||||
return tr.endTime() < QDateTime(d).toTime_t();
|
return date::fromTimestamp(tr.endTime(), date::To_LocalTime) < d;
|
||||||
});
|
});
|
||||||
if (lowest != mData.end())
|
if (lowest != mData.end())
|
||||||
{
|
{
|
||||||
helper::date startDate = helper::date::fromTimestamp(lowest->startTime());
|
helper::date startDate = helper::date::fromTimestamp(lowest->startTime(), helper::date::To_LocalTime);
|
||||||
if (startDate.mYear > year)
|
if (startDate.mYear > year)
|
||||||
continue;
|
continue;
|
||||||
if (startDate.mYear == year && startDate.mMonth > month)
|
if (startDate.mYear == year && startDate.mMonth > month)
|
||||||
@ -609,9 +622,10 @@ void TimeLine::getDays(int year, int month, std::set<int>& result)
|
|||||||
if (startDate.mYear == year && startDate.mMonth == month && startDate.mDay > day)
|
if (startDate.mYear == year && startDate.mMonth == month && startDate.mDay > day)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
result.insert(day);
|
r.insert(day);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TimeLine::getTime(int year, int month, int day, std::vector<TimeRecord>* intervals)
|
int TimeLine::getTime(int year, int month, int day, std::vector<TimeRecord>* intervals)
|
||||||
@ -630,7 +644,7 @@ int TimeLine::getTime(int year, int month, int day, std::vector<TimeRecord>* int
|
|||||||
{
|
{
|
||||||
TimeRecord& tr = *lowest;
|
TimeRecord& tr = *lowest;
|
||||||
|
|
||||||
helper::date startDate = helper::date::fromTimestamp(tr.startTime());
|
helper::date startDate = helper::date::fromTimestamp(tr.startTime(), date::To_LocalTime);
|
||||||
|
|
||||||
if (startDate.mYear > year)
|
if (startDate.mYear > year)
|
||||||
break;
|
break;
|
||||||
@ -670,31 +684,36 @@ int TimeLine::today()
|
|||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
TimeArray::iterator lowIter = std::lower_bound(mData.begin(), mData.end(), QDate::currentDate(),
|
// Find starting record related to today
|
||||||
[] (const TimeRecord& lhs, const QDate& rhs)
|
// Today is local time!
|
||||||
|
date today = date::today();
|
||||||
|
|
||||||
|
TimeArray::iterator lowIter = std::lower_bound(mData.begin(), mData.end(), today,
|
||||||
|
[] (const TimeRecord& lhs, const date& rhs)
|
||||||
{
|
{
|
||||||
return lhs.endTime().toLocalTime().date() < rhs;
|
return date::fromTimestamp(lhs.endTime(), date::To_LocalTime) < rhs;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (;lowIter != mData.end(); lowIter++)
|
for (;lowIter != mData.end(); lowIter++)
|
||||||
{
|
{
|
||||||
if (lowIter->startTime().toLocalTime().date() > QDate::currentDate())
|
if (date::fromTimestamp(lowIter->startTime(), date::To_LocalTime) > today)
|
||||||
break; // quit the loop
|
break; // quit the loop
|
||||||
|
|
||||||
if (lowIter->endTime().toLocalTime().date() >= QDate::currentDate())
|
if (date::fromTimestamp(lowIter->endTime(), date::To_LocalTime) >= today)
|
||||||
{
|
{
|
||||||
QDateTime dayBegin(QDate::currentDate(), QTime(0,0));
|
// Both are GMT time
|
||||||
QDateTime dayEnd(QDate::currentDate(), QTime(23, 59, 59));
|
time_t dayBegin = date::today().toTimestamp();
|
||||||
|
time_t dayEnd = dayBegin + 86359;
|
||||||
|
|
||||||
int secondsTo = dayBegin.secsTo(lowIter->startTime().toLocalTime());
|
int64_t secondsTo = lowIter->startTime() - dayBegin;
|
||||||
if (secondsTo > 0)
|
if (secondsTo > 0)
|
||||||
dayBegin = lowIter->startTime();
|
dayBegin = lowIter->startTime();
|
||||||
|
|
||||||
int secondsFrom = dayEnd.secsTo(lowIter->endTime().toLocalTime());
|
int64_t secondsFrom = lowIter->endTime() - dayEnd;
|
||||||
if (secondsFrom < 0)
|
if (secondsFrom < 0)
|
||||||
dayEnd = lowIter->endTime().toLocalTime();
|
dayEnd = lowIter->endTime();
|
||||||
|
|
||||||
int secondsSpent = dayBegin.secsTo(dayEnd);
|
int secondsSpent = dayEnd - dayBegin;
|
||||||
result += secondsSpent;
|
result += secondsSpent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include "SQLiteCpp/Database.h"
|
#include "SQLiteCpp/Database.h"
|
||||||
|
|
||||||
typedef uint64_t Id;
|
typedef int64_t Id;
|
||||||
|
|
||||||
class WorldId
|
class WorldId
|
||||||
{
|
{
|
||||||
@ -92,14 +92,27 @@ public:
|
|||||||
void setTaskId(Id id);
|
void setTaskId(Id id);
|
||||||
|
|
||||||
// These methods work with local time
|
// These methods work with local time
|
||||||
void getYears(std::set<int>& result);
|
// Returns set of available years in timeline
|
||||||
void getMonthes(int year, std::set<int>& result);
|
std::set<int> getYears();
|
||||||
void getDays(int year, int month, std::set<int>& result);
|
|
||||||
|
// Returns set of availables monthes in timeline for specified year
|
||||||
|
std::set<int> getMonthes(int year);
|
||||||
|
|
||||||
|
// Returns set of available days in timeline for specified year & month
|
||||||
|
std::set<int> getDays(int year, int month);
|
||||||
|
|
||||||
int getTime(int year, int month, int day, std::vector<TimeRecord>* intervals);
|
int getTime(int year, int month, int day, std::vector<TimeRecord>* intervals);
|
||||||
|
|
||||||
|
// Returns number of seconds spent today
|
||||||
int today();
|
int today();
|
||||||
|
|
||||||
|
// Returns number of seconds spent in current month
|
||||||
int month();
|
int month();
|
||||||
|
|
||||||
|
// Returns number of seconds spent in interval
|
||||||
int getSum(const QDate& start, const QDate& finish);
|
int getSum(const QDate& start, const QDate& finish);
|
||||||
|
|
||||||
|
// Checks if there duplicate & overllaping time intervals
|
||||||
bool duplicateDetected() const;
|
bool duplicateDetected() const;
|
||||||
|
|
||||||
// Checks if specified interval has intersection
|
// Checks if specified interval has intersection
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user