Skip to content

Commit

Permalink
bdlt::Datetime: modify 'add*' and 'add*IfValid' to take into account …
Browse files Browse the repository at this point in the history
…that (#5070)

if 'x == int64Min', -x is still < 0.
  • Loading branch information
lalawawa authored and GitHub Enterprise committed Nov 25, 2024
1 parent fbd8b61 commit 0219032
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 28 deletions.
56 changes: 28 additions & 28 deletions groups/bdl/bdlt/bdlt_datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -1808,17 +1808,17 @@ Datetime& Datetime::addTime(bsls::Types::Int64 hours,

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();

BSLS_ASSERT_SAFE( days <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(days <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - totalMicroseconds)
/ TimeUnitRatio::k_US_PER_D));
BSLS_ASSERT_SAFE(-days <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(days >= -static_cast<bsls::Types::Int64>
(totalMicroseconds / TimeUnitRatio::k_US_PER_D));

totalMicroseconds += days * TimeUnitRatio::k_US_PER_D;

BSLS_ASSERT_SAFE( microseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(microseconds <= static_cast<bsls::Types::Int64>
(k_MAX_US_FROM_EPOCH - totalMicroseconds));
BSLS_ASSERT_SAFE(-microseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(microseconds >= -static_cast<bsls::Types::Int64>
(totalMicroseconds));

totalMicroseconds += microseconds;
Expand Down Expand Up @@ -1880,19 +1880,19 @@ int Datetime::addTimeIfValid(bsls::Types::Int64 hours,

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();

if (!( days <= static_cast<bsls::Types::Int64>
if (!( days <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - totalMicroseconds)
/ TimeUnitRatio::k_US_PER_D)
&& -days <= static_cast<bsls::Types::Int64>
&& days >= -static_cast<bsls::Types::Int64>
(totalMicroseconds / TimeUnitRatio::k_US_PER_D))) {
return k_FAILURE; // RETURN
}

totalMicroseconds += days * TimeUnitRatio::k_US_PER_D;

if (!( microseconds <= static_cast<bsls::Types::Int64>
if (!( microseconds <= static_cast<bsls::Types::Int64>
(k_MAX_US_FROM_EPOCH - totalMicroseconds)
&& -microseconds <= static_cast<bsls::Types::Int64>
&& microseconds >= -static_cast<bsls::Types::Int64>
(totalMicroseconds))) {
return k_FAILURE; // RETURN
}
Expand All @@ -1908,10 +1908,10 @@ int Datetime::addTimeIfValid(bsls::Types::Int64 hours,
inline
Datetime& Datetime::addHours(bsls::Types::Int64 hours)
{
BSLS_ASSERT_SAFE( hours <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(hours <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_H));
BSLS_ASSERT_SAFE(-hours <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(hours >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_H));

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();
Expand All @@ -1927,10 +1927,10 @@ int Datetime::addHoursIfValid(bsls::Types::Int64 hours)
{
enum { k_SUCCESS = 0, k_FAILURE = -1 };

if ( hours <= static_cast<bsls::Types::Int64>
if ( hours <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_H)
&& -hours <= static_cast<bsls::Types::Int64>
&& hours >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_H)) {
addHours(hours);
return k_SUCCESS; // RETURN
Expand All @@ -1941,10 +1941,10 @@ int Datetime::addHoursIfValid(bsls::Types::Int64 hours)
inline
Datetime& Datetime::addMinutes(bsls::Types::Int64 minutes)
{
BSLS_ASSERT_SAFE( minutes <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(minutes <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_M));
BSLS_ASSERT_SAFE(-minutes <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(minutes >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_M));

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();
Expand All @@ -1959,10 +1959,10 @@ int Datetime::addMinutesIfValid(bsls::Types::Int64 minutes)
{
enum { k_SUCCESS = 0, k_FAILURE = -1 };

if ( minutes <= static_cast<bsls::Types::Int64>
if ( minutes <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_M)
&& -minutes <= static_cast<bsls::Types::Int64>
&& minutes >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_M)) {
addMinutes(minutes);
return k_SUCCESS; // RETURN
Expand All @@ -1973,10 +1973,10 @@ int Datetime::addMinutesIfValid(bsls::Types::Int64 minutes)
inline
Datetime& Datetime::addSeconds(bsls::Types::Int64 seconds)
{
BSLS_ASSERT_SAFE( seconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(seconds <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_S));
BSLS_ASSERT_SAFE(-seconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(seconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_S));

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();
Expand All @@ -1991,10 +1991,10 @@ int Datetime::addSecondsIfValid(bsls::Types::Int64 seconds)
{
enum { k_SUCCESS = 0, k_FAILURE = -1 };

if ( seconds <= static_cast<bsls::Types::Int64>
if ( seconds <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_S)
&& -seconds <= static_cast<bsls::Types::Int64>
&& seconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_S)) {
addSeconds(seconds);
return k_SUCCESS; // RETURN
Expand All @@ -2005,10 +2005,10 @@ int Datetime::addSecondsIfValid(bsls::Types::Int64 seconds)
inline
Datetime& Datetime::addMilliseconds(bsls::Types::Int64 milliseconds)
{
BSLS_ASSERT_SAFE( milliseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(milliseconds <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_MS));
BSLS_ASSERT_SAFE(-milliseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(milliseconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_MS));

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();
Expand All @@ -2023,10 +2023,10 @@ int Datetime::addMillisecondsIfValid(bsls::Types::Int64 milliseconds)
{
enum { k_SUCCESS = 0, k_FAILURE = -1 };

if ( milliseconds <= static_cast<bsls::Types::Int64>
if ( milliseconds <= static_cast<bsls::Types::Int64>
((k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
/ TimeUnitRatio::k_US_PER_MS)
&& -milliseconds <= static_cast<bsls::Types::Int64>
&& milliseconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch() / TimeUnitRatio::k_US_PER_MS)) {
addMilliseconds(milliseconds);
return k_SUCCESS; // RETURN
Expand All @@ -2037,9 +2037,9 @@ int Datetime::addMillisecondsIfValid(bsls::Types::Int64 milliseconds)
inline
Datetime& Datetime::addMicroseconds(bsls::Types::Int64 microseconds)
{
BSLS_ASSERT_SAFE( microseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(microseconds <= static_cast<bsls::Types::Int64>
(k_MAX_US_FROM_EPOCH - microsecondsFromEpoch()));
BSLS_ASSERT_SAFE(-microseconds <= static_cast<bsls::Types::Int64>
BSLS_ASSERT_SAFE(microseconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch()));

bsls::Types::Uint64 totalMicroseconds = microsecondsFromEpoch();
Expand All @@ -2054,9 +2054,9 @@ int Datetime::addMicrosecondsIfValid(bsls::Types::Int64 microseconds)
{
enum { k_SUCCESS = 0, k_FAILURE = -1 };

if ( microseconds <= static_cast<bsls::Types::Int64>
if ( microseconds <= static_cast<bsls::Types::Int64>
(k_MAX_US_FROM_EPOCH - microsecondsFromEpoch())
&& -microseconds <= static_cast<bsls::Types::Int64>
&& microseconds >= -static_cast<bsls::Types::Int64>
(microsecondsFromEpoch())) {
addMicroseconds(microseconds);
return k_SUCCESS; // RETURN
Expand Down
46 changes: 46 additions & 0 deletions groups/bdl/bdlt/bdlt_datetime.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ typedef bdlt::DayOfWeek::Enum DayOfWeek;
typedef bdlt::Time Time;

typedef bsls::Types::Int64 Int64;
typedef bsls::Types::Uint64 Uint64;

typedef bslx::TestInStream In;
typedef bslx::TestOutStream Out;
Expand Down Expand Up @@ -1294,11 +1295,27 @@ int main(int argc, char *argv[])
const Obj startOfEpoch( 1, 1, 1, 0, 0, 0, 0, 0);
const Obj endOfEpoch(9999, 12, 31, 23, 59, 59, 999, 999);

const Int64 int64Max = ~static_cast<Uint64>(0) >> 1;
const Int64 int64Min = ~int64Max;

if (veryVerbose) cout << "\t'addTimeIfValid'" << endl;
{
Obj x0(startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(0, 0, 0, 0, -1));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(0, 0, 0, 0, int64Max));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(0, 0, 0, int64Max, 0));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(0, 0, int64Max, 0, 0));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(0, int64Max, 0, 0, 0));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(int64Max, 0, 0, 0, 0));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addTimeIfValid(int64Max, int64Max, int64Max,
int64Max, int64Max));
ASSERT(x0 == startOfEpoch);
Obj x1(startOfEpoch);
ASSERT(0 == x1.addTimeIfValid(0, 0, 0, 0, 0));
Obj x2(startOfEpoch);
Expand All @@ -1311,13 +1328,28 @@ int main(int argc, char *argv[])
Obj y2(endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(0,0,0,0, 1));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(0,0,0,0, int64Min));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(0,0,0, int64Min, 0));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(0,0, int64Min, 0,0));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(0, int64Min, 0,0,0));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid( int64Min, 0,0,0,0));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addTimeIfValid(int64Min, int64Min, int64Min,
int64Min, int64Min));
ASSERT(y2 == endOfEpoch);
}

if (veryVerbose) cout << "\t'addHoursIfValid'" << endl;
{
Obj x0(startOfEpoch);
ASSERT(0 != x0.addHoursIfValid(-1));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addHoursIfValid(int64Max));
ASSERT(x0 == startOfEpoch);
Obj x1(startOfEpoch);
ASSERT(0 == x1.addHoursIfValid( 0));
Obj x2(startOfEpoch);
Expand All @@ -1330,13 +1362,17 @@ int main(int argc, char *argv[])
Obj y2( endOfEpoch);
ASSERT(0 != y2.addHoursIfValid( 1));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addHoursIfValid( int64Min));
ASSERT(y2 == endOfEpoch);
}

if (veryVerbose) cout << "\t'addMinutesIfValid'" << endl;
{
Obj x0(startOfEpoch);
ASSERT(0 != x0.addMinutesIfValid(-1));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addMinutesIfValid(int64Max));
ASSERT(x0 == startOfEpoch);
Obj x1(startOfEpoch);
ASSERT(0 == x1.addMinutesIfValid( 0));
Obj x2(startOfEpoch);
Expand All @@ -1349,13 +1385,17 @@ int main(int argc, char *argv[])
Obj y2( endOfEpoch);
ASSERT(0 != y2.addMinutesIfValid( 1));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addMinutesIfValid(int64Min));
ASSERT(y2 == endOfEpoch);
}

if (veryVerbose) cout << "\t'addSecondsIfValid'" << endl;
{
Obj x0(startOfEpoch);
ASSERT(0 != x0.addSecondsIfValid(-1));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addSecondsIfValid(int64Max));
ASSERT(x0 == startOfEpoch);
Obj x1(startOfEpoch);
ASSERT(0 == x1.addSecondsIfValid( 0));
Obj x2(startOfEpoch);
Expand All @@ -1368,6 +1408,8 @@ int main(int argc, char *argv[])
Obj y2( endOfEpoch);
ASSERT(0 != y2.addSecondsIfValid( 1));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addSecondsIfValid(int64Min));
ASSERT(y2 == endOfEpoch);
}

if (veryVerbose) cout << "\t'addMillisecondsIfValid'" << endl;
Expand All @@ -1394,6 +1436,8 @@ int main(int argc, char *argv[])
Obj x0(startOfEpoch);
ASSERT(0 != x0.addMicrosecondsIfValid(-1));
ASSERT(x0 == startOfEpoch);
ASSERT(0 != x0.addMicrosecondsIfValid(int64Max));
ASSERT(x0 == startOfEpoch);
Obj x1(startOfEpoch);
ASSERT(0 == x1.addMicrosecondsIfValid( 0));
Obj x2(startOfEpoch);
Expand All @@ -1406,6 +1450,8 @@ int main(int argc, char *argv[])
Obj y2( endOfEpoch);
ASSERT(0 != y2.addMicrosecondsIfValid( 1));
ASSERT(y2 == endOfEpoch);
ASSERT(0 != y2.addMicrosecondsIfValid(int64Min));
ASSERT(y2 == endOfEpoch);
}
}
} break;
Expand Down

0 comments on commit 0219032

Please sign in to comment.