// bdlt_localtimeoffset.h -*-C++-*- #ifndef INCLUDED_BDLT_LOCALTIMEOFFSET #define INCLUDED_BDLT_LOCALTIMEOFFSET #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide utilities to retrieve the local time offset. // //@CLASSES: // bdlt::LocalTimeOffset: namespace for local time offset functions // //@SEE_ALSO: bsls_timeinterval, bsls_systemtime, bsls_currenttime // //@DESCRIPTION: This component provides a 'struct', 'bdlt::LocalTimeOffset', in // which are defined a series of static methods for using a callback function // to retrieve the local time offset (the difference between the currently // executing task's local time and UTC time) at a specified UTC date and time. // 'LocalTimeoffset' provides a function 'localTimeOffset' that delegates to // the currently installed local time offset callback. By default, // 'localTimeOffsetDefault' is installed as the local time offset callback. // Clients can configure the default callback function by calling the // 'setLocalTimeOffsetCallback' function. // ///Thread Safety ///------------- // The functions provided by 'bdlt::LocalTimeOffset' are *thread-safe* (meaning // they may be called concurrently from multiple threads), including those that // set and retrieve the callback function. In addition, user-supplied callback // functions must be *thread-safe*. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Basic 'bdlt::LocalTimeOffset' Usage /// - - - - - - - - - - - - - - - - - - - - - - - // This example demonstrates how to use 'bdlt::LocalTimeOffset'. // // First, obtain the current UTC time - ignoring milliseconds - using // 'bsls::SystemTime' and 'bdlt::EpochUtil' (note that clients may prefer // 'bdlt_currenttime', which is not shown here for dependency reasons): //.. // bsls::TimeInterval now = bsls::SystemTime::nowRealtimeClock(); // // bdlt::Datetime utc = bdlt::EpochUtil::epoch() + // bdlt::DatetimeInterval(0, 0, 0, now.seconds()); //.. // Then, obtain the local time offset: //.. // bsls::TimeInterval localOffset = // bdlt::LocalTimeOffset::localTimeOffset(utc); //.. // Next, add the offset to the UTC time to obtain the local time: //.. // bdlt::Datetime local = utc; // local.addSeconds(localOffset.seconds()); //.. // Finally, stream the two time values to 'stdout': //.. // bsl::cout << "utc = " << utc << bsl::endl; // bsl::cout << "local = " << local << bsl::endl; //.. // The streaming operator produces output in the following format on 'stdout': //.. // utc = ddMONyyyy_hh:mm::ss.000 // local = ddMONyyyy_hh:mm::ss.000 //.. // ///Example 2: Using the Local Time Offset Callback ///- - - - - - - - - - - - - - - - - - - - - - - - // Suppose one has to provide time stamp values that always reflect local time // for a given location, even when local time transitions into and out of // daylight saving time. Further suppose that one must do this quite often // (e.g., for every record in a high frequency log), so the performance of the // default method for calculating local time offset is not adequate. Creation // and installation of a specialized user-defined callback for local time // offset allows one to solve this problem. // // First, create a utility class that provides a method of type // 'bdlt::LocalTimeOffset::LocalTimeOffsetCallback' that is valid for the // location of interest (New York) for the period of interest (the year 2013). //.. // struct MyLocalTimeOffsetUtilNewYork2013 { // // private: // // DATA // static int s_useCount; // static bdlt::Datetime s_startOfDaylightSavingTime; // UTC Datetime // static bdlt::Datetime s_resumptionOfStandardTime; // UTC Datetime // // public: // // CLASS METHODS // static bsls::TimeInterval localTimeOffset( // const bdlt::Datetime& utcDatetime); // // Return a 'bsls::TimeInterval' value representing the difference // // between the local time for the "America/New_York" timezone and // // UTC time at the specified 'utcDatetime'. The behavior is // // undefined unless '2013 == utcDatetime.date().year()'. // // static int useCount(); // // Return the number of invocations of the 'localTimeOffset' since // // the start of the process. // }; // // // DATA // int MyLocalTimeOffsetUtilNewYork2013::s_useCount = 0; // // bdlt::Datetime // MyLocalTimeOffsetUtilNewYork2013::s_startOfDaylightSavingTime(2013, // 3, // 10, // 7); // bdlt::Datetime // MyLocalTimeOffsetUtilNewYork2013::s_resumptionOfStandardTime(2013, // 11, // 3, // 6); // // // CLASS METHODS // bsls::TimeInterval MyLocalTimeOffsetUtilNewYork2013::localTimeOffset( // const bdlt::Datetime& utcDatetime) // { // assert(2013 == utcDatetime.date().year()); // // ++s_useCount; // int seconds = utcDatetime < s_startOfDaylightSavingTime ? -18000 : // utcDatetime < s_resumptionOfStandardTime ? -14400 : // -18000; // return bsls::TimeInterval(seconds, 0); // } // // int MyLocalTimeOffsetUtilNewYork2013::useCount() // { // return s_useCount; // } //.. // Note that the transition times into and out of daylight saving for New York // are given in UTC. Also notice that we do not attempt to make the // 'localTimeOffset' method 'inline', since we must take its address to install // it as the callback. // // Then, we install this 'localTimeOffset' as the local time offset callback. //.. // bdlt::LocalTimeOffset::LocalTimeOffsetCallback defaultCallback = // bdlt::LocalTimeOffset::setLocalTimeOffsetCallback( // &MyLocalTimeOffsetUtilNewYork2013:: // localTimeOffset); // // assert(bdlt::LocalTimeOffset::localTimeOffsetDefault == defaultCallback); // assert(&MyLocalTimeOffsetUtilNewYork2013::localTimeOffset // == bdlt::LocalTimeOffset::localTimeOffsetCallback()); //.. // Now, we can use the 'bdlt::LocalTimeOffset::localTimeOffset' method to // obtain the local time offsets in New York on several dates of interest. The // increasing values from our 'useCount' method assures us that the callback we // defined is indeed being used. //.. // assert(0 == MyLocalTimeOffsetUtilNewYork2013::useCount()); // // bsls::Types::Int64 offset; // bdlt::Datetime newYearsDay(2013, 1, 1); // bdlt::Datetime independenceDay(2013, 7, 4); // bdlt::Datetime newYearsEve(2013, 12, 31); // // offset = bdlt::LocalTimeOffset::localTimeOffset(newYearsDay).seconds(); // assert(-5 * 3600 == offset); // assert( 1 == MyLocalTimeOffsetUtilNewYork2013::useCount()); // // offset = bdlt::LocalTimeOffset::localTimeOffset(independenceDay).seconds(); // assert(-4 * 3600 == offset); // assert( 2 == MyLocalTimeOffsetUtilNewYork2013::useCount()); // // offset = bdlt::LocalTimeOffset::localTimeOffset(newYearsEve).seconds(); // assert(-5 * 3600 == offset); // assert( 3 == MyLocalTimeOffsetUtilNewYork2013::useCount()); //.. // Finally, to be neat, we restore the local time offset callback to the // default callback: //.. // bdlt::LocalTimeOffset::setLocalTimeOffsetCallback(defaultCallback); // assert(&bdlt::LocalTimeOffset::localTimeOffsetDefault // == bdlt::LocalTimeOffset::localTimeOffsetCallback()); //.. #include <bdlscm_version.h> #include <bdlt_datetime.h> #include <bsls_assert.h> #include <bsls_atomicoperations.h> #include <bsls_review.h> #include <bsls_timeinterval.h> #include <bsls_types.h> namespace BloombergLP { namespace bdlt { // ===================== // class LocalTimeOffset // ===================== struct LocalTimeOffset { // This 'struct' provides a namespace for local-time-offset procedures // including a configurable global callback mechanism. The use of these // procedures is thread-safe (see 'Thread Safety'). // TYPES typedef bsls::TimeInterval (*LocalTimeOffsetCallback)( const Datetime& utcDatetime); // 'LocalTimeOffsetCallback' is an alias for the type of a function // that returns a 'bsls::TimeInterval' value representing the // difference between local time and UTC time at the specified // 'utcDatetime'. This function must be thread-safe in multi-threaded // builds. Note that the installed callback function must have // geographic information specifying the local timezone. private: static bsls::AtomicOperations::AtomicTypes::Pointer s_localTimeOffsetCallback_p; // address of local-time-offset callback public: // CLASS METHODS // ** computation method ** static bsls::TimeInterval localTimeOffset(const Datetime& utcDatetime); // Return a 'bsls::TimeInterval' value representing the difference // between local time and UTC time at the specified 'utcDatetime'. // This method uses the currently installed local-time-offset callback // mechanism. // ** default callback ** static bsls::TimeInterval localTimeOffsetDefault( const Datetime& utcDatetime); // Return a 'bsls::TimeInterval' value representing the difference // between local time and UTC time at the specified 'utcDatetime'. // Note that the local time zone is determined by the 'TZ' environment // variable in the same manner as the 'localtime' POSIX function. // ** set callback ** static LocalTimeOffsetCallback setLocalTimeOffsetCallback( LocalTimeOffsetCallback callback); // Set the specified 'callback' as the function to be used to return a // 'bsls::TimeInterval' value representing the difference between // local time and UTC time at a specified UTC date and time. Return // the previously installed 'LocalTimeOffsetCallback' function. The // behavior is undefined unless '0 != callback'. // ** get current callback ** static LocalTimeOffsetCallback localTimeOffsetCallback(); // Return the currently installed 'LocalTimeOffsetCallback' function. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ** computation method ** inline bsls::TimeInterval LocalTimeOffset:: localTimeOffset(const Datetime& utcDatetime) { return localTimeOffsetCallback()(utcDatetime); } // ** set callback ** inline LocalTimeOffset::LocalTimeOffsetCallback LocalTimeOffset::setLocalTimeOffsetCallback(LocalTimeOffsetCallback callback) { BSLS_ASSERT(callback); LocalTimeOffsetCallback previousCallback = localTimeOffsetCallback(); bsls::AtomicOperations::setPtrRelease( &s_localTimeOffsetCallback_p, reinterpret_cast<void *>( reinterpret_cast<bsls::Types::IntPtr>(callback))); return previousCallback; } // ** get current callback ** inline LocalTimeOffset::LocalTimeOffsetCallback LocalTimeOffset::localTimeOffsetCallback() { return reinterpret_cast<LocalTimeOffsetCallback>( reinterpret_cast<bsls::Types::IntPtr>( bsls::AtomicOperations::getPtrAcquire( &s_localTimeOffsetCallback_p))); } } // 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 ----------------------------------