You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by fg...@apache.org on 2022/06/27 11:06:33 UTC
[nifi-minifi-cpp] 01/02: MINIFICPP-1842 getTimeStr should use std::chrono
This is an automated email from the ASF dual-hosted git repository.
fgerlits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit 58a3041fa0efc635b5f6a8fedafda55f3448e676
Author: Martin Zink <ma...@apache.org>
AuthorDate: Thu May 19 09:37:42 2022 +0200
MINIFICPP-1842 getTimeStr should use std::chrono
Also fixes MINIFICPP-1700 Change leftover integers to std::chrono in ListSFTP.
Signed-off-by: Ferenc Gerlits <fg...@gmail.com>
This closes #1352
---
extensions/sftp/processors/ListSFTP.cpp | 85 ++++++------
extensions/sftp/processors/ListSFTP.h | 6 +-
extensions/sftp/processors/PutSFTP.cpp | 19 ++-
extensions/sftp/tests/ListSFTPTests.cpp | 3 +-
.../processors/LogAttribute.cpp | 4 +-
libminifi/include/core/Property.h | 10 --
libminifi/include/utils/TimeUtil.h | 144 +++++----------------
libminifi/include/utils/tls/CertificateUtils.h | 14 +-
libminifi/src/controllers/SSLContextService.cpp | 4 +-
libminifi/src/utils/tls/CertificateUtils.cpp | 16 +--
libminifi/test/unit/PropertyTests.cpp | 33 +----
libminifi/test/unit/TimeUtilTests.cpp | 133 ++++++++++---------
12 files changed, 167 insertions(+), 304 deletions(-)
diff --git a/extensions/sftp/processors/ListSFTP.cpp b/extensions/sftp/processors/ListSFTP.cpp
index 573eeb50f..83b67b2bd 100644
--- a/extensions/sftp/processors/ListSFTP.cpp
+++ b/extensions/sftp/processors/ListSFTP.cpp
@@ -63,6 +63,21 @@ constexpr char const* ListSFTP::TARGET_SYSTEM_TIMESTAMP_PRECISION_MINUTES;
constexpr char const* ListSFTP::ENTITY_TRACKING_INITIAL_LISTING_TARGET_TRACKING_TIME_WINDOW;
constexpr char const* ListSFTP::ENTITY_TRACKING_INITIAL_LISTING_TARGET_ALL_AVAILABLE;
+namespace {
+uint64_t toUnixTime(const std::optional<std::chrono::system_clock::time_point> time_point) {
+ if (!time_point)
+ return 0;
+ return std::chrono::duration_cast<std::chrono::milliseconds>(time_point->time_since_epoch()).count();
+}
+
+std::optional<std::chrono::system_clock::time_point> fromUnixTime(const uint64_t timestamp) {
+ if (timestamp == 0)
+ return std::nullopt;
+ return std::chrono::system_clock::time_point{std::chrono::milliseconds{timestamp}};
+}
+
+} // namespace
+
void ListSFTP::initialize() {
logger_->log_trace("Initializing FetchSFTP");
@@ -82,8 +97,6 @@ ListSFTP::ListSFTP(const std::string& name, const utils::Identifier& uuid /*= ut
, minimum_file_size_(0U)
, maximum_file_size_(0U)
, already_loaded_from_cache_(false)
- , last_listed_latest_entry_timestamp_(0U)
- , last_processed_latest_entry_timestamp_(0U)
, initial_listing_complete_(false) {
logger_ = core::logging::LoggerFactory<ListSFTP>::getLogger();
}
@@ -174,8 +187,8 @@ void ListSFTP::invalidateCache() {
already_loaded_from_cache_ = false;
last_run_time_ = std::chrono::steady_clock::time_point();
- last_listed_latest_entry_timestamp_ = 0U;
- last_processed_latest_entry_timestamp_ = 0U;
+ last_listed_latest_entry_timestamp_.reset();
+ last_processed_latest_entry_timestamp_.reset();
latest_identifiers_processed_.clear();
initial_listing_complete_ = false;
@@ -323,11 +336,7 @@ bool ListSFTP::createAndTransferFlowFileFromChild(
logger_->log_error("Modification date %lu of \"%s/%s\" larger than int64_t max", child.attrs.mtime, child.parent_path.c_str(), child.filename.c_str());
return true;
}
- std::string mtime_str;
- if (!utils::timeutils::getDateTimeStr(gsl::narrow<int64_t>(child.attrs.mtime), mtime_str)) {
- logger_->log_error("Failed to convert modification date %lu of \"%s/%s\" to string", child.attrs.mtime, child.parent_path.c_str(), child.filename.c_str());
- return true;
- }
+ auto mtime_str = utils::timeutils::getDateTimeStr(date::sys_seconds{std::chrono::seconds(child.attrs.mtime)});
/* Create FlowFile */
auto flow_file = session->create();
@@ -380,8 +389,8 @@ bool ListSFTP::persistTrackingTimestampsCache(const std::shared_ptr<core::Proces
state["hostname"] = hostname;
state["username"] = username;
state["remote_path"] = remote_path;
- state["listing.timestamp"] = std::to_string(last_listed_latest_entry_timestamp_);
- state["processed.timestamp"] = std::to_string(last_processed_latest_entry_timestamp_);
+ state["listing.timestamp"] = std::to_string(toUnixTime(last_listed_latest_entry_timestamp_));
+ state["processed.timestamp"] = std::to_string(toUnixTime(last_processed_latest_entry_timestamp_));
size_t i = 0;
for (const auto& identifier : latest_identifiers_processed_) {
state["id." + std::to_string(i)] = identifier;
@@ -464,8 +473,8 @@ bool ListSFTP::updateFromTrackingTimestampsCache(const std::shared_ptr<core::Pro
return false;
}
- last_listed_latest_entry_timestamp_ = state_listing_timestamp;
- last_processed_latest_entry_timestamp_ = state_processed_timestamp;
+ last_listed_latest_entry_timestamp_ = fromUnixTime(state_listing_timestamp);
+ last_processed_latest_entry_timestamp_ = fromUnixTime(state_processed_timestamp);
latest_identifiers_processed_ = std::move(state_ids);
return true;
@@ -479,7 +488,7 @@ void ListSFTP::listByTrackingTimestamps(
const std::string& username,
const std::string& remote_path,
std::vector<Child>&& files) {
- uint64_t min_timestamp_to_list = last_listed_latest_entry_timestamp_;
+ auto min_timestamp_to_list = last_listed_latest_entry_timestamp_;
/* Load state from cache file if needed */
if (!already_loaded_from_cache_) {
@@ -492,16 +501,16 @@ void ListSFTP::listByTrackingTimestamps(
}
std::chrono::steady_clock::time_point current_run_time = std::chrono::steady_clock::now();
- time_t now = time(nullptr);
+ auto now = std::chrono::system_clock::now();
/* Order children by timestamp and try to detect timestamp precision if needed */
- std::map<uint64_t /*timestamp*/, std::list<Child>> ordered_files;
+ std::map<std::chrono::system_clock::time_point, std::list<Child>> ordered_files;
bool target_system_has_seconds = false;
for (auto&& file : files) {
- uint64_t timestamp = file.attrs.mtime * 1000;
- target_system_has_seconds |= timestamp % 60000 != 0;
+ std::chrono::system_clock::time_point timestamp{std::chrono::seconds(file.attrs.mtime)};
+ target_system_has_seconds |= std::chrono::round<std::chrono::minutes>(timestamp) != timestamp;
- bool new_file = min_timestamp_to_list == 0U || (timestamp >= min_timestamp_to_list && timestamp >= last_processed_latest_entry_timestamp_);
+ bool new_file = !min_timestamp_to_list.has_value() || (timestamp >= min_timestamp_to_list && timestamp >= last_processed_latest_entry_timestamp_);
if (new_file) {
auto& files_for_timestamp = ordered_files[timestamp];
files_for_timestamp.emplace_back(std::move(file));
@@ -510,9 +519,9 @@ void ListSFTP::listByTrackingTimestamps(
}
}
- uint64_t latest_listed_entry_timestamp_this_cycle = 0U;
+ std::optional<std::chrono::system_clock::time_point> latest_listed_entry_timestamp_this_cycle;
size_t flow_files_created = 0U;
- if (ordered_files.size() > 0) {
+ if (!ordered_files.empty()) {
latest_listed_entry_timestamp_this_cycle = ordered_files.crbegin()->first;
std::string remote_system_timestamp_precision;
@@ -533,20 +542,20 @@ void ListSFTP::listByTrackingTimestamps(
*/
remote_system_timestamp_precision = TARGET_SYSTEM_TIMESTAMP_PRECISION_SECONDS;
}
- uint64_t listing_lag = LISTING_LAG_MAP.at(remote_system_timestamp_precision);
- logger_->log_debug("The listing lag is %lu ms", listing_lag);
+ std::chrono::milliseconds listing_lag{LISTING_LAG_MAP.at(remote_system_timestamp_precision)};
+ logger_->log_debug("The listing lag is %lu ms", listing_lag.count());
/* If the latest listing time is equal to the last listing time, there are no entries with a newer timestamp than previously seen */
- if (latest_listed_entry_timestamp_this_cycle == last_listed_latest_entry_timestamp_) {
- const auto& latest_files = ordered_files.at(latest_listed_entry_timestamp_this_cycle);
- uint64_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_run_time - last_run_time_).count();
+ if (latest_listed_entry_timestamp_this_cycle == last_listed_latest_entry_timestamp_ && latest_listed_entry_timestamp_this_cycle) {
+ const auto& latest_files = ordered_files.at(*latest_listed_entry_timestamp_this_cycle);
+ auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(current_run_time - last_run_time_);
/* If a precision-specific listing lag has not yet elapsed since out last execution, we wait. */
if (elapsed_time < listing_lag) {
logger_->log_debug("The latest listed entry timestamp is the same as the last listed entry timestamp (%lu) "
"and the listing lag has not yet elapsed (%lu ms < % lu ms). Yielding.",
- latest_listed_entry_timestamp_this_cycle,
- elapsed_time,
- listing_lag);
+ toUnixTime(latest_listed_entry_timestamp_this_cycle),
+ elapsed_time.count(),
+ listing_lag.count());
context->yield();
return;
}
@@ -559,24 +568,24 @@ void ListSFTP::listByTrackingTimestamps(
return latest_identifiers_processed_.count(child.getPath()) == 1U;
})) {
logger_->log_debug("The latest listed entry timestamp is the same as the last listed entry timestamp (%lu) "
- "and all files for that timestamp has been processed. Yielding.", latest_listed_entry_timestamp_this_cycle);
+ "and all files for that timestamp has been processed. Yielding.", toUnixTime(latest_listed_entry_timestamp_this_cycle));
context->yield();
return;
}
} else {
/* Determine the minimum reliable timestamp based on precision */
- uint64_t minimum_reliable_timestamp = now * 1000 - listing_lag;
+ auto minimum_reliable_timestamp = now - listing_lag;
if (remote_system_timestamp_precision == TARGET_SYSTEM_TIMESTAMP_PRECISION_SECONDS) {
- minimum_reliable_timestamp -= minimum_reliable_timestamp % 1000;
+ std::chrono::floor<std::chrono::seconds>(minimum_reliable_timestamp);
} else {
- minimum_reliable_timestamp -= minimum_reliable_timestamp % 60000;
+ std::chrono::floor<std::chrono::minutes>(minimum_reliable_timestamp);
}
/* If the latest timestamp is not old enough, we wait another cycle */
- if (minimum_reliable_timestamp < latest_listed_entry_timestamp_this_cycle) {
+ if (latest_listed_entry_timestamp_this_cycle && minimum_reliable_timestamp < latest_listed_entry_timestamp_this_cycle) {
logger_->log_debug("Skipping files with latest timestamp because their modification date is not smaller than the minimum reliable timestamp: %lu ms >= %lu ms",
- latest_listed_entry_timestamp_this_cycle,
- minimum_reliable_timestamp);
- ordered_files.erase(latest_listed_entry_timestamp_this_cycle);
+ toUnixTime(latest_listed_entry_timestamp_this_cycle),
+ toUnixTime(minimum_reliable_timestamp));
+ ordered_files.erase(*latest_listed_entry_timestamp_this_cycle);
}
}
@@ -605,7 +614,7 @@ void ListSFTP::listByTrackingTimestamps(
}
/* If we have a listing timestamp, it is worth persisting the state */
- if (latest_listed_entry_timestamp_this_cycle != 0U) {
+ if (latest_listed_entry_timestamp_this_cycle) {
bool processed_new_files = flow_files_created > 0U;
if (processed_new_files) {
auto last_files_it = ordered_files.crbegin();
diff --git a/extensions/sftp/processors/ListSFTP.h b/extensions/sftp/processors/ListSFTP.h
index 16d98193f..871aea98a 100644
--- a/extensions/sftp/processors/ListSFTP.h
+++ b/extensions/sftp/processors/ListSFTP.h
@@ -144,7 +144,7 @@ class ListSFTP : public SFTPProcessorBase {
struct Child {
Child();
Child(const std::string& parent_path_, std::tuple<std::string /* filename */, std::string /* longentry */, LIBSSH2_SFTP_ATTRIBUTES /* attrs */>&& sftp_child);
- std::string getPath() const;
+ [[nodiscard]] std::string getPath() const;
bool directory;
std::string parent_path;
@@ -155,8 +155,8 @@ class ListSFTP : public SFTPProcessorBase {
bool already_loaded_from_cache_;
std::chrono::steady_clock::time_point last_run_time_;
- uint64_t last_listed_latest_entry_timestamp_;
- uint64_t last_processed_latest_entry_timestamp_;
+ std::optional<std::chrono::system_clock::time_point> last_listed_latest_entry_timestamp_;
+ std::optional<std::chrono::system_clock::time_point> last_processed_latest_entry_timestamp_;
std::set<std::string> latest_identifiers_processed_;
bool initial_listing_complete_;
diff --git a/extensions/sftp/processors/PutSFTP.cpp b/extensions/sftp/processors/PutSFTP.cpp
index 1efe850cb..b167f649e 100644
--- a/extensions/sftp/processors/PutSFTP.cpp
+++ b/extensions/sftp/processors/PutSFTP.cpp
@@ -117,8 +117,7 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c
std::string remote_path;
bool disable_directory_listing = false;
std::string temp_file_name;
- bool last_modified_time_set = false;
- int64_t last_modified_time = 0U;
+ std::optional<std::chrono::system_clock::time_point> last_modified_;
bool permissions_set = false;
uint32_t permissions = 0U;
bool remote_owner_set = false;
@@ -143,11 +142,9 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c
disable_directory_listing = utils::StringUtils::toBool(value).value_or(false);
}
context->getProperty(TempFilename, temp_file_name, flow_file);
- if (context->getProperty(LastModifiedTime, value, flow_file)) {
- if (core::Property::StringToDateTime(value, last_modified_time)) {
- last_modified_time_set = true;
- }
- }
+ if (context->getProperty(LastModifiedTime, value, flow_file))
+ last_modified_ = utils::timeutils::parseDateTimeStr(value);
+
if (context->getProperty(Permissions, value, flow_file)) {
if (core::Property::StringToPermissions(value, permissions)) {
permissions_set = true;
@@ -328,21 +325,21 @@ bool PutSFTP::processOne(const std::shared_ptr<core::ProcessContext> &context, c
}
/* Set file attributes if needed */
- if (last_modified_time_set ||
+ if (last_modified_ ||
permissions_set ||
remote_owner_set ||
remote_group_set) {
utils::SFTPClient::SFTPAttributes attrs;
attrs.flags = 0U;
- if (last_modified_time_set) {
+ if (last_modified_) {
/*
* NiFi doesn't set atime, only mtime, but because they can only be set together,
* if we don't want to modify atime, we first have to get it.
* Therefore setting them both saves an extra protocol round.
*/
attrs.flags |= utils::SFTPClient::SFTP_ATTRIBUTE_MTIME | utils::SFTPClient::SFTP_ATTRIBUTE_ATIME;
- attrs.mtime = last_modified_time;
- attrs.atime = last_modified_time;
+ attrs.mtime = std::chrono::duration_cast<std::chrono::seconds>(last_modified_->time_since_epoch()).count();
+ attrs.atime = std::chrono::duration_cast<std::chrono::seconds>(last_modified_->time_since_epoch()).count();
}
if (permissions_set) {
attrs.flags |= utils::SFTPClient::SFTP_ATTRIBUTE_PERMISSIONS;
diff --git a/extensions/sftp/tests/ListSFTPTests.cpp b/extensions/sftp/tests/ListSFTPTests.cpp
index 5f9c7c415..a51961653 100644
--- a/extensions/sftp/tests/ListSFTPTests.cpp
+++ b/extensions/sftp/tests/ListSFTPTests.cpp
@@ -234,8 +234,7 @@ TEST_CASE_METHOD(ListSFTPTestsFixture, "ListSFTP list one file writes attributes
testController.runSession(plan, true);
auto file = src_dir + "/vfs/nifi_test/tstFile.ext";
- std::string mtime_str;
- REQUIRE(true == utils::timeutils::getDateTimeStr(utils::file::to_time_t(utils::file::last_write_time(file).value()), mtime_str));
+ auto mtime_str = utils::timeutils::getDateTimeStr(std::chrono::time_point_cast<std::chrono::seconds>(utils::file::to_sys(utils::file::last_write_time(file).value())));
uint64_t uid, gid;
REQUIRE(true == utils::file::FileUtils::get_uid_gid(file, uid, gid));
uint32_t permissions;
diff --git a/extensions/standard-processors/processors/LogAttribute.cpp b/extensions/standard-processors/processors/LogAttribute.cpp
index dec826cb9..6791a952b 100644
--- a/extensions/standard-processors/processors/LogAttribute.cpp
+++ b/extensions/standard-processors/processors/LogAttribute.cpp
@@ -111,8 +111,8 @@ void LogAttribute::onTrigger(const std::shared_ptr<core::ProcessContext> &contex
message << dashLine;
message << "\nStandard FlowFile Attributes";
message << "\n" << "UUID:" << flow->getUUIDStr();
- message << "\n" << "EntryDate:" << utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(flow->getEntryDate().time_since_epoch()).count());
- message << "\n" << "lineageStartDate:" << utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(flow->getlineageStartDate().time_since_epoch()).count());
+ message << "\n" << "EntryDate:" << utils::timeutils::getTimeStr(flow->getEntryDate());
+ message << "\n" << "lineageStartDate:" << utils::timeutils::getTimeStr(flow->getlineageStartDate());
message << "\n" << "Size:" << flow->getSize() << " Offset:" << flow->getOffset();
message << "\nFlowFile Attributes Map Content";
std::map<std::string, std::string> attrs = flow->getAttributes();
diff --git a/libminifi/include/core/Property.h b/libminifi/include/core/Property.h
index 2b81b39c2..5ba79d1b4 100644
--- a/libminifi/include/core/Property.h
+++ b/libminifi/include/core/Property.h
@@ -165,16 +165,6 @@ class Property {
// Compare
bool operator <(const Property & right) const;
-
- static bool StringToDateTime(const std::string& input, int64_t& output) {
- int64_t temp = utils::timeutils::parseDateTimeStr(input);
- if (temp == -1) {
- return false;
- }
- output = temp;
- return true;
- }
-
static bool StringToPermissions(const std::string& input, uint32_t& output) {
uint32_t temp = 0U;
if (input.size() == 9U) {
diff --git a/libminifi/include/utils/TimeUtil.h b/libminifi/include/utils/TimeUtil.h
index 5a352947c..dbcf31014 100644
--- a/libminifi/include/utils/TimeUtil.h
+++ b/libminifi/include/utils/TimeUtil.h
@@ -86,125 +86,45 @@ class SteadyClock : public Clock {
}
};
-/**
- * Returns a string based on TIME_FORMAT, converting
- * the parameter to a string
- * @param msec milliseconds since epoch
- * @returns string representing the time
- */
-inline std::string getTimeStr(uint64_t msec, bool enforce_locale = false) {
- char date[120];
- time_t second = (time_t) (msec / 1000);
- msec = msec % 1000;
- strftime(date, sizeof(date) / sizeof(*date), TIME_FORMAT, (enforce_locale == true ? gmtime(&second) : localtime(&second)));
-
- std::string ret = date;
- date[0] = '\0';
- sprintf(date, ".%03llu", (unsigned long long) msec); // NOLINT
-
- ret += date;
- return ret;
+inline std::string getTimeStr(std::chrono::system_clock::time_point tp) {
+ std::ostringstream stream;
+ date::to_stream(stream, TIME_FORMAT, std::chrono::floor<std::chrono::milliseconds>(tp));
+ return stream.str();
}
-inline time_t mkgmtime(struct tm* date_time) {
-#ifdef WIN32
- return _mkgmtime(date_time);
-#else
- static const int month_lengths[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- static const int month_lengths_leap[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- static const auto is_leap_year = [](int year) -> bool {
- return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
- };
- static const auto num_leap_days = [](int year) -> int {
- return (year - 1968) / 4 - (year - 1900) / 100 + (year - 1600) / 400;
- };
-
- int year = date_time->tm_year + 1900;
- time_t result = year - 1970;
- result *= 365;
- result += num_leap_days(year - 1);
-
- for (int i = 0; i < 12 && i < date_time->tm_mon; ++i) {
- result += is_leap_year(year) ? month_lengths_leap[i] : month_lengths[i];
- }
-
- result += date_time->tm_mday - 1;
- result *= 24;
-
- result += date_time->tm_hour;
- result *= 60;
-
- result += date_time->tm_min;
- result *= 60;
-
- result += date_time->tm_sec;
- return result;
-#endif
+inline std::optional<std::chrono::sys_seconds> parseDateTimeStr(const std::string& str) {
+ std::istringstream stream(str);
+ std::chrono::sys_seconds tp;
+ date::from_stream(stream, "%Y-%m-%dT%H:%M:%SZ", tp);
+ if (stream.fail() || (stream.peek() && !stream.eof()))
+ return std::nullopt;
+ return tp;
}
-/**
- * Parse a datetime in yyyy-MM-dd'T'HH:mm:ssZ format
- * @param str the datetime string
- * @returns Unix timestamp
- */
-inline int64_t parseDateTimeStr(const std::string& str) {
- /**
- * There is no strptime on Windows. As long as we have to parse a single date format this is not so bad,
- * but if multiple formats will have to be supported in the future, it might be worth it to include
- * an strptime implementation from some BSD on Windows.
- */
- uint32_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hours;
- uint8_t minutes;
- uint8_t seconds;
- int read = 0;
- if (sscanf(str.c_str(), "%4u-%2hhu-%2hhuT%2hhu:%2hhu:%2hhuZ%n", &year, &month, &day, &hours, &minutes, &seconds, &read) != 6) {
- return -1;
- }
- // while it is unlikely that read will be < 0, the conditional adds little cost for a little defensiveness.
- if (read < 0 || static_cast<size_t>(read) != str.size()) {
- return -1;
- }
-
- if (year < 1970U ||
- month > 12U ||
- day > 31U ||
- hours > 23U ||
- minutes > 59U ||
- seconds > 60U) {
- return -1;
- }
-
- struct tm timeinfo{};
- timeinfo.tm_year = year - 1900;
- timeinfo.tm_mon = month - 1;
- timeinfo.tm_mday = day;
- timeinfo.tm_hour = hours;
- timeinfo.tm_min = minutes;
- timeinfo.tm_sec = seconds;
- timeinfo.tm_isdst = 0;
-
- return static_cast<int64_t>(mkgmtime(&timeinfo));
+inline std::string getDateTimeStr(std::chrono::sys_seconds tp) {
+ std::ostringstream stream;
+ date::to_stream(stream, "%Y-%m-%dT%H:%M:%SZ", std::chrono::floor<std::chrono::seconds>(tp));
+ return stream.str();
}
-inline bool getDateTimeStr(int64_t unix_timestamp, std::string& date_time_str) {
- if (unix_timestamp > (std::numeric_limits<time_t>::max)() || unix_timestamp < (std::numeric_limits<time_t>::lowest)()) {
- return false;
- }
- time_t time = static_cast<time_t>(unix_timestamp);
- struct tm* gmt = gmtime(&time); // NOLINT
- if (gmt == nullptr) {
- return false;
- }
- std::array<char, 64U> buf;
- if (strftime(buf.data(), buf.size(), "%Y-%m-%dT%H:%M:%SZ", gmt) == 0U) {
- return false;
- }
+inline date::sys_seconds to_sys_time(const std::tm& t) {
+ using date::year;
+ using date::month;
+ using date::day;
+ using std::chrono::hours;
+ using std::chrono::minutes;
+ using std::chrono::seconds;
+ return date::sys_days{year{t.tm_year + 1900}/(t.tm_mon+1)/t.tm_mday} + hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec};
+}
- date_time_str = buf.data();
- return true;
+inline date::local_seconds to_local_time(const std::tm& t) {
+ using date::year;
+ using date::month;
+ using date::day;
+ using std::chrono::hours;
+ using std::chrono::minutes;
+ using std::chrono::seconds;
+ return date::local_days{year{t.tm_year + 1900}/(t.tm_mon+1)/t.tm_mday} + hours{t.tm_hour} + minutes{t.tm_min} + seconds{t.tm_sec};
}
namespace details {
diff --git a/libminifi/include/utils/tls/CertificateUtils.h b/libminifi/include/utils/tls/CertificateUtils.h
index 73e7011fc..64f0d65f7 100644
--- a/libminifi/include/utils/tls/CertificateUtils.h
+++ b/libminifi/include/utils/tls/CertificateUtils.h
@@ -33,12 +33,7 @@
#include "WindowsCertStoreLocation.h"
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace utils {
-namespace tls {
+namespace org::apache::nifi::minifi::utils::tls {
class ssl_error_category : public std::error_category {
public:
@@ -114,11 +109,6 @@ std::error_code processP12Certificate(const std::string& cert_file, const std::s
std::error_code processPEMCertificate(const std::string& cert_file, const std::optional<std::string>& passphrase, const CertHandler& handler);
-} // namespace tls
-} // namespace utils
-} // namespace minifi
-} // namespace nifi
-} // namespace apache
-} // namespace org
+} // namespace org::apache::nifi::minifi::utils::tls
#endif // OPENSSL_SUPPORT
diff --git a/libminifi/src/controllers/SSLContextService.cpp b/libminifi/src/controllers/SSLContextService.cpp
index d91563f9f..76c178aa7 100644
--- a/libminifi/src/controllers/SSLContextService.cpp
+++ b/libminifi/src/controllers/SSLContextService.cpp
@@ -149,7 +149,7 @@ bool SSLContextService::configure_ssl_context(SSL_CTX *ctx) {
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, nullptr);
if (!IsNullOrEmpty(ca_certificate_)) {
- if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), 0) == 0) {
+ if (SSL_CTX_load_verify_locations(ctx, ca_certificate_.c_str(), nullptr) == 0) {
core::logging::LOG_ERROR(logger_) << "Cannot load CA certificate, exiting, " << getLatestOpenSSLErrorString();
return false;
}
@@ -545,7 +545,7 @@ void SSLContextService::initializeProperties() {
void SSLContextService::verifyCertificateExpiration() {
auto verify = [&] (const std::string& cert_file, const utils::tls::X509_unique_ptr& cert) {
if (auto end_date = utils::tls::getCertificateExpiration(cert)) {
- std::string end_date_str = utils::timeutils::getTimeStr(std::chrono::duration_cast<std::chrono::milliseconds>(end_date->time_since_epoch()).count());
+ std::string end_date_str = utils::timeutils::getTimeStr(*end_date);
if (end_date.value() < std::chrono::system_clock::now()) {
core::logging::LOG_ERROR(logger_) << "Certificate in '" << cert_file << "' expired at " << end_date_str;
} else if (auto diff = end_date.value() - std::chrono::system_clock::now(); diff < std::chrono::weeks{2}) {
diff --git a/libminifi/src/utils/tls/CertificateUtils.cpp b/libminifi/src/utils/tls/CertificateUtils.cpp
index 6fe4fe1bf..453a8d750 100644
--- a/libminifi/src/utils/tls/CertificateUtils.cpp
+++ b/libminifi/src/utils/tls/CertificateUtils.cpp
@@ -30,12 +30,7 @@
#include "utils/tls/TLSUtils.h"
#include "utils/TimeUtil.h"
-namespace org {
-namespace apache {
-namespace nifi {
-namespace minifi {
-namespace utils {
-namespace tls {
+namespace org::apache::nifi::minifi::utils::tls {
const ssl_error_category& ssl_error_category::get() {
static ssl_error_category instance;
@@ -181,7 +176,7 @@ std::optional<std::chrono::system_clock::time_point> getCertificateExpiration(co
if (ret == -1) {
return {};
}
- return std::chrono::system_clock::from_time_t(utils::timeutils::mkgmtime(&end));
+ return utils::timeutils::to_sys_time(end);
}
std::error_code processP12Certificate(const std::string& cert_file, const std::string& passphrase, const CertHandler& handler) {
@@ -265,11 +260,6 @@ std::error_code processPEMCertificate(const std::string& cert_file, const std::o
return {};
}
-} // namespace tls
-} // namespace utils
-} // namespace minifi
-} // namespace nifi
-} // namespace apache
-} // namespace org
+} // namespace org::apache::nifi::minifi::utils::tls
#endif // OPENSSL_SUPPORT
diff --git a/libminifi/test/unit/PropertyTests.cpp b/libminifi/test/unit/PropertyTests.cpp
index b35b0aa18..c2eb1cfc3 100644
--- a/libminifi/test/unit/PropertyTests.cpp
+++ b/libminifi/test/unit/PropertyTests.cpp
@@ -19,10 +19,10 @@
#include <string>
#include "core/Property.h"
-#include "../../include/core/Property.h"
#include "utils/StringUtils.h"
#include "../TestBase.h"
#include "../Catch.h"
+
namespace {
enum class ConversionTestTarget { MS, NS };
@@ -126,35 +126,4 @@ TEST_CASE("Test Permissions Conversion", "[testPermissions]") {
REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToPermissions("foobar", permissions));
}
-
-TEST_CASE("Test DateTime Conversion", "[testDateTime]") {
- int64_t timestamp = 0LL;
-
- REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00Z", timestamp));
- REQUIRE(0LL == timestamp);
-
- REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:59:59Z", timestamp));
- REQUIRE(3600 - 1 == timestamp);
-
- REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2000-06-17T12:34:21Z", timestamp));
- REQUIRE(961245261LL == timestamp);
-
- REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2038-01-19T03:14:07Z", timestamp));
- REQUIRE(2147483647LL == timestamp);
-
- REQUIRE(true == org::apache::nifi::minifi::core::Property::StringToDateTime("2065-01-24T05:20:00Z", timestamp));
- REQUIRE(3000000000LL == timestamp);
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01A00:00:00Z", timestamp));
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00", timestamp));
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-01-01T00:00:00Zfoo", timestamp));
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1969-01-01T00:00:00Z", timestamp));
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("1970-13-01T00:00:00Z", timestamp));
-
- REQUIRE(false == org::apache::nifi::minifi::core::Property::StringToDateTime("foobar", timestamp));
-}
} // namespace
diff --git a/libminifi/test/unit/TimeUtilTests.cpp b/libminifi/test/unit/TimeUtilTests.cpp
index 0a96e5134..bd2518c02 100644
--- a/libminifi/test/unit/TimeUtilTests.cpp
+++ b/libminifi/test/unit/TimeUtilTests.cpp
@@ -21,79 +21,78 @@
using namespace std::literals::chrono_literals;
-namespace {
- constexpr int ONE_HOUR = 60 * 60;
- constexpr int ONE_DAY = 24 * ONE_HOUR;
-
- struct tm createTm(int year, int month, int day, int hour, int minute, int second, bool is_dst = false) {
- struct tm date_time;
- date_time.tm_year = year - 1900;
- date_time.tm_mon = month - 1;
- date_time.tm_mday = day;
- date_time.tm_hour = hour;
- date_time.tm_min = minute;
- date_time.tm_sec = second;
- date_time.tm_isdst = is_dst ? 1 : 0;
- return date_time;
- }
-
- void mkgmtimeTestHelper(time_t expected, int year, int month, int day, int hour, int minute, int second) {
- using org::apache::nifi::minifi::utils::timeutils::mkgmtime;
- struct tm date_time = createTm(year, month, day, hour, minute, second);
- REQUIRE(mkgmtime(&date_time) == expected);
- }
-} // namespace
+TEST_CASE("parseDateTimeStr() works correctly", "[parseDateTimeStr]") {
+ using org::apache::nifi::minifi::utils::timeutils::parseDateTimeStr;
-TEST_CASE("mkgmtime() works correctly", "[mkgmtime]") {
- mkgmtimeTestHelper(0, 1970, 1, 1, 0, 0, 0);
- for (int hour = 0; hour < 24; ++hour) {
- mkgmtimeTestHelper((hour + 1) * ONE_HOUR - 1, 1970, 1, 1, hour, 59, 59);
- }
-
- mkgmtimeTestHelper(ONE_DAY, 1970, 1, 2, 0, 0, 0);
- mkgmtimeTestHelper(31 * ONE_DAY, 1970, 2, 1, 0, 0, 0);
- mkgmtimeTestHelper(365 * ONE_DAY, 1971, 1, 1, 0, 0, 0);
-
- mkgmtimeTestHelper(793929600, 1995, 2, 28, 0, 0, 0);
- mkgmtimeTestHelper(793929600 + ONE_DAY, 1995, 3, 1, 0, 0, 0);
- mkgmtimeTestHelper(825465600, 1996, 2, 28, 0, 0, 0);
- mkgmtimeTestHelper(825465600 + ONE_DAY, 1996, 2, 29, 0, 0, 0);
- mkgmtimeTestHelper(951696000, 2000, 2, 28, 0, 0, 0);
- mkgmtimeTestHelper(951696000 + ONE_DAY, 2000, 2, 29, 0, 0, 0);
- mkgmtimeTestHelper(4107456000, 2100, 2, 28, 0, 0, 0);
- mkgmtimeTestHelper(4107456000 + ONE_DAY, 2100, 3, 1, 0, 0, 0);
-
- mkgmtimeTestHelper(1513104856, 2017, 12, 12, 18, 54, 16);
- mkgmtimeTestHelper(1706655675, 2024, 1, 30, 23, 01, 15);
- mkgmtimeTestHelper(3710453630, 2087, 7, 31, 01, 33, 50);
+ CHECK(*parseDateTimeStr("1970-01-01T00:00:00Z") == std::chrono::sys_seconds{0s});
+ CHECK(*parseDateTimeStr("1970-01-01T00:59:59Z") == std::chrono::sys_seconds{1h - 1s});
+
+ CHECK(*parseDateTimeStr("1970-01-02T00:00:00Z") == std::chrono::sys_seconds{std::chrono::days(1)});
+ CHECK(*parseDateTimeStr("1970-02-01T00:00:00Z") == std::chrono::sys_seconds{31 * std::chrono::days(1)});
+ CHECK(*parseDateTimeStr("1971-01-01T00:00:00Z") == std::chrono::sys_seconds{365 * std::chrono::days(1)});
+
+ CHECK(*parseDateTimeStr("1995-02-28T00:00:00Z") == std::chrono::sys_seconds{793929600s});
+ CHECK(*parseDateTimeStr("1995-03-01T00:00:00Z") == std::chrono::sys_seconds{793929600s + std::chrono::days(1)});
+ CHECK(*parseDateTimeStr("1996-02-28T00:00:00Z") == std::chrono::sys_seconds{825465600s});
+ CHECK(*parseDateTimeStr("1996-02-29T00:00:00Z") == std::chrono::sys_seconds{825465600s + std::chrono::days(1)});
+ CHECK(*parseDateTimeStr("2000-02-28T00:00:00Z") == std::chrono::sys_seconds{951696000s});
+ CHECK(*parseDateTimeStr("2000-02-29T00:00:00Z") == std::chrono::sys_seconds{951696000s + std::chrono::days(1)});
+ CHECK(*parseDateTimeStr("2100-02-28T00:00:00Z") == std::chrono::sys_seconds{4107456000s});
+ CHECK(*parseDateTimeStr("2100-03-01T00:00:00Z") == std::chrono::sys_seconds{4107456000s + std::chrono::days(1)});
+
+ CHECK(*parseDateTimeStr("2017-12-12T18:54:16Z") == std::chrono::sys_seconds{1513104856s});
+ CHECK(*parseDateTimeStr("2024-01-30T23:01:15Z") == std::chrono::sys_seconds{1706655675s});
+ CHECK(*parseDateTimeStr("2087-07-31T01:33:50Z") == std::chrono::sys_seconds{3710453630s});
}
-TEST_CASE("parseDateTimeStr() works correctly", "[parseDateTimeStr]") {
- using org::apache::nifi::minifi::utils::timeutils::parseDateTimeStr;
- REQUIRE(parseDateTimeStr("1970-01-01T00:00:00Z") == 0);
- REQUIRE(parseDateTimeStr("1970-01-01T00:59:59Z") == ONE_HOUR - 1);
-
- REQUIRE(parseDateTimeStr("1970-01-02T00:00:00Z") == ONE_DAY);
- REQUIRE(parseDateTimeStr("1970-02-01T00:00:00Z") == 31 * ONE_DAY);
- REQUIRE(parseDateTimeStr("1971-01-01T00:00:00Z") == 365 * ONE_DAY);
-
- REQUIRE(parseDateTimeStr("1995-02-28T00:00:00Z") == 793929600);
- REQUIRE(parseDateTimeStr("1995-03-01T00:00:00Z") == 793929600 + ONE_DAY);
- REQUIRE(parseDateTimeStr("1996-02-28T00:00:00Z") == 825465600);
- REQUIRE(parseDateTimeStr("1996-02-29T00:00:00Z") == 825465600 + ONE_DAY);
- REQUIRE(parseDateTimeStr("2000-02-28T00:00:00Z") == 951696000);
- REQUIRE(parseDateTimeStr("2000-02-29T00:00:00Z") == 951696000 + ONE_DAY);
- REQUIRE(parseDateTimeStr("2100-02-28T00:00:00Z") == 4107456000);
- REQUIRE(parseDateTimeStr("2100-03-01T00:00:00Z") == 4107456000 + ONE_DAY);
-
- REQUIRE(parseDateTimeStr("2017-12-12T18:54:16Z") == 1513104856);
- REQUIRE(parseDateTimeStr("2024-01-30T23:01:15Z") == 1706655675);
- REQUIRE(parseDateTimeStr("2087-07-31T01:33:50Z") == 3710453630);
+TEST_CASE("getDateTimeStr() works correctly", "[getDateTimeStr]") {
+ using org::apache::nifi::minifi::utils::timeutils::getDateTimeStr;
+
+ CHECK("1970-01-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{0s}));
+ CHECK("1970-01-01T00:59:59Z" == getDateTimeStr(std::chrono::sys_seconds{1h - 1s}));
+
+ CHECK("1970-01-02T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{std::chrono::days(1)}));
+ CHECK("1970-02-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{31 * std::chrono::days(1)}));
+ CHECK("1971-01-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{365 * std::chrono::days(1)}));
+
+ CHECK("1995-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{793929600s}));
+ CHECK("1995-03-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{793929600s + std::chrono::days(1)}));
+ CHECK("1996-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{825465600s}));
+ CHECK("1996-02-29T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{825465600s + std::chrono::days(1)}));
+ CHECK("2000-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{951696000s}));
+ CHECK("2000-02-29T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{951696000s + std::chrono::days(1)}));
+ CHECK("2100-02-28T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{4107456000s}));
+ CHECK("2100-03-01T00:00:00Z" == getDateTimeStr(std::chrono::sys_seconds{4107456000s + std::chrono::days(1)}));
+
+ CHECK("2017-12-12T18:54:16Z" == getDateTimeStr(std::chrono::sys_seconds{1513104856s}));
+ CHECK("2024-01-30T23:01:15Z" == getDateTimeStr(std::chrono::sys_seconds{1706655675s}));
+ CHECK("2087-07-31T01:33:50Z" == getDateTimeStr(std::chrono::sys_seconds{3710453630s}));
}
TEST_CASE("Test time conversion", "[testtimeconversion]") {
using org::apache::nifi::minifi::utils::timeutils::getTimeStr;
- REQUIRE("2017-02-16 20:14:56.196" == getTimeStr(1487276096196, true));
+ CHECK("2017-02-16 20:14:56.196" == getTimeStr(std::chrono::system_clock::time_point{1487276096196ms}));
+}
+
+TEST_CASE("Test DateTime Conversion", "[testDateTime]") {
+ using namespace date::literals;
+ using namespace std::literals::chrono_literals;
+ using date::year_month_day;
+ using date::sys_days;
+ using utils::timeutils::parseDateTimeStr;
+
+ CHECK(sys_days(date::year_month_day(1970_y/01/01)) == parseDateTimeStr("1970-01-01T00:00:00Z"));
+ CHECK(sys_days(year_month_day(1970_y/01/01)) + 0h + 59min + 59s == parseDateTimeStr("1970-01-01T00:59:59Z"));
+ CHECK(sys_days(year_month_day(2000_y/06/17)) + 12h + 34min + 21s == parseDateTimeStr("2000-06-17T12:34:21Z"));
+ CHECK(sys_days(year_month_day(2038_y/01/19)) + 3h + 14min + 7s == parseDateTimeStr("2038-01-19T03:14:07Z"));
+ CHECK(sys_days(year_month_day(2065_y/01/24)) + 5h + 20min + 0s == parseDateTimeStr("2065-01-24T05:20:00Z"));
+ CHECK(sys_days(year_month_day(1969_y/01/01)) == parseDateTimeStr("1969-01-01T00:00:00Z"));
+
+ CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01A00:00:00Z"));
+ CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01T00:00:00"));
+ CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-01-01T00:00:00Zfoo"));
+ CHECK_FALSE(utils::timeutils::parseDateTimeStr("1970-13-01T00:00:00Z"));
+ CHECK_FALSE(utils::timeutils::parseDateTimeStr("foobar"));
}
TEST_CASE("Test system_clock epoch", "[systemclockepoch]") {
@@ -107,7 +106,7 @@ TEST_CASE("Test system_clock epoch", "[systemclockepoch]") {
TEST_CASE("Test clock resolutions", "[clockresolutiontests]") {
using namespace std::chrono;
CHECK(std::is_constructible<system_clock::duration, std::chrono::microseconds>::value); // The resolution of the system_clock is at least microseconds
- CHECK(std::is_constructible<steady_clock::duration, std::chrono::microseconds>::value); // The resolution of the system_clock is at least microseconds
+ CHECK(std::is_constructible<steady_clock::duration, std::chrono::microseconds>::value); // The resolution of the steady_clock is at least microseconds
CHECK(std::is_constructible<high_resolution_clock::duration, std::chrono::nanoseconds>::value); // The resolution of the high_resolution_clock is at least nanoseconds
}