// bdlt_datetimeutil.h -*-C++-*- #ifndef INCLUDED_BDLT_DATETIMEUTIL #define INCLUDED_BDLT_DATETIMEUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide common non-primitive operations on 'bdlt::Datetime'. // //@CLASSES: // bdlt::DatetimeUtil: non-primitive functions on 'bdlt::Datetime' // //@SEE_ALSO: bdlt_datetime, bdlt_datetimeinterval, bdlt_epochutil // //@DESCRIPTION: This component provides non-primitive operations on // 'bdlt::Datetime' objects. In particular, 'bdlt::DatetimeUtil' supplies // conversions of universal time to and from the C-standard 'struct' 'tm' // (which we alias as 'bsl::tm') representations. // // This utility component provides the following (static) methods: //.. // int convertFromTm(bdlt::Datetime *result, const tm& timeStruct); // bsl::tm convertToTm(const bdlt::Datetime& datetime); //.. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Converting Between 'bsl::tm' and 'bdlt::Datetime' /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // When interfacing with legacy systems, we may encounter calls that represent // date/time information using the standard 'bsl::tm'. In such cases, we have // to be able to convert that information to/from a 'bdlt::Datetime' object in // order to interface with the rest of our systems. // // Suppose we have a legacy system that tracks last-access times in terms of // 'bsl::tm'. We can use the 'convertToTm' and 'convertFromTm' routines from // this component to convert that information. // // First, we define a class, 'MyAccessTracker', that the legacy system uses to // manage last-access times (eliding the implementation for brevity): //.. // class MyAccessTracker { // // This class provides a facility for tracking last access times // // associated with usernames. // // // LOCAL TYPE // typedef bsl::map<bsl::string, bsl::tm> TStringTmMap; // // // DATA // TStringTmMap m_accesses; // map names to // // accesses // // public: // // TRAITS // BSLMF_NESTED_TRAIT_DECLARATION(MyAccessTracker, // bslma::UsesBslmaAllocator); // // // CREATORS // explicit MyAccessTracker(bslma::Allocator *basicAllocator = 0); // // Create an object which will track the last access time ... // // // MANIPULATORS // void updateLastAccess(const bsl::string& username, // const bsl::tm& accessTime); // // Update the last access time for the specified 'username' with // // the specified 'accessTime'. // // // ACCESSORS // int getLastAccess(bsl::tm *result, const bsl::string& username) const; // // Load into the specified 'result' the last access time associated // // with the specified 'username', if any. Return 0 on success, and // // non-0 (with no effect on 'result') if there's no access time // // associated with 'username'. // }; //.. // Next, we define a utility to allow us to use 'bdlt::Datetime' with our // legacy access tracker: //.. // class MyAccessTrackerUtil { // public: // static int getLastAccess(bdlt::Datetime *result, // const MyAccessTracker& tracker, // const bsl::string& username); // // Load into the specified 'result' the last access time associated // // with the specified 'username' in the specified 'tracker', if // // any. Returns 0 on success, and non-0 (with no effect on // // 'result') if there's no access time associated with 'username' // // or the associated access time cannot be converted to // // 'bdlt::Datetime'. // // static void updateLastAccess(MyAccessTracker *tracker, // const bsl::string& username, // const bdlt::Datetime& accessTime); // // Update the instance pointed to by the specified 'tracker' by // // adding the specified 'username' with its associated specified // // 'accessTime'. // }; //.. // Then, we implement 'getLastAccess': //.. // // ------------------------- // // class MyAccessTrackerUtil // // ------------------------- // // int MyAccessTrackerUtil::getLastAccess(bdlt::Datetime *result, // const MyAccessTracker& tracker, // const bsl::string& username) // { // BSLS_ASSERT(result); // // bsl::tm legacyAccessTime; // // int rc = tracker.getLastAccess(&legacyAccessTime, username); // // if (rc) { // return rc; // RETURN // } // // return bdlt::DatetimeUtil::convertFromTm(result, legacyAccessTime); // } //.. // Next, we implement 'updateLastAccess': //.. // void MyAccessTrackerUtil::updateLastAccess( // MyAccessTracker *tracker, // const bsl::string& username, // const bdlt::Datetime& accessTime) // { // BSLS_ASSERT(tracker); // // bsl::tm legacyAccessTime; // // legacyAccessTime = bdlt::DatetimeUtil::convertToTm(accessTime); // // tracker->updateLastAccess(username, legacyAccessTime); // } //.. // Finally, we create an access tracker then interact with it using // 'bdlt::Datetime' times. //.. // void exerciseTracker() // // Exercise 'MyAccessTracker' for pedagogical purposes. // { // MyAccessTracker accessTracker; // Datetime each user last accessed a // // resource. // // bsl::string richtofenName = "Baron von Richtofen"; // bdlt::Datetime richtofenDate(1918, 4, 21, 11, 0, 0); // MyAccessTrackerUtil::updateLastAccess(&accessTracker, // richtofenName, // richtofenDate); // // // ... some time later .... // // bdlt::Datetime lastAccessTime; // int rc = MyAccessTrackerUtil::getLastAccess(&lastAccessTime, // accessTracker, // richtofenName); // assert(0 == rc); // assert(lastAccessTime == richtofenDate); // // // Do something with the retrieved date... // } //.. #include <bdlscm_version.h> #include <bdlt_datetime.h> #include <bsls_assert.h> #include <bsls_review.h> #include <bsl_ctime.h> // 'bsl::tm' namespace BloombergLP { namespace bdlt { // =================== // struct DatetimeUtil // =================== struct DatetimeUtil { // This utility 'struct' provides a namespace for a suite of functions // operating on objects of type 'Datetime'. public: // CLASS METHODS static int convertFromTm(Datetime *result, const bsl::tm& timeStruct); // Load into the specified 'result' the value of the specified // 'timeStruct'. Return 0 on success, and a non-zero value with no // effect on 'result' if 'timeStruct' is invalid or otherwise cannot be // represented as a 'Datetime'. Values in fields 'tm_wday', 'tm_yday', // and 'tm_isdst' are ignored. The time 24:00:00 will be recognized, // and leap seconds (i.e., values in 'tm_sec' of 60 or 61) which can // otherwise be represented as a 'Datetime' will cause the conversion // to succeed with the 'result' "rolling over" into the zeroth second // of next minute. Note that time zones are irrelevant for this // conversion. static bsl::tm convertToTm( const Datetime& datetime); static void convertToTm(bsl::tm *result, const Datetime& datetime); // Return or load into the specified 'result' the value of the // specified 'datetime' expressed as a 'bsl::tm'. Each field in the // result is set to its proper value except 'tm_isdst', which is set to // '-1' to indicate that no information on daylight saving time is // available. A time value of 24:00:00:00 will be converted to // 0:00:00. Note that time zones are irrelevant for this conversion. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------- // struct DatetimeUtil // ------------------- inline int DatetimeUtil::convertFromTm(Datetime *result, const bsl::tm& timeStruct) { BSLS_ASSERT(result); bool isLeapSecond = false; int seconds = timeStruct.tm_sec; if (seconds > 59) { // Start handling leap seconds by shifting to the previous non-leap // second time. isLeapSecond = true; seconds = 59; } int rc = result->setDatetimeIfValid(timeStruct.tm_year + 1900, timeStruct.tm_mon + 1, timeStruct.tm_mday, timeStruct.tm_hour, timeStruct.tm_min, seconds); // msec = 0 if (isLeapSecond && !rc) { // Finish leap second handling by rolling over into second '0' in the // next minute. result->addSeconds(1); } return rc; } inline bsl::tm DatetimeUtil::convertToTm(const Datetime& datetime) { // 'struct tm' may contain non POSIX standard fields (e.g., on Linux/OSX), // which we want to 0 initialize. bsl::tm result = bsl::tm(); result.tm_sec = datetime.second(); result.tm_min = datetime.minute(); const int hour = datetime.hour(); if (24 == hour) { result.tm_hour = 0; } else { result.tm_hour = hour; } result.tm_mday = datetime.day(); result.tm_mon = datetime.month() - 1; result.tm_year = datetime.year() - 1900; result.tm_wday = datetime.date().dayOfWeek() - 1; result.tm_yday = datetime.date().dayOfYear() - 1; result.tm_isdst = -1; // This information is unavailable. return result; } inline void DatetimeUtil::convertToTm(bsl::tm *result, const Datetime& datetime) { BSLS_ASSERT(result); *result = convertToTm(datetime); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2014 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------