Fix handling negative time spans
This commit is contained in:
parent
a53601e5d0
commit
3bc9a7b07a
|
@ -69,7 +69,7 @@ DateTime DateTime::fromTimeStamp(time_t timeStamp)
|
|||
*/
|
||||
DateTime DateTime::fromTimeStampGmt(time_t timeStamp)
|
||||
{
|
||||
return DateTime(DateTime::unixEpochStart().totalTicks() + static_cast<uint64>(timeStamp) * TimeSpan::ticksPerSecond);
|
||||
return DateTime(DateTime::unixEpochStart().totalTicks() + static_cast<uint64>(timeStamp) * TimeSpan::m_ticksPerSecond);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -287,7 +287,7 @@ DateTime DateTime::exactGmtNow()
|
|||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return DateTime(
|
||||
DateTime::unixEpochStart().totalTicks() + static_cast<uint64>(t.tv_sec) * TimeSpan::ticksPerSecond + static_cast<uint64>(t.tv_nsec) / 100);
|
||||
DateTime::unixEpochStart().totalTicks() + static_cast<uint64>(t.tv_sec) * TimeSpan::m_ticksPerSecond + static_cast<uint64>(t.tv_nsec) / 100);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -296,25 +296,21 @@ DateTime DateTime::exactGmtNow()
|
|||
*/
|
||||
uint64 DateTime::dateToTicks(int year, int month, int day)
|
||||
{
|
||||
if (inRangeInclMax(year, 1, 9999)) {
|
||||
if (inRangeInclMax(month, 1, 12)) {
|
||||
const int *daysToMonth = isLeapYear(year) ? m_daysToMonth366 : m_daysToMonth365;
|
||||
int passedMonth = month - 1;
|
||||
if (inRangeInclMax(day, 1, daysToMonth[month] - daysToMonth[passedMonth])) {
|
||||
int passedYears = year - 1;
|
||||
int passedDays = day - 1;
|
||||
return (passedYears * m_daysPerYear + passedYears / 4 - passedYears / 100 + passedYears / 400 + daysToMonth[passedMonth] + passedDays)
|
||||
* TimeSpan::ticksPerDay;
|
||||
} else {
|
||||
throw ConversionException("day is out of range");
|
||||
}
|
||||
} else {
|
||||
throw ConversionException("month is out of range");
|
||||
}
|
||||
} else {
|
||||
if (!inRangeInclMax(year, 1, 9999)) {
|
||||
throw ConversionException("year is out of range");
|
||||
}
|
||||
return 0;
|
||||
if (!inRangeInclMax(month, 1, 12)) {
|
||||
throw ConversionException("month is out of range");
|
||||
}
|
||||
const int *daysToMonth = isLeapYear(year) ? m_daysToMonth366 : m_daysToMonth365;
|
||||
int passedMonth = month - 1;
|
||||
if (!inRangeInclMax(day, 1, daysToMonth[month] - daysToMonth[passedMonth])) {
|
||||
throw ConversionException("day is out of range");
|
||||
}
|
||||
int passedYears = year - 1;
|
||||
int passedDays = day - 1;
|
||||
return (passedYears * m_daysPerYear + passedYears / 4 - passedYears / 100 + passedYears / 400 + daysToMonth[passedMonth] + passedDays)
|
||||
* TimeSpan::m_ticksPerDay;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -334,8 +330,8 @@ uint64 DateTime::timeToTicks(int hour, int minute, int second, double millisecon
|
|||
if (!inRangeExclMax(millisecond, 0.0, 1000.0)) {
|
||||
throw ConversionException("millisecond is out of range");
|
||||
}
|
||||
return (hour * TimeSpan::ticksPerHour) + (minute * TimeSpan::ticksPerMinute) + (second * TimeSpan::ticksPerSecond)
|
||||
+ (uint64)(millisecond * (double)TimeSpan::ticksPerMillisecond);
|
||||
return (hour * TimeSpan::m_ticksPerHour) + (minute * TimeSpan::m_ticksPerMinute) + (second * TimeSpan::m_ticksPerSecond)
|
||||
+ (uint64)(millisecond * (double)TimeSpan::m_ticksPerMillisecond);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -344,7 +340,7 @@ uint64 DateTime::timeToTicks(int hour, int minute, int second, double millisecon
|
|||
*/
|
||||
int DateTime::getDatePart(DatePart part) const
|
||||
{
|
||||
int fullDays = m_ticks / TimeSpan::ticksPerDay;
|
||||
int fullDays = m_ticks / TimeSpan::m_ticksPerDay;
|
||||
int full400YearBlocks = fullDays / m_daysPer400Years;
|
||||
int daysMinusFull400YearBlocks = fullDays - full400YearBlocks * m_daysPer400Years;
|
||||
int full100YearBlocks = daysMinusFull400YearBlocks / m_daysPer100Years;
|
||||
|
|
|
@ -243,7 +243,7 @@ inline int DateTime::dayOfYear() const
|
|||
*/
|
||||
constexpr inline DayOfWeek DateTime::dayOfWeek() const
|
||||
{
|
||||
return static_cast<DayOfWeek>((m_ticks / TimeSpan::ticksPerDay) % 7l);
|
||||
return static_cast<DayOfWeek>((m_ticks / TimeSpan::m_ticksPerDay) % 7l);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -251,7 +251,7 @@ constexpr inline DayOfWeek DateTime::dayOfWeek() const
|
|||
*/
|
||||
constexpr inline int DateTime::hour() const
|
||||
{
|
||||
return m_ticks / TimeSpan::ticksPerHour % 24ul;
|
||||
return m_ticks / TimeSpan::m_ticksPerHour % 24ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -259,7 +259,7 @@ constexpr inline int DateTime::hour() const
|
|||
*/
|
||||
constexpr inline int DateTime::minute() const
|
||||
{
|
||||
return m_ticks / TimeSpan::ticksPerMinute % 60ul;
|
||||
return m_ticks / TimeSpan::m_ticksPerMinute % 60ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -267,7 +267,7 @@ constexpr inline int DateTime::minute() const
|
|||
*/
|
||||
constexpr inline int DateTime::second() const
|
||||
{
|
||||
return m_ticks / TimeSpan::ticksPerSecond % 60ul;
|
||||
return m_ticks / TimeSpan::m_ticksPerSecond % 60ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -275,7 +275,7 @@ constexpr inline int DateTime::second() const
|
|||
*/
|
||||
constexpr inline int DateTime::millisecond() const
|
||||
{
|
||||
return m_ticks / TimeSpan::ticksPerMillisecond % 1000ul;
|
||||
return m_ticks / TimeSpan::m_ticksPerMillisecond % 1000ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -292,7 +292,7 @@ constexpr inline bool DateTime::isNull() const
|
|||
*/
|
||||
constexpr inline TimeSpan DateTime::timeOfDay() const
|
||||
{
|
||||
return TimeSpan(m_ticks % TimeSpan::ticksPerDay);
|
||||
return TimeSpan(m_ticks % TimeSpan::m_ticksPerDay);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -332,7 +332,7 @@ inline int DateTime::daysInMonth(int year, int month)
|
|||
*/
|
||||
constexpr inline bool DateTime::isSameDay(const DateTime &other) const
|
||||
{
|
||||
return (m_ticks / TimeSpan::ticksPerDay) == (other.m_ticks / TimeSpan::ticksPerDay);
|
||||
return (m_ticks / TimeSpan::m_ticksPerDay) == (other.m_ticks / TimeSpan::m_ticksPerDay);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -22,6 +22,10 @@ using namespace ConversionUtilities;
|
|||
*/
|
||||
TimeSpan TimeSpan::fromString(const char *str, char separator)
|
||||
{
|
||||
if (!*str) {
|
||||
return TimeSpan();
|
||||
}
|
||||
|
||||
vector<double> parts;
|
||||
size_t partsSize = 1;
|
||||
for (const char *i = str; *i; ++i) {
|
||||
|
@ -42,8 +46,6 @@ TimeSpan TimeSpan::fromString(const char *str, char separator)
|
|||
}
|
||||
|
||||
switch (parts.size()) {
|
||||
case 0:
|
||||
return TimeSpan();
|
||||
case 1:
|
||||
return TimeSpan::fromSeconds(parts.front());
|
||||
case 2:
|
||||
|
@ -79,32 +81,40 @@ string TimeSpan::toString(TimeSpanOutputFormat format, bool noMilliseconds) cons
|
|||
void TimeSpan::toString(string &result, TimeSpanOutputFormat format, bool noMilliseconds) const
|
||||
{
|
||||
stringstream s(stringstream::in | stringstream::out);
|
||||
if (isNegative())
|
||||
s << "- ";
|
||||
TimeSpan positive(m_ticks);
|
||||
if (positive.isNegative()) {
|
||||
s << '-';
|
||||
positive.m_ticks = -positive.m_ticks;
|
||||
}
|
||||
switch (format) {
|
||||
case TimeSpanOutputFormat::Normal:
|
||||
s << setfill('0') << setw(2) << floor(fabs(totalHours())) << ":" << setw(2) << minutes() << ":" << setw(2) << seconds() << " ";
|
||||
s << setfill('0') << setw(2) << floor(positive.totalHours()) << ":" << setw(2) << positive.minutes() << ":" << setw(2) << positive.seconds()
|
||||
<< " ";
|
||||
break;
|
||||
case TimeSpanOutputFormat::WithMeasures:
|
||||
if (isNull()) {
|
||||
s << "0 s ";
|
||||
} else if (totalMilliseconds() < 1.0) {
|
||||
s << setprecision(2) << (m_ticks / 10.0) << " µs ";
|
||||
} else {
|
||||
if (days()) {
|
||||
s << days() << " d ";
|
||||
}
|
||||
if (hours()) {
|
||||
s << hours() << " h ";
|
||||
}
|
||||
if (minutes()) {
|
||||
s << minutes() << " min ";
|
||||
}
|
||||
if (seconds()) {
|
||||
s << seconds() << " s ";
|
||||
}
|
||||
if (!noMilliseconds && milliseconds()) {
|
||||
s << milliseconds() << " ms ";
|
||||
if (positive.totalMilliseconds() < 1.0) {
|
||||
s << setprecision(2) << (m_ticks / 10.0) << " µs ";
|
||||
} else {
|
||||
if (const int days = positive.days()) {
|
||||
s << days << " d ";
|
||||
}
|
||||
if (const int hours = positive.hours()) {
|
||||
s << hours << " h ";
|
||||
}
|
||||
if (const int minutes = positive.minutes()) {
|
||||
s << minutes << " min ";
|
||||
}
|
||||
if (const int seconds = positive.seconds()) {
|
||||
s << seconds << " s ";
|
||||
}
|
||||
if (!noMilliseconds) {
|
||||
if (const int milliseconds = positive.milliseconds()) {
|
||||
s << milliseconds << " ms ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -72,12 +72,20 @@ public:
|
|||
constexpr bool isNegativeInfinity() const;
|
||||
constexpr bool isInfinity() const;
|
||||
|
||||
// TODO: make those public constants signed in next major release and remove private ones then
|
||||
static constexpr uint64 ticksPerMillisecond = 10000uL;
|
||||
static constexpr uint64 ticksPerSecond = 10000000uL;
|
||||
static constexpr uint64 ticksPerMinute = 600000000uL;
|
||||
static constexpr uint64 ticksPerHour = 36000000000uL;
|
||||
static constexpr uint64 ticksPerDay = 864000000000uL;
|
||||
|
||||
private:
|
||||
static constexpr int64 m_ticksPerMillisecond = 10000L;
|
||||
static constexpr int64 m_ticksPerSecond = 10000000L;
|
||||
static constexpr int64 m_ticksPerMinute = 600000000L;
|
||||
static constexpr int64 m_ticksPerHour = 36000000000L;
|
||||
static constexpr int64 m_ticksPerDay = 864000000000L;
|
||||
|
||||
private:
|
||||
int64 m_ticks;
|
||||
};
|
||||
|
@ -103,7 +111,7 @@ constexpr inline TimeSpan::TimeSpan(int64 ticks)
|
|||
*/
|
||||
constexpr inline TimeSpan TimeSpan::fromMilliseconds(double milliseconds)
|
||||
{
|
||||
return TimeSpan(static_cast<int64>(milliseconds * static_cast<double>(ticksPerMillisecond)));
|
||||
return TimeSpan(static_cast<int64>(milliseconds * static_cast<double>(m_ticksPerMillisecond)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -111,7 +119,7 @@ constexpr inline TimeSpan TimeSpan::fromMilliseconds(double milliseconds)
|
|||
*/
|
||||
constexpr inline TimeSpan TimeSpan::fromSeconds(double seconds)
|
||||
{
|
||||
return TimeSpan(static_cast<int64>(seconds * static_cast<double>(ticksPerSecond)));
|
||||
return TimeSpan(static_cast<int64>(seconds * static_cast<double>(m_ticksPerSecond)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -119,7 +127,7 @@ constexpr inline TimeSpan TimeSpan::fromSeconds(double seconds)
|
|||
*/
|
||||
constexpr inline TimeSpan TimeSpan::fromMinutes(double minutes)
|
||||
{
|
||||
return TimeSpan(static_cast<int64>(minutes * static_cast<double>(ticksPerMinute)));
|
||||
return TimeSpan(static_cast<int64>(minutes * static_cast<double>(m_ticksPerMinute)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -127,7 +135,7 @@ constexpr inline TimeSpan TimeSpan::fromMinutes(double minutes)
|
|||
*/
|
||||
constexpr inline TimeSpan TimeSpan::fromHours(double hours)
|
||||
{
|
||||
return TimeSpan(static_cast<int64>(hours * static_cast<double>(ticksPerHour)));
|
||||
return TimeSpan(static_cast<int64>(hours * static_cast<double>(m_ticksPerHour)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -135,7 +143,7 @@ constexpr inline TimeSpan TimeSpan::fromHours(double hours)
|
|||
*/
|
||||
constexpr inline TimeSpan TimeSpan::fromDays(double days)
|
||||
{
|
||||
return TimeSpan(static_cast<int64>(days * static_cast<double>(ticksPerDay)));
|
||||
return TimeSpan(static_cast<int64>(days * static_cast<double>(m_ticksPerDay)));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -175,7 +183,7 @@ constexpr inline int64 TimeSpan::totalTicks() const
|
|||
*/
|
||||
constexpr inline double TimeSpan::totalMilliseconds() const
|
||||
{
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(ticksPerMillisecond);
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(m_ticksPerMillisecond);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -183,7 +191,7 @@ constexpr inline double TimeSpan::totalMilliseconds() const
|
|||
*/
|
||||
constexpr inline double TimeSpan::totalSeconds() const
|
||||
{
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(ticksPerSecond);
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(m_ticksPerSecond);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -191,7 +199,7 @@ constexpr inline double TimeSpan::totalSeconds() const
|
|||
*/
|
||||
constexpr inline double TimeSpan::totalMinutes() const
|
||||
{
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(ticksPerMinute);
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(m_ticksPerMinute);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -199,7 +207,7 @@ constexpr inline double TimeSpan::totalMinutes() const
|
|||
*/
|
||||
constexpr inline double TimeSpan::totalHours() const
|
||||
{
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(ticksPerHour);
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(m_ticksPerHour);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -207,7 +215,7 @@ constexpr inline double TimeSpan::totalHours() const
|
|||
*/
|
||||
constexpr inline double TimeSpan::totalDays() const
|
||||
{
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(ticksPerDay);
|
||||
return static_cast<double>(m_ticks) / static_cast<double>(m_ticksPerDay);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -215,7 +223,7 @@ constexpr inline double TimeSpan::totalDays() const
|
|||
*/
|
||||
constexpr inline int TimeSpan::milliseconds() const
|
||||
{
|
||||
return (m_ticks / ticksPerMillisecond) % 1000l;
|
||||
return (m_ticks / m_ticksPerMillisecond) % 1000l;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -223,7 +231,7 @@ constexpr inline int TimeSpan::milliseconds() const
|
|||
*/
|
||||
constexpr inline int TimeSpan::seconds() const
|
||||
{
|
||||
return (m_ticks / ticksPerSecond) % 60l;
|
||||
return (m_ticks / m_ticksPerSecond) % 60l;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -231,7 +239,7 @@ constexpr inline int TimeSpan::seconds() const
|
|||
*/
|
||||
constexpr inline int TimeSpan::minutes() const
|
||||
{
|
||||
return (m_ticks / ticksPerMinute) % 60l;
|
||||
return (m_ticks / m_ticksPerMinute) % 60l;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -239,7 +247,7 @@ constexpr inline int TimeSpan::minutes() const
|
|||
*/
|
||||
constexpr inline int TimeSpan::hours() const
|
||||
{
|
||||
return (m_ticks / ticksPerHour) % 24l;
|
||||
return (m_ticks / m_ticksPerHour) % 24l;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -247,7 +255,7 @@ constexpr inline int TimeSpan::hours() const
|
|||
*/
|
||||
constexpr inline int TimeSpan::days() const
|
||||
{
|
||||
return (m_ticks / ticksPerDay);
|
||||
return (m_ticks / m_ticksPerDay);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
Loading…
Reference in New Issue