<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#ifndef _Stroika_Foundation_Time_DateTime_h_
#define _Stroika_Foundation_Time_DateTime_h_ 1

#include "../StroikaPreComp.h"

#include <climits>
#include <ctime>
#include <locale>
#include <string>

#if qPlatform_Windows
#include <Windows.h>
#endif

#include "../Characters/String.h"
#include "../Configuration/Common.h"
#include "../Configuration/Enumeration.h"
#include "../Math/Common.h"

#include "Date.h"
#include "TimeOfDay.h"
#include "Timezone.h"

/**
 *  \file
 *
 *  \version    <a href="Code-Status.md">Alpha-Late</a>
 *
 * TODO:
 *
 *      @todo   Need DefaultNames<> for enums in DateTime module
 *
 *      @todo   Support various 64bit int (epoch time) types - even if time_t is 32-bit (such as on AIX).
 *              Be careful about overflow in underlying types like Date and TimeOfDay() however.
 *
 *      @todo   I'm not sure eCurrentLocale_WithZerosStripped is a good idea. Not sure if better
 *              to use separate format print arg or???
 *
 *      @todo   LCID stuff appears to be obsolete, and perhaps not supported by MSFT any longer. Consider
 *              de-supporting.
 *
 *      @todo   We sometimes store datetime internally as localetime, and sometimes as UTC. Maybe we
 *              should alway use UTC? If we use localtime and the timezone changes while we are running
 *              (timezone or DST) - we could get funky results.
 *
 *      @todo   (medium) Consider using strftime and strptime with %FT%T%z.
 *              Same format
 *              That doesn’t use std::locale()
 *              En.cppreference.com/w/cpp/io/manip/get_time
 *              istringstream xxx (“2011-feb…”)
 *              ss.imbue(std::locale() (“de-DE”));
 *              ss >> std::get_time(&t, “%FT%T%z”)
 *
 *      @todo   Maybe use wcsftime (buf, NEltsOf (buf), L"%I:%M %p", &temp);   or related for formatting dates/time?
 *
 *      @todo   Consider using strptime/strftime - and possibly use that to replace windows formatting APIs?
 *
 *      @todo   Should we PIN or throw OVERFLOW exception on values/requests which are out of range?
 *
 *      @todo   Consider replacing eXML with eISO8601_PF?  Not 100% sure they are the same. Maybe we should
 *              support BOTH here? Maybe where they differ doesn't matter for this class?
 *
 *      @todo   Error checking in conversions (date to string/Format/String2Date - should be doign THROWS on
 *              bad conversions I think - moistly an issue for the locale-based stuff. Now it maybe just
 *              silently returns empty date/time/etc. Better to except!
 *
 *      @todo   Future directions consider representing as big struct
 *          o   And maybe store cached string reps for common cases as optimization and
 *              store cached second-offset (mutable) for quick compares
 *          o   Note for timeofday it COULD be enhanced in the future to store TOD as
 *              fractional number of seconds. COULD use LINUX style struct with number of seconds and fixed
 *              point like number of nanoseconds (or some such)
 *
 *      @todo   (minor) Consider if DateTime stuff should cache locale () in some methods (static) –
 *              so can be re-used?? Performance tweek cuz current stuff doing new locale() does
 *              locking to bump refcount?
 */

namespace Stroika {
    namespace Foundation {
        namespace Time {

            using Characters::String;

            class Duration; // forward declare for Differnce ()

            /*
             *  Description:
             *
             *      DateTime is more than just a combination of Date, and Time. It also introduces the notion of TIMEZONE.
             *
             *      Timezone may be "unknown" (missing), or a Timezone object (@see Timezone).
             *
             *      'empty' concept:
             *          Treat it as DISTINCT from any other DateTime. However, when converting it to a number
             *          of seconds or days (JulienRep), treat empty as DateTime::kMin. For format routine,
             *          return empty string. And for COMPARIONS (=,<,<=, etc) treat it as LESS THAN DateTime::kMin.
             *          This is a bit like the floating point concept of negative infinity.
             *
             *          This concept is the same as the Date::empty () concept.
             *
             *  <<<CONSIDERING MAYBE REQUIRING>>>
             *          Also note that if empty () - BOTH the date and timeofday parts of the DateTime must be empty, and
             *          the value of timezone is undefined. That way, d.empty () iff d == DateTime ()
             *  <<</CONSIDERING MAYBE REQUIRING>>>
             *
             *  \note   See coding conventions document about operator usage: Compare () and operator<, operator>, etc
             *
             *  \note   In the DateTime code, time_t is always assumed to be in UTC, because according to http://en.cppreference.com/w/c/chrono/time_t:
             *              Although not defined by the C standard, this is almost always an integral 
             *              value holding the number of seconds (not counting leap seconds) 
             *              since 00:00, Jan 1 1970 UTC
             */
            class DateTime {
            public:
                /**
                 *  Construct a DateTime record with the given date and time value. Presume that these values
                 *  apply to the given (argument) timezone. This does not adjust the value of date/time for the given tz -
                 *  but just records that this datetime refers to the given timezone.
                 *
                 *  To change TO a target timezone, use AsUTC () or AsLocalTime ().
                 *
                 *  explicit DateTime (time_t unixEpochTime) noexcept
                 *      Creates a DateTime object in UTC, using UNIX Epoch time.
                 *
                 *  explicit DateTime (const FILETIME& fileTime, const Memory::Optional<Timezone>& tz = Timezone::kUTC) noexcept;
                 *      Most windows APIs return filetimes in UTC (or so it appears). Because of this,
                 *      our default interpretation of a FILETIME structure as as UTC.
                 *      Call DateTime (ft).AsLocalTime () to get the value returned in local time.
                 *
                 *  \note DateTime (time_t unixEpochTime) returns a datetime in UTC
                 */
                constexpr DateTime () noexcept;
                constexpr DateTime (const DateTime& src) = default;
                constexpr DateTime (DateTime&& src)      = default;
                constexpr DateTime (const Date& d) noexcept;
                DateTime (const DateTime& dt, const Date& updateDate) noexcept;
                DateTime (const DateTime& dt, const TimeOfDay& updateTOD) noexcept;
                constexpr DateTime (const Date& date, const TimeOfDay& timeOfDay, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
                explicit DateTime (time_t unixEpochTime) noexcept;
                explicit DateTime (const tm& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
#if qPlatform_POSIX
                explicit DateTime (const timeval& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
                explicit DateTime (const timespec& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
#elif qPlatform_Windows
                explicit DateTime (const SYSTEMTIME& sysTime, const Memory::Optional<Timezone>& tz = Timezone::kLocalTime) noexcept;
                explicit DateTime (const FILETIME& fileTime, const Memory::Optional<Timezone>& tz = Timezone::kUTC) noexcept;
#endif<commit_msg>revert last change - DateTime move CTOR is not constexpr (maybe can figure out how todo but not yet)<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#ifndef _Stroika_Foundation_Time_DateTime_h_
#define _Stroika_Foundation_Time_DateTime_h_ 1

#include "../StroikaPreComp.h"

#include <climits>
#include <ctime>
#include <locale>
#include <string>

#if qPlatform_Windows
#include <Windows.h>
#endif

#include "../Characters/String.h"
#include "../Configuration/Common.h"
#include "../Configuration/Enumeration.h"
#include "../Math/Common.h"

#include "Date.h"
#include "TimeOfDay.h"
#include "Timezone.h"

/**
 *  \file
 *
 *  \version    <a href="Code-Status.md">Alpha-Late</a>
 *
 * TODO:
 *
 *      @todo   Need DefaultNames<> for enums in DateTime module
 *
 *      @todo   Support various 64bit int (epoch time) types - even if time_t is 32-bit (such as on AIX).
 *              Be careful about overflow in underlying types like Date and TimeOfDay() however.
 *
 *      @todo   I'm not sure eCurrentLocale_WithZerosStripped is a good idea. Not sure if better
 *              to use separate format print arg or???
 *
 *      @todo   LCID stuff appears to be obsolete, and perhaps not supported by MSFT any longer. Consider
 *              de-supporting.
 *
 *      @todo   We sometimes store datetime internally as localetime, and sometimes as UTC. Maybe we
 *              should alway use UTC? If we use localtime and the timezone changes while we are running
 *              (timezone or DST) - we could get funky results.
 *
 *      @todo   (medium) Consider using strftime and strptime with %FT%T%z.
 *              Same format
 *              That doesn’t use std::locale()
 *              En.cppreference.com/w/cpp/io/manip/get_time
 *              istringstream xxx (“2011-feb…”)
 *              ss.imbue(std::locale() (“de-DE”));
 *              ss >> std::get_time(&t, “%FT%T%z”)
 *
 *      @todo   Maybe use wcsftime (buf, NEltsOf (buf), L"%I:%M %p", &temp);   or related for formatting dates/time?
 *
 *      @todo   Consider using strptime/strftime - and possibly use that to replace windows formatting APIs?
 *
 *      @todo   Should we PIN or throw OVERFLOW exception on values/requests which are out of range?
 *
 *      @todo   Consider replacing eXML with eISO8601_PF?  Not 100% sure they are the same. Maybe we should
 *              support BOTH here? Maybe where they differ doesn't matter for this class?
 *
 *      @todo   Error checking in conversions (date to string/Format/String2Date - should be doign THROWS on
 *              bad conversions I think - moistly an issue for the locale-based stuff. Now it maybe just
 *              silently returns empty date/time/etc. Better to except!
 *
 *      @todo   Future directions consider representing as big struct
 *          o   And maybe store cached string reps for common cases as optimization and
 *              store cached second-offset (mutable) for quick compares
 *          o   Note for timeofday it COULD be enhanced in the future to store TOD as
 *              fractional number of seconds. COULD use LINUX style struct with number of seconds and fixed
 *              point like number of nanoseconds (or some such)
 *
 *      @todo   (minor) Consider if DateTime stuff should cache locale () in some methods (static) –
 *              so can be re-used?? Performance tweek cuz current stuff doing new locale() does
 *              locking to bump refcount?
 */

namespace Stroika {
    namespace Foundation {
        namespace Time {

            using Characters::String;

            class Duration; // forward declare for Differnce ()

            /*
             *  Description:
             *
             *      DateTime is more than just a combination of Date, and Time. It also introduces the notion of TIMEZONE.
             *
             *      Timezone may be "unknown" (missing), or a Timezone object (@see Timezone).
             *
             *      'empty' concept:
             *          Treat it as DISTINCT from any other DateTime. However, when converting it to a number
             *          of seconds or days (JulienRep), treat empty as DateTime::kMin. For format routine,
             *          return empty string. And for COMPARIONS (=,<,<=, etc) treat it as LESS THAN DateTime::kMin.
             *          This is a bit like the floating point concept of negative infinity.
             *
             *          This concept is the same as the Date::empty () concept.
             *
             *  <<<CONSIDERING MAYBE REQUIRING>>>
             *          Also note that if empty () - BOTH the date and timeofday parts of the DateTime must be empty, and
             *          the value of timezone is undefined. That way, d.empty () iff d == DateTime ()
             *  <<</CONSIDERING MAYBE REQUIRING>>>
             *
             *  \note   See coding conventions document about operator usage: Compare () and operator<, operator>, etc
             *
             *  \note   In the DateTime code, time_t is always assumed to be in UTC, because according to http://en.cppreference.com/w/c/chrono/time_t:
             *              Although not defined by the C standard, this is almost always an integral 
             *              value holding the number of seconds (not counting leap seconds) 
             *              since 00:00, Jan 1 1970 UTC
             */
            class DateTime {
            public:
                /**
                 *  Construct a DateTime record with the given date and time value. Presume that these values
                 *  apply to the given (argument) timezone. This does not adjust the value of date/time for the given tz -
                 *  but just records that this datetime refers to the given timezone.
                 *
                 *  To change TO a target timezone, use AsUTC () or AsLocalTime ().
                 *
                 *  explicit DateTime (time_t unixEpochTime) noexcept
                 *      Creates a DateTime object in UTC, using UNIX Epoch time.
                 *
                 *  explicit DateTime (const FILETIME& fileTime, const Memory::Optional<Timezone>& tz = Timezone::kUTC) noexcept;
                 *      Most windows APIs return filetimes in UTC (or so it appears). Because of this,
                 *      our default interpretation of a FILETIME structure as as UTC.
                 *      Call DateTime (ft).AsLocalTime () to get the value returned in local time.
                 *
                 *  \note DateTime (time_t unixEpochTime) returns a datetime in UTC
                 */
                constexpr DateTime () noexcept;
                constexpr DateTime (const DateTime& src) = default;
                DateTime (DateTime&& src)                = default;
                constexpr DateTime (const Date& d) noexcept;
                DateTime (const DateTime& dt, const Date& updateDate) noexcept;
                DateTime (const DateTime& dt, const TimeOfDay& updateTOD) noexcept;
                constexpr DateTime (const Date& date, const TimeOfDay& timeOfDay, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
                explicit DateTime (time_t unixEpochTime) noexcept;
                explicit DateTime (const tm& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
#if qPlatform_POSIX
                explicit DateTime (const timeval& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
                explicit DateTime (const timespec& tmTime, const Memory::Optional<Timezone>& tz = Timezone_kUnknown) noexcept;
#elif qPlatform_Windows
                explicit DateTime (const SYSTEMTIME& sysTime, const Memory::Optional<Timezone>& tz = Timezone::kLocalTime) noexcept;
                explicit DateTime (const FILETIME& fileTime, const Memory::Optional<Timezone>& tz = Timezone::kUTC) noexcept;
#endif
{'fraction_non_alphanumeric': 0.07765950746362663, 'fraction_numerical': 0.004282924985828557, 'mean_word_length': 2.061114324272219, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4223552', 'n_tokens_mistral': 4223, 'n_tokens_neox': 4037, 'n_words': 1663}