// baltzo_timezoneutilimp.h                                           -*-C++-*-
#ifndef INCLUDED_BALTZO_TIMEZONEUTILIMP
#define INCLUDED_BALTZO_TIMEZONEUTILIMP

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Implement utilities for converting times between time zones.
//
//@CLASSES:
//  baltzo::TimeZoneUtilImp: implementation utilities for converting times
//
//@SEE_ALSO: baltzo_localdatetime, baltzo_zoneinfo,
//           baltzo_defaultzoneinfocache
//
//@DESCRIPTION: This component provides a namespace, `baltzo::TimeZoneUtilImp`,
// containing a set of utility functions for converting time values to and
// from, their corresponding local time representations in (possibly) different
// time zones.  The primary methods provided include: `convertUtcToLocalTime`
// for converting time values to their corresponding local-time values in some
// time zone; `convertLocalToUtc`, for converting a local-time value into the
// corresponding UTC time value; and `initLocalTime` for initializing a
// local-time value.  Additionally the `loadLocalTimeForUtc` method enable
// clients to obtain information about a time value, such as whether the
// provided time is a daylight-saving time value.
//
///Usage
///-----
// The following examples demonstrate how to use a `baltzo::TimeZoneUtilImp` to
// perform common operations on time values:
//
///Prologue: Initializing an Example `baltzo::ZoneinfoCache` Object
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Before using the methods provided by `baltzo::TimeZoneUtilImp` we must first
// define a `baltzo::ZoneinfoCache` object containing information about various
// time zones.  For the purposes of this example, we will define a sample cache
// containing only data for New York loaded through a `baltzo::TestLoader`
// object.  Note that, in general, clients should use data from an external
// data source (see `baltzo_datafileloader`).
//
// First, we create a Zoneinfo object for New York, and populate `newYork` with
// a correct time zone identifier:
// ```
// baltzo::Zoneinfo newYork;
// newYork.setIdentifier("America/New_York");
// ```
// Next, we create two local-time descriptors, one for standard time and one
// for daylight-saving time:
// ```
// baltzo::LocalTimeDescriptor est(-18000, false, "EST");
// baltzo::LocalTimeDescriptor edt(-14400, true,  "EDT");
// ```
// Then, we set the initial descriptor for `newYork` to Eastern Standard Time.
// Note that such an initial transition is required for a `baltzo::Zoneinfo`
// object to be considered Well-Defined (see `baltzo_zoneinfoutil`)
// ```
// const bsls::Epoch::TimeT64 firstTransitionTime =
//                 bdlt::EpochUtil::convertToTimeT64(bdlt::Datetime(1, 1, 1));
//
// newYork.addTransition(firstTransitionTime, est);
// ```
// Next, we create a series of transitions between these local-time descriptors
// for the years 2007-2011.  Note that the United States transitions to
// daylight saving time on the second Sunday in March, at 2am local time (07:00
// UTC), and transitions back to standard time on the first Sunday in November
// at 2am local time (06:00 UTC), resulting in an even number of transitions:
// ```
// static const bdlt::Datetime TRANSITION_TIMES[] = {
//     bdlt::Datetime(2007,  3, 11, 7),
//     bdlt::Datetime(2007, 11,  4, 6),
//     bdlt::Datetime(2008,  3,  9, 7),
//     bdlt::Datetime(2008, 11,  2, 6),
//     bdlt::Datetime(2009,  3,  8, 7),
//     bdlt::Datetime(2009, 11,  1, 6),
//     bdlt::Datetime(2010,  3, 14, 7),
//     bdlt::Datetime(2010, 11,  7, 6),
//     bdlt::Datetime(2011,  3, 13, 7),
//     bdlt::Datetime(2011, 11,  6, 6),
// };
// const int NUM_TRANSITION_TIMES =
//                         sizeof TRANSITION_TIMES / sizeof *TRANSITION_TIMES;
// assert(0 == NUM_TRANSITION_TIMES % 2);
//
// for (int i = 0; i < NUM_TRANSITION_TIMES; i += 2) {
//
//     const bsls::Epoch::TimeT64 edtTransitionTime =
//                     bdlt::EpochUtil::convertToTimeT64(TRANSITION_TIMES[i]);
//     newYork.addTransition(edtTransitionTime, edt);
//
//     const bsls::Epoch::TimeT64 estTransitionTime =
//                 bdlt::EpochUtil::convertToTimeT64(TRANSITION_TIMES[i + 1]);
//     newYork.addTransition(estTransitionTime, est);
// }
// ```
// Next, we verify that the time zone information we have created is considered
// well-defined (as discussed above):
// ```
// assert(true == baltzo::ZoneinfoUtil::isWellFormed(newYork));
// ```
// Finally, we create a `baltzo::TestLoader` object, provide it the description
// of `newYork`, and use it to initialize a `baltzo::ZoneinfoCache` object:
// ```
// baltzo::TestLoader loader;
// loader.setTimeZone(newYork);
// baltzo::ZoneinfoCache cache(&loader);
// ```
//
///Example 1: Converting from a UTC Time to a Local Time
///- - - - - - - - - - - - - - - - - - - - - - - - - - -
// In this example we demonstrate how to convert a UTC time to the
// corresponding local time using the `convertUtcToLocalTime` class method.
//
// We start by creating a `bdlt::Datetime` representing the UTC time "Dec 12,
// 2010 15:00":
// ```
// bdlt::Datetime utcTime(2010, 12, 12, 15, 0, 0);
// ```
// Now, we call `convertUtcToLocalTime` and supply as input `utcTime`, the time
// zone identifier for New York ("America/New_York"), and the cache of time
// zone information created in the prologue:
// ```
// bdlt::DatetimeTz localNYTime;
// baltzo::TimeZoneUtilImp::convertUtcToLocalTime(&localNYTime,
//                                               "America/New_York",
//                                               utcTime,
//                                               &cache);
// ```
// Finally we verify that `localNYTime` is "Dec 12, 2010 10:00+5:00", the time
// in New York corresponding to the UTC time "Dec 12, 2010 15:00".
// ```
// assert(utcTime                         == localNYTime.utcDatetime());
// assert(bdlt::Datetime(2010, 12, 12, 10) == localNYTime.localDatetime());
// assert(-5 * 60                         == localNYTime.offset());
// ```

#include <balscm_version.h>

#include <baltzo_dstpolicy.h>
#include <baltzo_localtimevalidity.h>
#include <baltzo_zoneinfo.h>

#include <bdlt_datetime.h>
#include <bdlt_datetimetz.h>

#include <bsl_iosfwd.h>

namespace BloombergLP {
namespace baltzo {

class LocalTimePeriod;
class ZoneinfoCache;

                           // =====================
                           // class TimeZoneUtilImp
                           // =====================

/// This `struct` provides a namespace for utility functions that convert
/// time values to, and from, local time.
struct TimeZoneUtilImp {

    // CLASS METHODS

    /// Load, into the specified `result`, the local date-time value, in the
    /// time zone indicated by the specified `resultTimeZoneId`,
    /// corresponding to the specified `utcTime`, using time zone
    /// information supplied by the specified `cache`.  Return 0 on success,
    /// and a non-zero value otherwise.  A return status of
    /// `ErrorCode::k_UNSUPPORTED_ID` indicates that `resultTimeZoneId` is
    /// not recognized, and a return status of `ErrorCode::k_OUT_OF_RANGE`
    /// indicates that an out of range value of `result` would have
    /// occurred.
    static int convertUtcToLocalTime(bdlt::DatetimeTz      *result,
                                     const char            *resultTimeZoneId,
                                     const bdlt::Datetime&  utcTime,
                                     ZoneinfoCache         *cache);

    /// Load, into the specified `result`, attributes characterizing local
    /// time indicated by the specified `transition` in the specified
    /// `timeZone`.  The behavior is undefined unless
    /// `ZoneinfoUtil::isWellFormed(timeZone)` is `true` and `transition` is
    /// a valid, non-ending, iterator into the sequence of transitions
    /// described by `timeZone`.
    static void createLocalTimePeriod(
                          LocalTimePeriod                          *result,
                          const Zoneinfo::TransitionConstIterator&  transition,
                          const Zoneinfo&                           timeZone);

    /// Load, into the specified `result`, the local date-time value --
    /// including the local date, time, and resolved UTC offset -- indicated
    /// by the specified `localTime` in the time zone indicated by the
    /// specified `timeZoneId`, using the specified `dstPolicy` to interpret
    /// whether or not `localTime` represents a daylight-saving time value,
    /// and using time zone information supplied by the specified `cache`.
    /// Load, into the specified `resultValidity` the value indicating the
    /// whether `localTime` is unique, ambiguous but valid, or invalid.
    /// Return 0 on success, and a non-zero value otherwise.  A return
    /// status of `ErrorCode::k_UNSUPPORTED_ID` indicates that `timeZoneId`
    /// is not recognized.  The behavior is undefined unless the result of
    /// the initialization falls within the supported epoch.
    static int initLocalTime(bdlt::DatetimeTz         *result,
                             LocalTimeValidity::Enum  *resultValidity,
                             const bdlt::Datetime&     localTime,
                             const char               *timeZoneId,
                             DstPolicy::Enum           dstPolicy,
                             ZoneinfoCache            *cache);

    /// Load, into the specified `result`, attributes characterizing local
    /// time at the specified `utcTime` in the time zone indicated by the
    /// specified `timeZoneId` (e.g., the offset from UTC, whether it is
    /// daylight-saving time), as well as the time interval over which those
    /// attributes apply, using time zone information supplied by the
    /// specified `cache`.  Return 0 on success, and a non-zero value
    /// otherwise.  A return status of `ErrorCode::k_UNSUPPORTED_ID`
    /// indicates that `timeZoneId` is not recognized.
    static int loadLocalTimePeriodForUtc(LocalTimePeriod       *result,
                                         const char            *timeZoneId,
                                         const bdlt::Datetime&  utcTime,
                                         ZoneinfoCache         *cache);

    /// Load, into the specified `result`, the local time and UTC offset of
    /// the specified `localTime` in the specified `timeZone`, using the
    /// specified `dstPolicy` to interpret whether or not `localTime`
    /// represents a daylight-saving time value; load into the specified
    /// `resultValidity` an indication of whether `localTime` is valid and
    /// unique, valid but ambiguous, or invalid; load into the specified
    /// `transitionIter` an iterator pointing to the transition that
    /// characterizes the attributes of `localTime`.  The behavior is
    /// undefined unless `ZoneinfoUtil::isWellFormed(timeZone)` is `true`
    /// and the result of the resolution falls within the supported epoch.
    static void resolveLocalTime(
                             bdlt::DatetimeTz                  *result,
                             LocalTimeValidity::Enum           *resultValidity,
                             Zoneinfo::TransitionConstIterator *transitionIter,
                             const bdlt::Datetime&              localTime,
                             DstPolicy::Enum                    dstPolicy,
                             const Zoneinfo&                    timeZone);

};

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 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 ----------------------------------
