Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
0e4c5ad
Follow up PR for https://github.com/eclipse-score/baselibs/pull/135
Rutuja-Patil-Bosch Jun 3, 2026
ad5bb80
Merge pull request #1 from bgsw-contrib/datetime_converter_code_ut_up…
Rutuja-Patil-Bosch Jun 3, 2026
9d98249
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 4, 2026
2887fb7
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 6, 2026
950e974
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 10, 2026
1aa1740
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 11, 2026
31cb58f
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 12, 2026
75f7b31
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 13, 2026
3583d22
fixed boat findings
Rutuja-Patil-Bosch Jun 15, 2026
87a0ad8
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 16, 2026
ec7e75b
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 17, 2026
1987194
Merge pull request #2 from bgsw-contrib/datetimeconverter-bot-comment…
Rutuja-Patil-Bosch Jun 17, 2026
66aeed0
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 18, 2026
467ff54
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 19, 2026
f0c9d19
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 20, 2026
d622585
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 23, 2026
aa0da41
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 24, 2026
9fd3e42
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 25, 2026
d154a5c
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 26, 2026
6f2b728
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 27, 2026
692a348
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jun 30, 2026
47ca391
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 1, 2026
bd1d4ea
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 2, 2026
fb600a0
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 3, 2026
a2756f8
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 4, 2026
360d2c4
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 7, 2026
ec8722a
Merge branch 'eclipse-score:main' into main
bgsw-contrib[bot] Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 29 additions & 23 deletions score/datetime_converter/datetime_converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@ namespace score
namespace common
{

static std::int8_t daysInMonth(const std::int16_t year, const std::int8_t month)
{
if (month == 2)
{
return yearIsLeap(year) ? 29 : 28;
}

if ((month == 4) || (month == 6) || (month == 9) || (month == 11))
{
return 30;
}

return 31;
}

int16_t leapYearsSince1970(const int16_t year)
{
int16_t numOfLeapYears = (((year - 1969) / 4) - ((year - 1901) / 100)) + ((year - 1601) / 400);
Expand Down Expand Up @@ -70,24 +85,7 @@ bool isValidDateTimeFormat(const std::shared_ptr<DateTimeType> dateTime)
return false;
}

if (dateTime->m_month == 2)
{
if (yearIsLeap(dateTime->m_year))
{
return (dateTime->m_day <= 29);
}
else
{
return (dateTime->m_day <= 28);
}
}

if (dateTime->m_month == 4 || dateTime->m_month == 6 || dateTime->m_month == 9 || dateTime->m_month == 11)
{
return (dateTime->m_day <= 30);
}

return true;
return (dateTime->m_day <= daysInMonth(dateTime->m_year, dateTime->m_month));
};

bool dateTimeToEpoch(const std::shared_ptr<DateTimeType> dateTime, time_t* epoch)
Expand Down Expand Up @@ -151,10 +149,6 @@ std::shared_ptr<DateTimeType> epochToDateTime(time_t epoch)
time_t daysSum = (epoch / SECONDS_PER_DAY) + 1;
if (before1970)
{
if (yearIsLeap(dateTime->m_year) && ((daysSum * -1) < DAYS_UNTIL_MONTHS[1]))
{
--daysSum;
}
daysSum = DAYS_PER_YEAR + daysSum - 1;
if (yearIsLeap(dateTime->m_year))
{
Expand Down Expand Up @@ -200,7 +194,7 @@ std::shared_ptr<DateTimeType> epochToDateTime(time_t epoch)
}
else
{
if (daysSum >= DAYS_PER_YEAR)
if (daysSum > DAYS_PER_YEAR)
{
dateTime->m_year = dateTime->m_year + 1;
daysSum = daysSum - DAYS_PER_YEAR;
Expand Down Expand Up @@ -264,6 +258,18 @@ std::shared_ptr<DateTimeType> epochToDateTime(time_t epoch)
dateTime->m_hour = dateTime->m_hour - HOURS_PER_DAY;
dateTime->m_day++;
}

if (dateTime->m_day == daysInMonth(dateTime->m_year, dateTime->m_month) + 1)
{
dateTime->m_day = 1;
dateTime->m_month++;

if (dateTime->m_month == 13)
{
dateTime->m_month = 1;
dateTime->m_year++;
}
}
}

if (isValidDateTimeFormat(dateTime))
Expand Down
93 changes: 93 additions & 0 deletions score/datetime_converter/datetime_converter_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,99 @@ TEST_F(DateTimeConverterTest, test_yearIsLeap)
ASSERT_FALSE(score::common::yearIsLeap(2100));
}

TEST_F(DateTimeConverterTest, invalid_month_values)
{
RecordProperty("Description", "Verify invalid month values are rejected.");
RecordProperty("TestType", "requirements-based");

auto dtt = std::make_shared<DateTimeType>(2020, 0, 10, 3, 4, 5);
ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt));

dtt->m_month = 13;
ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt));

dtt->m_month = -1;
ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt));
}

TEST_F(DateTimeConverterTest, invalid_day_values)
{
RecordProperty("Description", "Verify invalid day values are rejected.");
RecordProperty("TestType", "requirements-based");

auto dtt = std::make_shared<DateTimeType>(2020, 12, 34, 3, 4, 5);
ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt));

dtt->m_day = -1;
ASSERT_FALSE(score::common::isValidDateTimeFormat(dtt));
}

TEST_F(DateTimeConverterTest, dateTimeToEpoch_false_isValidDateTimeFormat)
{
RecordProperty("Description", "Verify dateTimeToEpoch returns false for invalid DateTime input.");
RecordProperty("TestType", "requirements-based");

time_t epoch = static_cast<time_t>(0x7F7F7F7F);

// Invalid: month = 13 -> isValidDateTimeFormat returns false
auto d = std::make_shared<DateTimeType>(2024, 13, 10, 12, 30, 45);

ASSERT_FALSE(score::common::dateTimeToEpoch(d, &epoch));

ASSERT_EQ(epoch, static_cast<time_t>(0x7F7F7F7F));
}

TEST_F(DateTimeConverterTest, EpochToDateTime_Post1970_NonLeapYear_YearRollover)
{
RecordProperty("Description",
"Verify that a post-1970 epoch landing exactly on a non-leap year boundary rolls over to the next year correctly.");
RecordProperty("TestType", "requirements-based");

time_t epoch{};
auto dateTimeOriginal = std::make_shared<DateTimeType>(1971, 1, 1, 0, 0, 0);
ASSERT_TRUE(score::common::dateTimeToEpoch(dateTimeOriginal, &epoch));

auto dateTimeConverted = score::common::epochToDateTime(epoch);
ASSERT_NE(dateTimeConverted, nullptr);
ASSERT_EQ(dateTimeConverted->m_year, 1971);
ASSERT_EQ(dateTimeConverted->m_month, 1);
ASSERT_EQ(dateTimeConverted->m_day, 1);
ASSERT_EQ(dateTimeConverted->m_hour, 0);
ASSERT_EQ(dateTimeConverted->m_minute, 0);
ASSERT_EQ(dateTimeConverted->m_second, 0);
}

TEST_F(DateTimeConverterTest, EpochToDateTime_Pre1970_YearBoundary_DayOverflowRollover)
{
RecordProperty("Description",
"Verify that pre-1970 conversion handles day overflow at year boundary by rolling month and year.");
RecordProperty("TestType", "requirements-based");

// 1960-01-01 00:00:00 epoch; this path normalizes an intermediate Dec 32 to Jan 1 of the next year.
const time_t epochAt1960Start = static_cast<time_t>(-315619200);

auto dateTimeConverted = score::common::epochToDateTime(epochAt1960Start);
ASSERT_NE(dateTimeConverted, nullptr);
EXPECT_EQ(dateTimeConverted->m_year, 1960);
EXPECT_EQ(dateTimeConverted->m_month, 1);
EXPECT_EQ(dateTimeConverted->m_day, 1);
EXPECT_EQ(dateTimeConverted->m_hour, 0);
EXPECT_EQ(dateTimeConverted->m_minute, 0);
EXPECT_EQ(dateTimeConverted->m_second, 0);
}

TEST_F(DateTimeConverterTest, EpochToDateTime_OutOfRangeUpperBound_ReturnsNullptr)
{
RecordProperty("Description",
"Verify that epoch values mapping above the supported year range return nullptr.");
RecordProperty("TestType", "requirements-based");

// This epoch maps to year 10000, which is above the supported upper bound (9999).
const time_t epochOutOfRange = static_cast<time_t>(253405000000);

auto dateTimeConverted = score::common::epochToDateTime(epochOutOfRange);
EXPECT_EQ(dateTimeConverted, nullptr);
}
} // namespace testing
} // namespace platform
} // namespace score
Loading