diff --git a/examples/GetPresignedPostFormData.cc b/examples/GetPresignedPostFormData.cc index ef960a92..c526b43b 100644 --- a/examples/GetPresignedPostFormData.cc +++ b/examples/GetPresignedPostFormData.cc @@ -27,7 +27,7 @@ int main() { minio::s3::Client client(base_url, &provider); // Create get presigned post form data arguments. - minio::utils::Time expiration = minio::utils::Time::Now(); + minio::utils::UtcTime expiration = minio::utils::UtcTime::Now(); expiration.Add(60 * 60 * 24); // 1 day from now. minio::s3::PostPolicy policy("my-bucket", expiration); policy.AddStartsWithCondition("key", "my/object/prefix/"); diff --git a/examples/SetObjectRetention.cc b/examples/SetObjectRetention.cc index 95a74505..36b503ee 100644 --- a/examples/SetObjectRetention.cc +++ b/examples/SetObjectRetention.cc @@ -31,7 +31,7 @@ int main() { args.bucket = "my-bucket"; args.object = "my-object"; args.retention_mode = minio::s3::RetentionMode::kGovernance; - minio::utils::Time tomorrow = minio::utils::Time::Now(); + minio::utils::UtcTime tomorrow = minio::utils::UtcTime::Now(); tomorrow.Add(60 * 60 * 24); args.retain_until_date = tomorrow; diff --git a/include/args.h b/include/args.h index 9fb1d8f8..227595c4 100644 --- a/include/args.h +++ b/include/args.h @@ -83,8 +83,8 @@ struct ObjectConditionalReadArgs : public ObjectReadArgs { size_t *length = nullptr; std::string match_etag; std::string not_match_etag; - utils::Time modified_since; - utils::Time unmodified_since; + utils::UtcTime modified_since; + utils::UtcTime unmodified_since; ObjectConditionalReadArgs() = default; ~ObjectConditionalReadArgs() = default; @@ -488,7 +488,7 @@ using GetObjectRetentionArgs = ObjectVersionArgs; struct SetObjectRetentionArgs : public ObjectVersionArgs { RetentionMode retention_mode; - utils::Time retain_until_date; + utils::UtcTime retain_until_date; SetObjectRetentionArgs() = default; ~SetObjectRetentionArgs() = default; @@ -502,7 +502,7 @@ inline constexpr unsigned int kDefaultExpirySeconds = struct GetPresignedObjectUrlArgs : public ObjectVersionArgs { http::Method method; unsigned int expiry_seconds = kDefaultExpirySeconds; - utils::Time request_time; + utils::UtcTime request_time; GetPresignedObjectUrlArgs() = default; ~GetPresignedObjectUrlArgs() = default; @@ -514,7 +514,7 @@ struct PostPolicy { std::string bucket; std::string region; - PostPolicy(std::string bucket, utils::Time expiration) + PostPolicy(std::string bucket, utils::UtcTime expiration) : bucket(std::move(bucket)), expiration_(std::move(expiration)) {} ~PostPolicy() = default; @@ -538,14 +538,15 @@ struct PostPolicy { static constexpr const char *starts_with_ = "starts-with"; static constexpr const char *algorithm_ = "AWS4-HMAC-SHA256"; - utils::Time expiration_; + utils::UtcTime expiration_; std::map> conditions_; Integer lower_limit_; Integer upper_limit_; static std::string trimDollar(std::string value); static std::string getCredentialString(std::string access_key, - utils::Time date, std::string region); + utils::UtcTime date, + std::string region); static bool isReservedElement(std::string element); }; // struct PostPolicy } // namespace s3 diff --git a/include/credentials.h b/include/credentials.h index 68e21db8..49594b82 100644 --- a/include/credentials.h +++ b/include/credentials.h @@ -20,7 +20,7 @@ namespace minio { namespace creds { -bool expired(const utils::Time& expiration); +bool expired(const utils::UtcTime& expiration); /** * Credentials contains access key and secret key with optional session token @@ -31,7 +31,7 @@ struct Credentials { std::string access_key = {}; std::string secret_key = {}; std::string session_token = {}; - utils::Time expiration = {}; + utils::UtcTime expiration = {}; Credentials() = default; ~Credentials() = default; diff --git a/include/request.h b/include/request.h index 46098770..30cdb51c 100644 --- a/include/request.h +++ b/include/request.h @@ -113,7 +113,7 @@ struct Request { void* progress_userdata = nullptr; std::string sha256; - utils::Time date; + utils::UtcTime date; bool debug = false; bool ignore_cert_check = false; diff --git a/include/response.h b/include/response.h index 352ade4e..e14b0827 100644 --- a/include/response.h +++ b/include/response.h @@ -160,9 +160,9 @@ struct StatObjectResponse : public Response { std::string version_id; std::string etag; size_t size = 0; - utils::Time last_modified; + utils::UtcTime last_modified; RetentionMode retention_mode; - utils::Time retention_retain_until_date; + utils::UtcTime retention_retain_until_date; LegalHold legal_hold; bool delete_marker; utils::Multimap user_metadata; @@ -185,7 +185,7 @@ using GetObjectResponse = Response; struct Item : public Response { std::string etag; // except DeleteMarker std::string name; - utils::Time last_modified; + utils::UtcTime last_modified; std::string owner_id; std::string owner_name; size_t size = 0; // except DeleteMarker @@ -478,7 +478,7 @@ struct IsObjectLegalHoldEnabledResponse : public Response { struct GetObjectRetentionResponse : public Response { RetentionMode retention_mode; - utils::Time retain_until_date; + utils::UtcTime retain_until_date; GetObjectRetentionResponse() = default; diff --git a/include/signer.h b/include/signer.h index 5c5b67cc..9aae4ec9 100644 --- a/include/signer.h +++ b/include/signer.h @@ -22,7 +22,7 @@ namespace minio { namespace signer { -std::string GetScope(const utils::Time& time, const std::string& region, +std::string GetScope(const utils::UtcTime& time, const std::string& region, const std::string& service_name); std::string GetCanonicalRequestHash(const std::string& method, const std::string& uri, @@ -30,11 +30,12 @@ std::string GetCanonicalRequestHash(const std::string& method, const std::string& headers, const std::string& signed_headers, const std::string& content_sha256); -std::string GetStringToSign(const utils::Time& date, const std::string& scope, +std::string GetStringToSign(const utils::UtcTime& date, + const std::string& scope, const std::string& canonical_request_hash); std::string HmacHash(std::string_view key, std::string_view data); std::string GetSigningKey(const std::string& secret_key, - const utils::Time& date, std::string_view region, + const utils::UtcTime& date, std::string_view region, std::string_view service_name); std::string GetSignature(std::string_view signing_key, std::string_view string_to_sign); @@ -48,30 +49,31 @@ utils::Multimap SignV4(const std::string& service_name, http::Method method, const std::string& access_key, const std::string& secret_key, const std::string& content_sha256, - const utils::Time& date); + const utils::UtcTime& date); utils::Multimap SignV4S3(http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, const std::string& content_sha256, - const utils::Time& date); + const utils::UtcTime& date); utils::Multimap SignV4STS(http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, const std::string& content_sha256, - const utils::Time& date); + const utils::UtcTime& date); utils::Multimap PresignV4(http::Method method, const std::string& host, const std::string& uri, const std::string& region, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, - const utils::Time& date, unsigned int expires); + const utils::UtcTime& date, unsigned int expires); std::string PostPresignV4(const std::string& data, const std::string& secret_key, - const utils::Time& date, const std::string& region); + const utils::UtcTime& date, + const std::string& region); } // namespace signer } // namespace minio #endif // #ifndef __MINIO_SIGNER_H diff --git a/include/types.h b/include/types.h index ab1ebd5a..9a220b06 100644 --- a/include/types.h +++ b/include/types.h @@ -307,7 +307,7 @@ using SelectResultFunction = std::function; struct Bucket { std::string name; - utils::Time creation_date; + utils::UtcTime creation_date; Bucket() = default; ~Bucket() = default; @@ -316,7 +316,7 @@ struct Bucket { struct Part { unsigned int number; std::string etag; - utils::Time last_modified = {}; + utils::UtcTime last_modified = {}; size_t size = 0; Part() = default; @@ -325,7 +325,7 @@ struct Part { struct Retention { RetentionMode mode; - utils::Time retain_until_date; + utils::UtcTime retain_until_date; Retention() = default; ~Retention() = default; @@ -687,7 +687,7 @@ struct ReplicationConfig { struct LifecycleRule { Integer abort_incomplete_multipart_upload_days_after_initiation; - utils::Time expiration_date; + utils::UtcTime expiration_date; Integer expiration_days; Boolean expiration_expired_object_delete_marker; Filter filter; @@ -696,7 +696,7 @@ struct LifecycleRule { Integer noncurrent_version_transition_noncurrent_days; std::string noncurrent_version_transition_storage_class; bool status = false; - utils::Time transition_date; + utils::UtcTime transition_date; Integer transition_days; std::string transition_storage_class; diff --git a/include/utils.h b/include/utils.h index 59ce16e2..d3e339a9 100644 --- a/include/utils.h +++ b/include/utils.h @@ -118,28 +118,26 @@ error::Error CalcPartInfo(long object_size, size_t& part_size, long& part_count); /** - * Time represents date and time with timezone. + * UtcTime represents date and time in UTC timezone. */ -class Time { +class UtcTime { private: - struct timeval tv_ = {}; - bool utc_ = false; + std::time_t secs_ = {}; + long usecs_ = 0L; + + std::tm* getBrokenDownTime() const; public: - Time() = default; + UtcTime() = default; - Time(std::time_t tv_sec, long tv_usec, bool utc) : utc_(utc) { - tv_.tv_sec = static_cast(tv_sec); - tv_.tv_usec = static_cast(tv_usec); - } + UtcTime(std::time_t secs) : secs_(secs) {} + UtcTime(std::time_t secs, long usecs) : secs_(secs), usecs_(usecs) {} - ~Time() = default; + ~UtcTime() = default; - void Add(std::time_t seconds) { - tv_.tv_sec += static_cast(seconds); - } + void Add(std::time_t seconds) { secs_ += seconds; } - std::tm* ToUTC() const; + void ToLocalTime(std::tm& time); std::string ToSignerDate() const; @@ -147,40 +145,40 @@ class Time { std::string ToHttpHeaderValue() const; - static Time FromHttpHeaderValue(const char* value); + static UtcTime FromHttpHeaderValue(const char* value); std::string ToISO8601UTC() const; - static Time FromISO8601UTC(const char* value); + static UtcTime FromISO8601UTC(const char* value); - static Time Now(); + static UtcTime Now(); - explicit operator bool() const { return tv_.tv_sec != 0 && tv_.tv_usec != 0; } + explicit operator bool() const { return secs_ != 0 && usecs_ != 0; } - int Compare(const Time& rhs) const; + int Compare(const UtcTime& rhs) const; - bool Equal(const Time& rhs) const { return Compare(rhs) == 0; } + bool Equal(const UtcTime& rhs) const { return Compare(rhs) == 0; } - bool operator==(const Time& rhs) const { return Equal(rhs); } + bool operator==(const UtcTime& rhs) const { return Equal(rhs); } - bool operator!=(const Time& rhs) const { return !operator==(rhs); } + bool operator!=(const UtcTime& rhs) const { return !operator==(rhs); } - bool operator<(const Time& rhs) const { return Compare(rhs) < 0; } + bool operator<(const UtcTime& rhs) const { return Compare(rhs) < 0; } - bool operator>(const Time& rhs) const { return Compare(rhs) > 0; } + bool operator>(const UtcTime& rhs) const { return Compare(rhs) > 0; } - bool operator<=(const Time& rhs) const { return !operator>(rhs); } + bool operator<=(const UtcTime& rhs) const { return !operator>(rhs); } - bool operator>=(const Time& rhs) const { return !operator<(rhs); } + bool operator>=(const UtcTime& rhs) const { return !operator<(rhs); } #if __cplusplus >= 202002L - auto operator<=>(const Time& rhs) const { return Compare(rhs); } + auto operator<=>(const UtcTime& rhs) const { return Compare(rhs); } #endif - friend std::ostream& operator<<(std::ostream& s, const Time& v) { + friend std::ostream& operator<<(std::ostream& s, const UtcTime& v) { return s << v.ToISO8601UTC(); } -}; // class Time +}; // class UtcTime /** * Multimap represents dictionary of keys and their multiple values. diff --git a/src/args.cc b/src/args.cc index 47634ddf..dc7c9582 100644 --- a/src/args.cc +++ b/src/args.cc @@ -657,7 +657,7 @@ minio::error::Error minio::s3::PostPolicy::FormData( conditions.push_back( {"content-length-range", lower_limit_.Get(), upper_limit_.Get()}); } - utils::Time date = utils::Time::Now(); + utils::UtcTime date = utils::UtcTime::Now(); std::string credential = getCredentialString(access_key, date, region); std::string amz_date = date.ToAmzDate(); conditions.push_back({eq_, "$x-amz-algorithm", algorithm_}); @@ -692,7 +692,7 @@ std::string minio::s3::PostPolicy::trimDollar(std::string value) { } std::string minio::s3::PostPolicy::getCredentialString(std::string access_key, - utils::Time date, + utils::UtcTime date, std::string region) { return access_key + "/" + date.ToSignerDate() + "/" + region + "/s3/aws4_request"; diff --git a/src/baseclient.cc b/src/baseclient.cc index de0f5e97..3b51baa5 100644 --- a/src/baseclient.cc +++ b/src/baseclient.cc @@ -874,7 +874,8 @@ minio::s3::GetObjectRetentionResponse minio::s3::BaseClient::GetObjectRetention( response.retention_mode = StringToRetentionMode(text.node().value()); text = xdoc.select_node("/Retention/RetainUntilDate/text()"); - response.retain_until_date = utils::Time::FromISO8601UTC(text.node().value()); + response.retain_until_date = + utils::UtcTime::FromISO8601UTC(text.node().value()); return response; } @@ -933,7 +934,7 @@ minio::s3::BaseClient::GetPresignedObjectUrl(GetPresignedObjectUrlArgs args) { query_params.Add("X-Amz-Security-Token", creds.session_token); } - utils::Time date = utils::Time::Now(); + utils::UtcTime date = utils::UtcTime::Now(); if (args.request_time) date = args.request_time; std::string host = url.HostHeaderValue(); @@ -1704,7 +1705,7 @@ minio::s3::StatObjectResponse minio::s3::BaseClient::StatObject( value = response.headers.GetFront("last-modified"); if (!value.empty()) { - resp.last_modified = utils::Time::FromHttpHeaderValue(value.c_str()); + resp.last_modified = utils::UtcTime::FromHttpHeaderValue(value.c_str()); } value = response.headers.GetFront("x-amz-object-lock-mode"); @@ -1713,7 +1714,7 @@ minio::s3::StatObjectResponse minio::s3::BaseClient::StatObject( value = response.headers.GetFront("x-amz-object-lock-retain-until-date"); if (!value.empty()) { resp.retention_retain_until_date = - utils::Time::FromISO8601UTC(value.c_str()); + utils::UtcTime::FromISO8601UTC(value.c_str()); } value = response.headers.GetFront("x-amz-object-lock-legal-hold"); diff --git a/src/credentials.cc b/src/credentials.cc index 9db4fe27..085ccf6d 100644 --- a/src/credentials.cc +++ b/src/credentials.cc @@ -17,9 +17,9 @@ #include -bool minio::creds::expired(const utils::Time& expiration) { +bool minio::creds::expired(const utils::UtcTime& expiration) { if (!expiration) return false; - utils::Time now = utils::Time::Now(); + utils::UtcTime now = utils::UtcTime::Now(); now.Add(10); return expiration < now; } @@ -42,7 +42,7 @@ minio::creds::Credentials minio::creds::Credentials::ParseXML( std::string session_token = text.node().value(); text = credentials.node().select_node("Expiration/text()"); - auto expiration = utils::Time::FromISO8601UTC(text.node().value()); + auto expiration = utils::UtcTime::FromISO8601UTC(text.node().value()); return Credentials{error::SUCCESS, access_key, secret_key, session_token, expiration}; diff --git a/src/providers.cc b/src/providers.cc index 32fb8a85..73882d5b 100644 --- a/src/providers.cc +++ b/src/providers.cc @@ -235,7 +235,7 @@ minio::creds::Credentials minio::creds::AssumeRoleProvider::Fetch() { if (creds_) return creds_; - utils::Time date = utils::Time::Now(); + utils::UtcTime date = utils::UtcTime::Now(); utils::Multimap headers; headers.Add("Content-Type", "application/x-www-form-urlencoded"); headers.Add("Host", sts_endpoint_.host); @@ -304,7 +304,7 @@ minio::creds::WebIdentityClientGrantsProvider::Fetch() { if (!role_session_name_.empty()) { map.Add("RoleSessionName", role_session_name_); } else { - map.Add("RoleSessionName", utils::Time::Now().ToISO8601UTC()); + map.Add("RoleSessionName", utils::UtcTime::Now().ToISO8601UTC()); } } } else { @@ -434,7 +434,7 @@ minio::creds::Credentials minio::creds::IamAwsProvider::fetch(http::Url url) { std::string expiration = json["Expiration"]; return Credentials{error::SUCCESS, json["AccessKeyId"], json["SecretAccessKey"], json["Token"], - utils::Time::FromISO8601UTC(expiration.c_str())}; + utils::UtcTime::FromISO8601UTC(expiration.c_str())}; } minio::error::Error minio::creds::IamAwsProvider::getRoleName( diff --git a/src/request.cc b/src/request.cc index 704f411b..d07aaaf9 100644 --- a/src/request.cc +++ b/src/request.cc @@ -281,7 +281,7 @@ void minio::s3::Request::BuildHeaders(http::Url& url, if (!md5sum.empty()) headers.Add("Content-MD5", md5sum); if (!sha256.empty()) headers.Add("x-amz-content-sha256", sha256); - date = utils::Time::Now(); + date = utils::UtcTime::Now(); headers.Add("x-amz-date", date.ToAmzDate()); if (provider != nullptr) { diff --git a/src/response.cc b/src/response.cc index 5cf1295b..c922d92c 100644 --- a/src/response.cc +++ b/src/response.cc @@ -81,13 +81,13 @@ minio::s3::ListBucketsResponse minio::s3::ListBucketsResponse::ParseXML( xdoc.select_nodes("/ListAllMyBucketsResult/Buckets/Bucket"); for (auto xnode : xnodes) { std::string name; - utils::Time creation_date; + utils::UtcTime creation_date; if (auto node = xnode.node().select_node("Name/text()").node()) { name = node.value(); } if (auto node = xnode.node().select_node("CreationDate/text()").node()) { std::string value = node.value(); - creation_date = utils::Time::FromISO8601UTC(value.c_str()); + creation_date = utils::UtcTime::FromISO8601UTC(value.c_str()); } buckets.push_back(Bucket{name, creation_date}); @@ -232,7 +232,7 @@ minio::s3::ListObjectsResponse minio::s3::ListObjectsResponse::ParseXML( text = content.node().select_node("LastModified/text()"); value = text.node().value(); - item.last_modified = utils::Time::FromISO8601UTC(value.c_str()); + item.last_modified = utils::UtcTime::FromISO8601UTC(value.c_str()); text = content.node().select_node("Owner/ID/text()"); item.owner_id = text.node().value(); @@ -656,7 +656,7 @@ minio::s3::GetBucketLifecycleResponse::ParseXML(std::string_view data) { if (rule.node().select_node("Expiration/Date")) { text = rule.node().select_node("Expiration/Date/text()"); lrule.expiration_date = - utils::Time::FromISO8601UTC(text.node().value()); + utils::UtcTime::FromISO8601UTC(text.node().value()); } if (rule.node().select_node("Expiration/Days")) { @@ -735,7 +735,7 @@ minio::s3::GetBucketLifecycleResponse::ParseXML(std::string_view data) { if (rule.node().select_node("Transition/Date")) { text = rule.node().select_node("Transition/Date/text()"); lrule.transition_date = - utils::Time::FromISO8601UTC(text.node().value()); + utils::UtcTime::FromISO8601UTC(text.node().value()); } if (rule.node().select_node("Transition/Days")) { diff --git a/src/signer.cc b/src/signer.cc index 36d442ff..f33af171 100644 --- a/src/signer.cc +++ b/src/signer.cc @@ -17,7 +17,7 @@ const char* SIGN_V4_ALGORITHM = "AWS4-HMAC-SHA256"; -std::string minio::signer::GetScope(const utils::Time& time, +std::string minio::signer::GetScope(const utils::UtcTime& time, const std::string& region, const std::string& service_name) { return time.ToSignerDate() + "/" + region + "/" + service_name + @@ -42,7 +42,7 @@ std::string minio::signer::GetCanonicalRequestHash( } std::string minio::signer::GetStringToSign( - const utils::Time& date, const std::string& scope, + const utils::UtcTime& date, const std::string& scope, const std::string& canonical_request_hash) { return "AWS4-HMAC-SHA256\n" + date.ToAmzDate() + "\n" + scope + "\n" + canonical_request_hash; @@ -61,7 +61,7 @@ std::string minio::signer::HmacHash(std::string_view key, } std::string minio::signer::GetSigningKey(const std::string& secret_key, - const utils::Time& date, + const utils::UtcTime& date, std::string_view region, std::string_view service_name) { std::string date_key = HmacHash("AWS4" + secret_key, date.ToSignerDate()); @@ -95,7 +95,7 @@ minio::utils::Multimap minio::signer::SignV4( const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, const std::string& content_sha256, - const utils::Time& date) { + const utils::UtcTime& date) { std::string scope = GetScope(date, region, service_name); std::string signed_headers; @@ -128,7 +128,7 @@ minio::utils::Multimap minio::signer::SignV4S3( http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, - const std::string& content_sha256, const utils::Time& date) { + const std::string& content_sha256, const utils::UtcTime& date) { std::string service_name = "s3"; return SignV4(service_name, method, uri, region, headers, std::move(query_params), access_key, secret_key, content_sha256, @@ -139,7 +139,7 @@ minio::utils::Multimap minio::signer::SignV4STS( http::Method method, const std::string& uri, const std::string& region, utils::Multimap& headers, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, - const std::string& content_sha256, const utils::Time& date) { + const std::string& content_sha256, const utils::UtcTime& date) { std::string service_name = "sts"; return SignV4(service_name, method, uri, region, headers, std::move(query_params), access_key, secret_key, content_sha256, @@ -150,7 +150,7 @@ minio::utils::Multimap minio::signer::PresignV4( http::Method method, const std::string& host, const std::string& uri, const std::string& region, utils::Multimap query_params, const std::string& access_key, const std::string& secret_key, - const utils::Time& date, unsigned int expires) { + const utils::UtcTime& date, unsigned int expires) { std::string service_name = "s3"; std::string scope = GetScope(date, region, service_name); std::string canonical_headers = "host:" + host; @@ -179,7 +179,7 @@ minio::utils::Multimap minio::signer::PresignV4( std::string minio::signer::PostPresignV4(const std::string& string_to_sign, const std::string& secret_key, - const utils::Time& date, + const utils::UtcTime& date, const std::string& region) { std::string service_name = "s3"; std::string signing_key = diff --git a/src/utils.cc b/src/utils.cc index 53182e7a..6cadbcfd 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -281,60 +281,65 @@ std::string minio::utils::FormatTime(const std::tm* time, const char* format) { return std::string(buf); } -std::tm* minio::utils::Time::ToUTC() const { - std::tm* t = new std::tm; - const time_t secs = tv_.tv_sec; - *t = utc_ ? *std::localtime(&secs) : *std::gmtime(&secs); - return t; +std::tm* minio::utils::UtcTime::getBrokenDownTime() const { + const time_t secs = secs_; + return std::localtime(&secs); } -minio::utils::Time minio::utils::Time::Now() { - auto usec = std::chrono::system_clock::now().time_since_epoch() / - std::chrono::microseconds(1); - return Time(static_cast(usec / 1000000), - static_cast(usec % 1000000), false); +minio::utils::UtcTime minio::utils::UtcTime::Now() { + auto usec_now = std::chrono::system_clock::now().time_since_epoch() / + std::chrono::microseconds(1); + auto secs_local = static_cast(usec_now / 1000000); + auto secs_utc = std::mktime(std::gmtime(&secs_local)); + return UtcTime(secs_utc, static_cast(usec_now % 1000000)); } -std::string minio::utils::Time::ToSignerDate() const { - std::unique_ptr utc(ToUTC()); - std::string result = FormatTime(utc.get(), "%Y%m%d"); - return result; +void minio::utils::UtcTime::ToLocalTime(std::tm& time) { + auto usec_now = std::chrono::system_clock::now().time_since_epoch() / + std::chrono::microseconds(1); + auto secs_local = static_cast(usec_now / 1000000); + auto secs_utc = std::mktime(std::gmtime(&secs_local)); + auto secs = secs_ + (secs_local - secs_utc); + time = *std::localtime(&secs); } -std::string minio::utils::Time::ToAmzDate() const { - std::unique_ptr utc(ToUTC()); - std::string result = FormatTime(utc.get(), "%Y%m%dT%H%M%SZ"); - return result; +std::string minio::utils::UtcTime::ToSignerDate() const { + return FormatTime(getBrokenDownTime(), "%Y%m%d"); +} + +std::string minio::utils::UtcTime::ToAmzDate() const { + return FormatTime(getBrokenDownTime(), "%Y%m%dT%H%M%SZ"); } -std::string minio::utils::Time::ToHttpHeaderValue() const { - std::unique_ptr utc(ToUTC()); +std::string minio::utils::UtcTime::ToHttpHeaderValue() const { + auto tm = getBrokenDownTime(); std::stringstream ss; - ss << WEEK_DAYS[utc->tm_wday] << ", " << FormatTime(utc.get(), "%d ") - << MONTHS[utc->tm_mon] << FormatTime(utc.get(), " %Y %H:%M:%S GMT"); + ss << WEEK_DAYS[tm->tm_wday] << ", " << FormatTime(tm, "%d ") + << MONTHS[tm->tm_mon] << FormatTime(tm, " %Y %H:%M:%S GMT"); return ss.str(); } -minio::utils::Time minio::utils::Time::FromHttpHeaderValue(const char* value) { +minio::utils::UtcTime minio::utils::UtcTime::FromHttpHeaderValue( + const char* value) { std::string s(value); - if (s.size() != 29) return Time(); + if (s.size() != 29) return UtcTime(); // Parse week day. auto pos = std::find(std::begin(WEEK_DAYS), std::end(WEEK_DAYS), s.substr(0, 3)); - if (pos == std::end(WEEK_DAYS)) return Time(); - if (s.at(3) != ',') return Time(); - if (s.at(4) != ' ') return Time(); + if (pos == std::end(WEEK_DAYS)) return UtcTime(); + if (s.at(3) != ',') return UtcTime(); + if (s.at(4) != ' ') return UtcTime(); auto week_day = pos - std::begin(WEEK_DAYS); // Parse day. std::tm day{}; strptime(s.substr(5, 2).c_str(), "%d", &day); - if (s.at(7) != ' ') return Time(); + if (s.at(7) != ' ') return UtcTime(); // Parse month. pos = std::find(std::begin(MONTHS), std::end(MONTHS), s.substr(8, 3)); - if (pos == std::end(MONTHS)) return Time(); + if (pos == std::end(MONTHS)) return UtcTime(); auto month = pos - std::begin(MONTHS); // Parse rest of values. @@ -346,38 +351,37 @@ minio::utils::Time minio::utils::Time::FromHttpHeaderValue(const char* value) { // Validate week day. std::time_t time = std::mktime(<m); std::tm* t = std::localtime(&time); - if (week_day != t->tm_wday) return Time(); + if (week_day != t->tm_wday) return UtcTime(); - return Time(std::mktime(t), 0, true); + return UtcTime(std::mktime(t)); } -std::string minio::utils::Time::ToISO8601UTC() const { +std::string minio::utils::UtcTime::ToISO8601UTC() const { char buf[64]; - snprintf(buf, 64, "%03ld", (long int)tv_.tv_usec); + snprintf(buf, 64, "%03ld", (long int)usecs_); std::string usec_str(buf); if (usec_str.size() > 3) usec_str = usec_str.substr(0, 3); - std::unique_ptr utc(ToUTC()); - std::string result = - FormatTime(utc.get(), "%Y-%m-%dT%H:%M:%S.") + usec_str + "Z"; - return result; + return FormatTime(getBrokenDownTime(), "%Y-%m-%dT%H:%M:%S.") + usec_str + "Z"; } -minio::utils::Time minio::utils::Time::FromISO8601UTC(const char* value) { +minio::utils::UtcTime minio::utils::UtcTime::FromISO8601UTC(const char* value) { std::tm t{}; char* rv = strptime(value, "%Y-%m-%dT%H:%M:%S", &t); + std::time_t secs = std::mktime(&t); + unsigned long ul = 0; sscanf(rv, ".%lu", &ul); - long tv_usec = (long)ul; - std::time_t time = std::mktime(&t); - return Time(time, tv_usec, true); + long usecs = (long)ul; + + return UtcTime(secs, usecs); } -int minio::utils::Time::Compare(const Time& rhs) const { - if (tv_.tv_sec != rhs.tv_.tv_sec) { - return (tv_.tv_sec < rhs.tv_.tv_sec) ? -1 : 1; +int minio::utils::UtcTime::Compare(const UtcTime& rhs) const { + if (secs_ != rhs.secs_) { + return (secs_ < rhs.secs_) ? -1 : 1; } - if (tv_.tv_usec != rhs.tv_.tv_usec) { - return (tv_.tv_usec < rhs.tv_.tv_usec) ? -1 : 1; + if (usecs_ != rhs.usecs_) { + return (usecs_ < rhs.usecs_) ? -1 : 1; } return 0; }