Skip to content

Commit

Permalink
feat: add between function to Date module (#951)
Browse files Browse the repository at this point in the history
* feat: added two between functions one for ISO one for timestamps

* feat: exported between functions in includes and removed reference from params

* feat: added several tests for newly added between functions
  • Loading branch information
Mounayer authored Oct 8, 2024
1 parent c932a4a commit f8fa805
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
33 changes: 33 additions & 0 deletions include/faker-cxx/date.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,37 @@ FAKER_CXX_EXPORT unsigned dayOfWeek();
* @endcode
*/
FAKER_CXX_EXPORT std::string_view timezoneRandom();

/**
* @brief Generates a random date between two given Unix timestamps.
*
* @param from The starting Unix timestamp (seconds since the Unix epoch).
* @param to The ending Unix timestamp (seconds since the Unix epoch).
* @param dateFormat Specifies the format of the output date, either as an ISO string or a Unix timestamp.
* @returns A string representing the random date in the specified format.
*
* @code
* faker::date::between(1609459200, 1640995200, DateFormat::ISO); // Returns a random date between Jan 1, 2021, and Jan
* 1, 2022, formatted as "2021-06-15T12:34:56Z" faker::date::between(1609459200, 1640995200, DateFormat::Timestamp); //
* Returns the Unix timestamp of a random date between Jan 1, 2021, and Jan 1, 2022
* @endcode
*/
FAKER_CXX_EXPORT std::string between(int64_t from, int64_t to, DateFormat dateFormat = DateFormat::ISO);

/**
* @brief Generates a random date between two given ISO date strings.
*
* @param from The starting ISO date string in the format "YYYY-MM-DDTHH:MM:SSZ".
* @param to The ending ISO date string in the format "YYYY-MM-DDTHH:MM:SSZ".
* @param dateFormat Specifies the format of the output date, either as an ISO string or a Unix timestamp.
* @returns A string representing the random date in the specified format.
*
* @code
* faker::date::between("2021-01-01T00:00:00Z", "2022-01-01T00:00:00Z", DateFormat::ISO); // Returns a random date
* between Jan 1, 2021, and Jan 1, 2022, formatted as "2021-06-15T12:34:56Z"
* faker::date::between("2021-01-01T00:00:00Z", "2022-01-01T00:00:00Z", DateFormat::Timestamp); // Returns the Unix
* timestamp of a random date between Jan 1, 2021, and Jan 1, 2022
* @endcode
*/
FAKER_CXX_EXPORT std::string between(std::string from, std::string to, DateFormat dateFormat);
}
29 changes: 27 additions & 2 deletions src/modules/date.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,39 @@ std::string betweenDate(const auto& from, const auto& to, DateFormat dateFormat)
return serializeTimePoint(randomDateWithinRange, dateFormat);
}

std::string between(std::string from, std::string to, DateFormat dateFormat)
{
std::istringstream fromStream(from);
std::istringstream toStream(to);

std::tm fromTm{}, toTm{};

fromStream >> std::get_time(&fromTm, "%Y-%m-%dT%H:%M:%SZ");
toStream >> std::get_time(&toTm, "%Y-%m-%dT%H:%M:%SZ");

auto fromTimePoint = std::chrono::system_clock::from_time_t(std::mktime(&fromTm));
auto toTimePoint = std::chrono::system_clock::from_time_t(std::mktime(&toTm));

return betweenDate(fromTimePoint, toTimePoint, dateFormat);
}

std::string between(int64_t from, int64_t to, DateFormat dateFormat)
{
const auto fromTimePoint = std::chrono::system_clock::from_time_t(from);
const auto toTimePoint = std::chrono::system_clock::from_time_t(to);

return betweenDate(fromTimePoint, toTimePoint, dateFormat);
}

const auto numberOfHoursInDay = 24;
const auto numberOfDaysInYear = 365;

std::string anytime(DateFormat dateFormat)
{
constexpr int64_t total_seconds = 3600LL * 24LL* 365LL * 200LL; // sec/hr * hr/d * d/yr * years
constexpr int64_t total_seconds = 3600LL * 24LL * 365LL * 200LL; // sec/hr * hr/d * d/yr * years

int64_t now_seconds = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
int64_t now_seconds =
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
int64_t max_seconds = now_seconds + total_seconds;

std::random_device rd;
Expand Down
67 changes: 65 additions & 2 deletions tests/modules/date_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ TEST_F(DateTest, shouldGenerateFutureDateTimestamp)
EXPECT_TRUE(std::chrono::duration_cast<std::chrono::seconds>(futureDate - currentDate).count() < secondsInYear);
EXPECT_TRUE(futureDate > currentDate);
}

TEST_F(DateTest, shouldGenerateAnytimeISO)
{
const auto currentDate = std::chrono::system_clock::now();
Expand All @@ -138,7 +139,9 @@ TEST_F(DateTest, shouldGenerateAnytimeISO)
EXPECT_GT(generatedDate, unixEpoch);

auto duration = generatedDate - currentDate;
double durationInYears = static_cast<double>(std::chrono::duration_cast<std::chrono::seconds>(duration).count()) / (365.25 * 24 * 3600);
double durationInYears =
static_cast<double>(std::chrono::duration_cast<std::chrono::seconds>(duration).count()) /
(365.25 * 24 * 3600);
durationInYears = std::abs(durationInYears);
EXPECT_LT(durationInYears, 201);
}
Expand All @@ -157,7 +160,9 @@ TEST_F(DateTest, shouldGenerateAnytimeTimestamp)
EXPECT_GT(generatedDate, unixEpoch);

auto duration = generatedDate - currentDate;
double durationInYears = static_cast<double>(std::chrono::duration_cast<std::chrono::seconds>(duration).count()) / (365.25 * 24 * 3600);
double durationInYears =
static_cast<double>(std::chrono::duration_cast<std::chrono::seconds>(duration).count()) /
(365.25 * 24 * 3600);
durationInYears = std::abs(durationInYears);
EXPECT_LT(durationInYears, 201);
}
Expand Down Expand Up @@ -386,3 +391,61 @@ TEST_F(DateTest, shouldGenerateRandomTime)
ASSERT_LE(minute, 59);
ASSERT_GE(minute, 0);
}

TEST_F(DateTest, shouldGenerateDateBetweenTimestampDates)
{
int64_t fromTimestamp = 1609459200;
int64_t toTimestamp = 1640995200;

auto generatedTimestampStr = between(fromTimestamp, toTimestamp, DateFormat::Timestamp);
int64_t generatedTimestamp = std::stoll(generatedTimestampStr);

ASSERT_GE(generatedTimestamp, fromTimestamp);
ASSERT_LE(generatedTimestamp, toTimestamp);
}

TEST_F(DateTest, shouldGenerateDateBetweenTimestampDatesInISOFormat)
{
int64_t fromTimestamp = 1609459200;
int64_t toTimestamp = 1640995200;

auto generatedDateISO = between(fromTimestamp, toTimestamp, DateFormat::ISO);
auto generatedDate = parseISOFormattedStringToTimePoint(generatedDateISO);

auto fromTime = std::chrono::system_clock::from_time_t(fromTimestamp);
auto toTime = std::chrono::system_clock::from_time_t(toTimestamp);

ASSERT_GE(generatedDate, fromTime);
ASSERT_LE(generatedDate, toTime);
}

TEST_F(DateTest, shouldGenerateDateBetweenISODates)
{
std::string fromISO = "2021-01-01T00:00:00Z";
std::string toISO = "2022-01-01T00:00:00Z";

auto generatedDateISO = between(fromISO, toISO, DateFormat::ISO);
auto generatedDate = parseISOFormattedStringToTimePoint(generatedDateISO);

auto fromTime = parseISOFormattedStringToTimePoint(fromISO);
auto toTime = parseISOFormattedStringToTimePoint(toISO);

ASSERT_GE(generatedDate, fromTime);
ASSERT_LE(generatedDate, toTime);
}

TEST_F(DateTest, shouldGenerateDateBetweenISODatesInTimestampFormat)
{
std::string fromISO = "2021-01-01T00:00:00Z";
std::string toISO = "2022-01-01T00:00:00Z";

auto generatedTimestampStr = between(fromISO, toISO, DateFormat::Timestamp);
int64_t generatedTimestamp = std::stoll(generatedTimestampStr);

auto fromTime = parseISOFormattedStringToTimePoint(fromISO);
auto toTime = parseISOFormattedStringToTimePoint(toISO);
auto generatedTime = std::chrono::system_clock::from_time_t(generatedTimestamp);

ASSERT_GE(generatedTime, fromTime);
ASSERT_LE(generatedTime, toTime);
}

0 comments on commit f8fa805

Please sign in to comment.