// baltzo_localtimeoffsetutil.h -*-C++-*- #ifndef INCLUDED_BALTZO_LOCALTIMEOFFSETUTIL #define INCLUDED_BALTZO_LOCALTIMEOFFSETUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide utilities for a 'bdlt_localtimeoffset' local time callback. // //@CLASSES: // baltzo::LocalTimeOffsetUtil: utilities managing a local time callback // //@SEE_ALSO: bdlt_localtimeoffset // //@DESCRIPTION: This component, 'baltzo::LocalTimeOffsetUtil', provides // 'baltzo::LocalTimeOffsetUtil::localTimeOffset', a high performance // 'bdlt::LocalTimeOffset' local time offset callback function, which accesses // the Zoneinfo database. To achieve high performance, this function refers to // a cached copy of local time period information (which includes the local // time offset from UTC) that is populated by a call to one of the 'configure' // methods. The cache *must* be configured prior to the first call of // 'localTimeOffset'. That cached information is updated on receipt of a // request with a datetime value outside of the range covered by the cached // information. As there are usually are only a few timezone transitions per // year, the cache hit rate should be very high for typical applications. The // cached information might be invalidated by updates to the Zoneinfo database; // however, those occur are also infrequent events. // // A successful return from one of the 'configure' methods is a prerequisite to // the use of most of the other functions provided here. Most methods are // thread-safe. Refer to the function-level documentation for details. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Using 'localTimeOffset' as the Local Time Offset Callback /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose we must quickly generate time stamp values in local time (e.g., on // records for a high frequency logger) and the default performance of the // relevant methods of 'bdlt::CurrentTime' is inadequate. Further suppose that // we must do so arbitrary time values and time zones. Those requirements can // be met by installing the 'localTimeOffset' method of // 'baltzo::LocalTimeOffsetUtil' as the local time callback used by // 'bdlt::CurrentTime'. // // First, specify the time zone to be used by the callback and a UTC date time // for the initial offset information in the cache. //.. // assert(0 == baltzo::LocalTimeOffsetUtil::updateCount()); // // int status = baltzo::LocalTimeOffsetUtil::configure("America/New_York", // bdlt::Datetime(2013, // 2, // 26)); // assert(0 == status); // assert(1 == baltzo::LocalTimeOffsetUtil::updateCount()); // // bsl::string timezone; // // baltzo::LocalTimeOffsetUtil::loadTimezone(&timezone); // assert(0 == strcmp("America/New_York", timezone.c_str())); //.. // Notice that the value returned by the 'updateCount' method is increased by // one after then time zone information has been set. // // Then, use the 'setLoadLocalTimeOffsetCallback' method to set the // 'localTimeOffset' of 'baltzo::LocalTimeOffsetUtil' as the local time offset // callback used in 'bdlt::CurrentTime'. //.. // bdlt::LocalTimeOffset::LocalTimeOffsetCallback previousCallback = // baltzo::LocalTimeOffsetUtil::setLoadLocalTimeOffsetCallback(); // // assert(&baltzo::LocalTimeOffsetUtil::localTimeOffset // == bdlt::CurrentTime::localTimeOffsetCallback()); //.. // Notice that previously installed callback was saved so we can restore it, if // needed. // // Now, calls to 'bdlt::CurrentTime' methods will use the method we installed. // For example, we can check the time offset in New York for three dates of // interest: //.. // bsls::Types::Int64 offsetInSeconds = // bdlt::LocalTimeOffset::localTimeOffset(bdlt::Datetime(2013, 2, 26)) // .totalSeconds(); // assert( 0 == status); // assert(-5 * 3600 == offsetInSeconds); // assert( 1 == baltzo::LocalTimeOffsetUtil::updateCount()); // // baltzo::LocalTimeOffsetUtil::loadTimezone(&timezone); // assert( 0 == strcmp("America/New_York", timezone.c_str())); // // offsetInSeconds = // bdlt::LocalTimeOffset::localTimeOffset(bdlt::Datetime(2013, 7, 4)) // .totalSeconds(); // assert(-4 * 3600 == offsetInSeconds); // assert( 2 == baltzo::LocalTimeOffsetUtil::updateCount()); // baltzo::LocalTimeOffsetUtil::loadTimezone(&timezone); // assert( 0 == strcmp("America/New_York", timezone.c_str())); // // offsetInSeconds = // bdlt::LocalTimeOffset::localTimeOffset(bdlt::Datetime(2013, 12, 21)) // .totalSeconds(); // assert(-5 * 3600 == offsetInSeconds); // assert( 3 == baltzo::LocalTimeOffsetUtil::updateCount()); // baltzo::LocalTimeOffsetUtil::loadTimezone(&timezone); // assert( 0 == strcmp("America/New_York", timezone.c_str())); //.. // Notice that the value returned by 'updateCount()' is unchanged by our first // request, but incremented by the second and third request, which transitions // into and then out of daylight saving time. Also notice that the updates // change the offset information but do not change the timezone. // // Finally, we restore the original local time callback. //.. // previousCallback = bdlt::LocalTimeOffset::setLocalTimeOffsetCallback( // previousCallback); // ASSERT(previousCallback == &baltzo::LocalTimeOffsetUtil::localTimeOffset); //.. #include <baltzo_localtimeperiod.h> #include <baltzo_timezoneutil.h> #include <balscm_version.h> #include <bdlt_currenttime.h> #include <bdlt_datetime.h> #include <bdlt_localtimeoffset.h> #include <bslmt_rwmutex.h> #include <bsls_libraryfeatures.h> #include <bsl_string.h> #include <bsls_atomic.h> #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR #include <memory_resource> #endif namespace BloombergLP { namespace baltzo { // ========================== // struct LocalTimeOffsetUtil // ========================== struct LocalTimeOffsetUtil { // This 'struct' provides a namespace for a 'bdlt::LocalTimeOffset' local // time offset callback, and functions that manage the timezone information // reported by that callback. All public methods are *thread-safe*. // CLASS DATA private: static bsls::AtomicInt s_updateCount; // PRIVATE CLASS METHODS static int configureImp(const char *timezone, const bdlt::Datetime& utcDatetime); // Set the local time period information used by the 'localTimeOffset' // method according to the specified 'timezone' at the specified // 'utcDatetime'. Return 0 on success, and a non-zero value otherwise. // This method is *not* thread-safe. static LocalTimePeriod *privateLocalTimePeriod(); // Return the address of the current local time period information. // This method is *not* thread-safe. static bslmt::RWMutex *privateLock(); // Return the address of the lock controlling access to the local time // period information. This method is *not* thread-safe. static bsl::string *privateTimezone(); // Return the address of the time period information. This method is // *not* thread-safe. // CLASS METHODS public: // *** local time offset methods *** #ifndef BDE_OMIT_INTERNAL_DEPRECATED // pending deprecation // DEPRECATED CLASS METHODS static void loadLocalTimeOffset(int *result, const bdlt::Datetime& utcDatetime); // !DEPRECATED!: Use 'localTimeOffset' instead. // // Efficiently load to the specified 'result' the offset of the local // time from UTC for the specified 'utcDatetime'. This function is // thread-safe. The behavior is undefined unless the local time zone // has been previously established by a call to the 'configure' method. // This method *is* thread-safe. Note that this function is no longer // used as a callback function. It exisis for backwards compatibility // with code that called it directly, and is deprecated. #endif // BDE_OMIT_INTERNAL_DEPRECATED -- pending deprecation static bsls::TimeInterval localTimeOffset( const bdlt::Datetime& utcDatetime); // Return the offset of the local time from UTC for the specified // 'utcDatetime'. This function is thread-safe. The behavior is // undefined unless the local time zone has been previously established // by a call to the 'configure' method. This method *is* thread-safe. static bdlt::LocalTimeOffset::LocalTimeOffsetCallback setLoadLocalTimeOffsetCallback(); // Set 'localTimeOffset' as the local time offset callback of // 'bdlt::CurrentTime'. Return the previously installed callback. // This method is *not* thread-safe. // *** configure methods *** static int configure(); // Set the local time period information used by the 'localTimeOffset' // method to that for the time zone in the 'TZ' environment variable at // the current UTC datetime. Return 0 on success, and a non-zero value // otherwise. This method is *not* thread-safe. The behavior is // undefined if the environment changes (e.g., a call to the 'putenv' // POSIX function) during the invocation of this method. static int configure(const char *timezone); // Set the local time period information used by the 'localTimeOffset' // method to that for specified 'timezone' at the current UTC datetime. // Return 0 on success, and a non-zero value otherwise. This method is // *not* thread-safe. static int configure(const char *timezone, const bdlt::Datetime& utcDatetime); // Set the local time period information used by the 'localTimeOffset' // method to that for the specified 'timezone' at the specified // 'utcDatetime'. Return 0 on success, and a non-zero value otherwise. // This method is *not* thread-safe. // *** accessor methods *** static void loadLocalTimePeriod(LocalTimePeriod *localTimePeriod); // Load to the specified 'localTimePeriod' the local time period // information currently used by the 'localTimeOffset' method. That // information is updated when 'localTimeOffset' is called with a // 'utcDatetime' outside the range 'localTimePeriod().utcStartTime()' // (inclusive) 'localTimePeriod().utcEndTime()' (exclusive). This // method is *not* thread-safe. The behavior is undefined if this // method is invoked before the successful invocation of a 'configure' // method. static void loadTimezone(bsl::string *timezone); static void loadTimezone(std::string *timezone); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static void loadTimezone(std::pmr::string *timezone); #endif // Load to the specified 'timezone' time zone identifier used to // determine the local time offset from UTC. This method *is* not // thread-safe. The behavior is undefined if this method is invoked // before the successful invocation of a 'configure' method. static int updateCount(); // Return the number of successful updates of the local time period // information since the start of the process. This count is // incremented on calls to any of the 'setTimeZone' methods and when // 'loadLocalTimePeriod' is called with a 'utcDatetime' outside the // range of the current local time period information. This method // *is* thread-safe. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------------------- // struct LocalTimeOffsetUtil // -------------------------- // CLASS METHODS // *** local time offset methods *** inline bdlt::LocalTimeOffset::LocalTimeOffsetCallback LocalTimeOffsetUtil::setLoadLocalTimeOffsetCallback() { return bdlt::LocalTimeOffset::setLocalTimeOffsetCallback( &LocalTimeOffsetUtil::localTimeOffset); } // *** accessor methods *** inline int LocalTimeOffsetUtil::updateCount() { return s_updateCount; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 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 ----------------------------------