2015-03-26 19:59:06 -05:00
/********************************************************************\
* gnc - datetime . cpp - - Date and Time classes for GnuCash *
* *
* Copyright 2015 John Ralls < jralls @ ceridwen . us > *
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation ; either version 2 of *
* the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , contact : *
* *
* Free Software Foundation Voice : + 1 - 617 - 542 - 5942 *
* 51 Franklin Street , Fifth Floor Fax : + 1 - 617 - 542 - 2652 *
* Boston , MA 02110 - 1301 , USA gnu @ gnu . org *
* *
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern " C "
{
2017-10-26 04:14:21 -05:00
# include <config.h>
2015-03-26 19:59:06 -05:00
# include "platform.h"
}
# include <boost/date_time/gregorian/gregorian.hpp>
2015-12-15 15:38:50 -06:00
# include <boost/date_time/posix_time/posix_time.hpp>
2017-12-12 10:42:32 -06:00
# include <boost/date_time/local_time/local_time.hpp>
2017-04-21 09:58:20 -05:00
# include <boost/regex.hpp>
# include <libintl.h>
# include <map>
2015-03-26 19:59:06 -05:00
# include <memory>
2015-12-15 15:38:50 -06:00
# include <iostream>
# include <sstream>
2016-06-30 16:09:25 -05:00
# include <string>
2017-04-21 09:58:20 -05:00
# include <vector>
2015-03-26 19:59:06 -05:00
# include "gnc-timezone.hpp"
# include "gnc-datetime.hpp"
2017-04-21 09:58:20 -05:00
# define N_(string) string //So that xgettext will find it
2015-03-26 19:59:06 -05:00
using Date = boost : : gregorian : : date ;
using Month = boost : : gregorian : : greg_month ;
using PTime = boost : : posix_time : : ptime ;
using LDT = boost : : local_time : : local_date_time ;
using Duration = boost : : posix_time : : time_duration ;
using LDTBase = boost : : local_time : : local_date_time_base < PTime , boost : : date_time : : time_zone_base < PTime , char > > ;
2015-12-26 14:18:27 -06:00
using boost : : date_time : : not_a_date_time ;
2015-03-26 19:59:06 -05:00
using time64 = int64_t ;
static const TimeZoneProvider tzp ;
// For converting to/from POSIX time.
static const PTime unix_epoch ( Date ( 1970 , boost : : gregorian : : Jan , 1 ) ,
2015-04-28 19:53:35 -05:00
boost : : posix_time : : seconds ( 0 ) ) ;
2015-04-28 12:06:18 -05:00
static const TZ_Ptr utc_zone ( new boost : : local_time : : posix_time_zone ( " UTC-0 " ) ) ;
2015-03-26 19:59:06 -05:00
2015-04-07 17:36:40 -05:00
/* To ensure things aren't overly screwed up by setting the nanosecond clock for boost::date_time. Don't do it, though, it doesn't get us anything and slows down the date/time library. */
# ifndef BOOST_DATE_TIME_HAS_NANOSECONDS
static constexpr auto ticks_per_second = INT64_C ( 1000000 ) ;
# else
static constexpr auto ticks_per_second = INT64_C ( 1000000000 ) ;
# endif
2015-03-26 19:59:06 -05:00
2017-04-21 09:58:20 -05:00
/* Vector of date formats understood by gnucash and corresponding regex
* to parse each from an external source
* Note : while the format names are using a " - " as separator , the
* regexes will accept any of " -/.' " and will also work for dates
* without separators .
*/
const std : : vector < GncDateFormat > GncDate : : c_formats ( {
GncDateFormat {
N_ ( " y-m-d " ) ,
" (?: " // either y-m-d
" (?<YEAR>[0-9]+)[-/.' ]+ "
" (?<MONTH>[0-9]+)[-/.' ]+ "
" (?<DAY>[0-9]+) "
" | " // or CCYYMMDD
" (?<YEAR>[0-9]{4}) "
" (?<MONTH>[0-9]{2}) "
" (?<DAY>[0-9]{2}) "
" ) "
} ,
GncDateFormat {
N_ ( " d-m-y " ) ,
" (?: " // either d-m-y
" (?<DAY>[0-9]+)[-/.' ]+ "
" (?<MONTH>[0-9]+)[-/.' ]+ "
" (?<YEAR>[0-9]+) "
" | " // or DDMMCCYY
" (?<DAY>[0-9]{2}) "
" (?<MONTH>[0-9]{2}) "
" (?<YEAR>[0-9]{4}) "
" ) "
} ,
GncDateFormat {
N_ ( " m-d-y " ) ,
" (?: " // either m-d-y
" (?<MONTH>[0-9]+)[-/.' ]+ "
" (?<DAY>[0-9]+)[-/.' ]+ "
" (?<YEAR>[0-9]+) "
" | " // or MMDDCCYY
" (?<MONTH>[0-9]{2}) "
" (?<DAY>[0-9]{2}) "
" (?<YEAR>[0-9]{4}) "
" ) "
} ,
// Note year is still checked for in the regexes below
// This is to be able to raise an error if one is found for a yearless date format
GncDateFormat {
( N_ ( " d-m " ) ) ,
" (?: " // either d-m(-y)
" (?<DAY>[0-9]+)[-/.' ]+ "
" (?<MONTH>[0-9]+)(?:[-/.' ]+ "
" (?<YEAR>[0-9]+))? "
" | " // or DDMM(CCYY)
" (?<DAY>[0-9]{2}) "
" (?<MONTH>[0-9]{2}) "
" (?<YEAR>[0-9]+)? "
" ) "
} ,
GncDateFormat {
( N_ ( " m-d " ) ) ,
" (?: " // either m-d(-y)
" (?<MONTH>[0-9]+)[-/.' ]+ "
" (?<DAY>[0-9]+)(?:[-/.' ]+ "
" (?<YEAR>[0-9]+))? "
" | " // or MMDD(CCYY)
" (?<MONTH>[0-9]{2}) "
" (?<DAY>[0-9]{2}) "
" (?<YEAR>[0-9]+)? "
" ) "
}
} ) ;
2015-03-26 19:59:06 -05:00
/** Private implementation of GncDateTime. See the documentation for that class.
*/
static LDT
LDT_from_unix_local ( const time64 time )
{
2015-04-28 17:23:26 -05:00
try
{
2015-04-28 19:53:35 -05:00
PTime temp ( unix_epoch . date ( ) ,
boost : : posix_time : : hours ( time / 3600 ) +
boost : : posix_time : : seconds ( time % 3600 ) ) ;
auto tz = tzp . get ( temp . date ( ) . year ( ) ) ;
return LDT ( temp , tz ) ;
2015-04-28 17:23:26 -05:00
}
catch ( boost : : gregorian : : bad_year )
{
2015-04-28 19:53:35 -05:00
throw ( std : : invalid_argument ( " Time value is outside the supported year range. " ) ) ;
2015-04-28 17:23:26 -05:00
}
2015-03-26 19:59:06 -05:00
}
2015-04-26 18:44:39 -05:00
static LDT
LDT_from_struct_tm ( const struct tm tm )
{
2015-04-28 17:23:26 -05:00
try
{
2015-04-28 19:53:35 -05:00
auto tdate = boost : : gregorian : : date_from_tm ( tm ) ;
auto tdur = boost : : posix_time : : time_duration ( tm . tm_hour , tm . tm_min ,
tm . tm_sec , 0 ) ;
auto tz = tzp . get ( tdate . year ( ) ) ;
2017-12-12 10:42:32 -06:00
LDT ldt ( tdate , tdur , tz , LDTBase : : EXCEPTION_ON_ERROR ) ;
return ldt ;
2015-04-28 17:23:26 -05:00
}
catch ( boost : : gregorian : : bad_year )
{
2015-04-28 19:53:35 -05:00
throw ( std : : invalid_argument ( " Time value is outside the supported year range. " ) ) ;
2015-04-28 17:23:26 -05:00
}
2017-12-12 10:42:32 -06:00
catch ( boost : : local_time : : time_label_invalid )
{
throw ( std : : invalid_argument ( " Struct tm does not resolve to a valid time. " ) ) ;
}
catch ( boost : : local_time : : ambiguous_result )
{
throw ( std : : invalid_argument ( " Struct tm can resolve to more than one time. " ) ) ;
}
2015-04-26 18:44:39 -05:00
}
2017-12-12 23:01:58 -06:00
using TD = boost : : posix_time : : time_duration ;
2015-04-07 17:36:40 -05:00
class GncDateTimeImpl
{
public :
2017-01-14 13:49:48 -06:00
GncDateTimeImpl ( ) : m_time ( boost : : local_time : : local_sec_clock : : local_time ( tzp . get ( boost : : gregorian : : day_clock : : local_day ( ) . year ( ) ) ) ) { }
2015-04-07 17:36:40 -05:00
GncDateTimeImpl ( const time64 time ) : m_time ( LDT_from_unix_local ( time ) ) { }
2015-04-26 18:44:39 -05:00
GncDateTimeImpl ( const struct tm tm ) : m_time ( LDT_from_struct_tm ( tm ) ) { }
2017-04-20 15:58:35 -05:00
GncDateTimeImpl ( const GncDateImpl & date , DayPart part = DayPart : : neutral ) ;
2018-02-24 12:55:03 -06:00
GncDateTimeImpl ( std : : string str ) ;
2015-04-07 17:36:40 -05:00
GncDateTimeImpl ( PTime & & pt ) : m_time ( pt , tzp . get ( pt . date ( ) . year ( ) ) ) { }
GncDateTimeImpl ( LDT & & ldt ) : m_time ( ldt ) { }
2015-04-10 11:33:51 -05:00
operator time64 ( ) const ;
2015-04-26 18:44:39 -05:00
operator struct tm ( ) const ;
2015-04-07 17:36:40 -05:00
void now ( ) { m_time = boost : : local_time : : local_sec_clock : : local_time ( tzp . get ( boost : : gregorian : : day_clock : : local_day ( ) . year ( ) ) ) ; }
2015-04-26 18:44:39 -05:00
long offset ( ) const ;
2015-04-28 17:23:26 -05:00
struct tm utc_tm ( ) const { return to_tm ( m_time . utc_time ( ) ) ; }
2015-04-28 12:06:18 -05:00
std : : unique_ptr < GncDateImpl > date ( ) const ;
2015-04-26 20:01:23 -05:00
std : : string format ( const char * format ) const ;
2016-11-06 11:39:21 -06:00
std : : string format_zulu ( const char * format ) const ;
2015-04-07 17:36:40 -05:00
private :
LDT m_time ;
2017-12-12 23:01:58 -06:00
static const TD time_of_day [ 3 ] ;
2015-04-07 17:36:40 -05:00
} ;
2015-04-10 11:33:51 -05:00
2017-12-12 23:01:58 -06:00
const TD GncDateTimeImpl : : time_of_day [ 3 ] = { TD ( 0 , 0 , 0 ) , TD ( 10 , 59 , 0 ) , TD ( 23 , 59 , 59 ) } ;
2017-04-20 14:42:24 -05:00
/** Private implementation of GncDate. See the documentation for that class.
*/
class GncDateImpl
{
public :
GncDateImpl ( ) : m_greg ( boost : : gregorian : : day_clock : : local_day ( ) ) { }
GncDateImpl ( const int year , const int month , const int day ) :
m_greg ( year , static_cast < Month > ( month ) , day ) { }
GncDateImpl ( Date d ) : m_greg ( d ) { }
2017-04-21 09:58:20 -05:00
GncDateImpl ( const std : : string str , const std : : string fmt ) ;
2017-04-20 14:42:24 -05:00
void today ( ) { m_greg = boost : : gregorian : : day_clock : : local_day ( ) ; }
ymd year_month_day ( ) const ;
std : : string format ( const char * format ) const ;
std : : string format_zulu ( const char * format ) const ;
private :
Date m_greg ;
2017-04-20 15:58:35 -05:00
friend GncDateTimeImpl : : GncDateTimeImpl ( const GncDateImpl & , DayPart ) ;
2017-04-29 11:01:12 -05:00
friend bool operator < ( const GncDateImpl & , const GncDateImpl & ) ;
friend bool operator > ( const GncDateImpl & , const GncDateImpl & ) ;
friend bool operator = = ( const GncDateImpl & , const GncDateImpl & ) ;
friend bool operator < = ( const GncDateImpl & , const GncDateImpl & ) ;
friend bool operator > = ( const GncDateImpl & , const GncDateImpl & ) ;
friend bool operator ! = ( const GncDateImpl & , const GncDateImpl & ) ;
2017-04-20 14:42:24 -05:00
} ;
/* Member function definitions for GncDateTimeImpl.
*/
2017-12-12 23:01:58 -06:00
2017-04-20 15:58:35 -05:00
GncDateTimeImpl : : GncDateTimeImpl ( const GncDateImpl & date , DayPart part ) :
2017-12-12 23:01:58 -06:00
m_time ( date . m_greg , time_of_day [ part ] , tzp . get ( date . m_greg . year ( ) ) ,
LDT : : NOT_DATE_TIME_ON_ERROR )
2017-04-20 15:58:35 -05:00
{
2017-12-12 23:01:58 -06:00
using boost : : posix_time : : hours ;
2017-04-20 15:58:35 -05:00
try
{
2017-12-12 23:01:58 -06:00
if ( part = = DayPart : : neutral )
{
auto offset = m_time . local_time ( ) - m_time . utc_time ( ) ;
m_time = LDT ( date . m_greg , time_of_day [ part ] , utc_zone ,
LDT : : EXCEPTION_ON_ERROR ) ;
if ( offset < hours ( - 10 ) )
m_time - = hours ( offset . hours ( ) + 10 ) ;
if ( offset > hours ( 13 ) )
2017-12-15 12:12:01 -06:00
m_time - = hours ( offset . hours ( ) - 11 ) ;
2017-12-12 23:01:58 -06:00
}
2017-04-20 15:58:35 -05:00
}
catch ( boost : : gregorian : : bad_year )
{
throw ( std : : invalid_argument ( " Time value is outside the supported year range. " ) ) ;
}
}
2018-01-09 15:58:25 -06:00
using PTZ = boost : : local_time : : posix_time_zone ;
static TZ_Ptr
tz_from_string ( std : : string str )
{
if ( str . empty ( ) ) return utc_zone ;
std : : string tzstr = " XXX " + str ;
if ( tzstr . length ( ) > 6 & & tzstr [ 6 ] ! = ' : ' ) //6 for XXXsHH, s is + or -
tzstr . insert ( 6 , " : " ) ;
if ( tzstr . length ( ) > 9 & & tzstr [ 9 ] ! = ' : ' ) //9 for XXXsHH:MM
{
tzstr . insert ( 9 , " : " ) ;
}
return TZ_Ptr ( new PTZ ( tzstr ) ) ;
}
2018-02-24 12:55:03 -06:00
GncDateTimeImpl : : GncDateTimeImpl ( std : : string str ) :
2015-04-28 12:06:18 -05:00
m_time ( unix_epoch , utc_zone )
{
if ( str . empty ( ) ) return ;
auto tzpos = str . find_first_of ( " +- " , str . find ( " : " ) ) ;
2018-01-09 15:58:25 -06:00
auto tzptr = tz_from_string ( tzpos ! = str . npos ? str . substr ( tzpos ) : " " ) ;
if ( tzpos ! = str . npos & & str [ tzpos - 1 ] = = ' ' ) - - tzpos ;
2015-04-28 19:53:35 -05:00
try
{
2018-02-24 12:55:03 -06:00
bool delimited = str . find ( " - " ) = = 4 ;
if ( ! delimited )
str . insert ( 8 , " T " ) ;
auto pdt = delimited ?
boost : : posix_time : : time_from_string ( str . substr ( 0 , tzpos ) ) :
boost : : posix_time : : from_iso_string ( str . substr ( 0 , tzpos ) ) ;
2015-04-28 19:53:35 -05:00
m_time = LDT ( pdt . date ( ) , pdt . time_of_day ( ) , tzptr ,
2017-12-23 16:25:15 -06:00
LDTBase : : NOT_DATE_TIME_ON_ERROR ) ;
2015-04-28 19:53:35 -05:00
}
catch ( boost : : gregorian : : bad_year )
{
throw ( std : : invalid_argument ( " The date string was outside of the supported year range. " ) ) ;
2015-04-28 12:06:18 -05:00
}
2018-01-09 15:58:25 -06:00
/* Bug 767824: A GLib bug in parsing the UTC timezone on Windows may have
* created a bogus timezone of a random number of minutes . Since there are
* no fractional - hour timezones around the prime meridian we can safely
* check for this in files by resetting to UTC if there ' s a
* less - than - an - hour offset .
*/
auto offset = tzptr - > base_utc_offset ( ) . seconds ( ) ;
if ( offset ! = 0 & & std : : abs ( offset ) < 3600 )
m_time = m_time . local_time_in ( utc_zone ) ;
2015-04-28 12:06:18 -05:00
}
2015-04-10 11:33:51 -05:00
GncDateTimeImpl : : operator time64 ( ) const
{
auto duration = m_time . utc_time ( ) - unix_epoch ;
auto secs = duration . ticks ( ) ;
secs / = ticks_per_second ;
return secs ;
2015-04-07 17:36:40 -05:00
}
2015-04-26 18:44:39 -05:00
GncDateTimeImpl : : operator struct tm ( ) const
{
2015-04-28 17:23:26 -05:00
struct tm time = to_tm ( m_time ) ;
# if HAVE_STRUCT_TM_GMTOFF
time . tm_gmtoff = offset ( ) ;
# endif
return time ;
2015-04-26 18:44:39 -05:00
}
long
GncDateTimeImpl : : offset ( ) const
{
auto offset = m_time . local_time ( ) - m_time . utc_time ( ) ;
return offset . total_seconds ( ) ;
}
2015-04-28 12:06:18 -05:00
std : : unique_ptr < GncDateImpl >
GncDateTimeImpl : : date ( ) const
{
return std : : unique_ptr < GncDateImpl > ( new GncDateImpl ( m_time . local_time ( ) . date ( ) ) ) ;
}
2015-04-26 20:01:23 -05:00
std : : string
GncDateTimeImpl : : format ( const char * format ) const
{
using Facet = boost : : local_time : : local_time_facet ;
std : : stringstream ss ;
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet ( new Facet ( format ) ) ;
ss . imbue ( std : : locale ( std : : locale ( ) , output_facet ) ) ;
ss < < m_time ;
return ss . str ( ) ;
}
2016-11-06 11:39:21 -06:00
std : : string
GncDateTimeImpl : : format_zulu ( const char * format ) const
{
using Facet = boost : : posix_time : : time_facet ;
std : : stringstream ss ;
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet ( new Facet ( format ) ) ;
ss . imbue ( std : : locale ( std : : locale ( ) , output_facet ) ) ;
ss < < m_time . utc_time ( ) ;
return ss . str ( ) ;
}
2017-04-21 09:58:20 -05:00
/* Member function definitions for GncDateImpl.
2017-04-20 14:42:24 -05:00
*/
2017-04-21 09:58:20 -05:00
GncDateImpl : : GncDateImpl ( const std : : string str , const std : : string fmt ) :
m_greg ( boost : : gregorian : : day_clock : : local_day ( ) ) /* Temporarily initialized to today, will be used and adjusted in the code below */
{
auto iter = std : : find_if ( GncDate : : c_formats . cbegin ( ) , GncDate : : c_formats . cend ( ) ,
[ & fmt ] ( const GncDateFormat & v ) { return ( v . m_fmt = = fmt ) ; } ) ;
if ( iter = = GncDate : : c_formats . cend ( ) )
throw std : : invalid_argument ( N_ ( " Unknown date format specifier passed as argument. " ) ) ;
boost : : regex r ( iter - > m_re ) ;
boost : : smatch what ;
if ( ! boost : : regex_search ( str , what , r ) ) // regex didn't find a match
throw std : : invalid_argument ( N_ ( " Value can't be parsed into a date using the selected date format. " ) ) ;
// Bail out if a year was found with a yearless format specifier
auto fmt_has_year = ( fmt . find ( ' y ' ) ! = std : : string : : npos ) ;
if ( ! fmt_has_year & & ( what . length ( " YEAR " ) ! = 0 ) )
throw std : : invalid_argument ( N_ ( " Value appears to contain a year while the selected format forbids this. " ) ) ;
int year ;
if ( fmt_has_year )
{
/* The input dates have a year, so use that one */
year = std : : stoi ( what . str ( " YEAR " ) ) ;
/* We assume two-digit years to be in the range 1969 - 2068. */
if ( year < 69 )
year + = 2000 ;
else if ( year < 100 )
year + = 1900 ;
}
else /* The input dates have no year, so use current year */
year = m_greg . year ( ) ; // Can use m_greg here as it was already initialized in the initializer list earlier
m_greg = Date ( year ,
static_cast < Month > ( std : : stoi ( what . str ( " MONTH " ) ) ) ,
std : : stoi ( what . str ( " DAY " ) ) ) ;
}
2017-04-20 14:42:24 -05:00
ymd
GncDateImpl : : year_month_day ( ) const
2015-04-07 17:36:40 -05:00
{
2017-04-20 14:42:24 -05:00
auto boost_ymd = m_greg . year_month_day ( ) ;
return { boost_ymd . year , boost_ymd . month . as_number ( ) , boost_ymd . day } ;
2015-04-07 17:36:40 -05:00
}
2015-05-04 17:03:54 -05:00
std : : string
2017-04-20 14:42:24 -05:00
GncDateImpl : : format ( const char * format ) const
2015-04-28 12:06:18 -05:00
{
2017-04-20 14:42:24 -05:00
using Facet = boost : : gregorian : : date_facet ;
std : : stringstream ss ;
//The stream destructor frees the facet, so it must be heap-allocated.
auto output_facet ( new Facet ( format ) ) ;
ss . imbue ( std : : locale ( std : : locale ( ) , output_facet ) ) ;
ss < < m_greg ;
return ss . str ( ) ;
2015-04-28 12:06:18 -05:00
}
2017-04-29 11:01:12 -05:00
bool operator < ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg < b . m_greg ; }
bool operator > ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg > b . m_greg ; }
bool operator = = ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg = = b . m_greg ; }
bool operator < = ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg < = b . m_greg ; }
bool operator > = ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg > = b . m_greg ; }
bool operator ! = ( const GncDateImpl & a , const GncDateImpl & b ) { return a . m_greg ! = b . m_greg ; }
2017-04-20 14:42:24 -05:00
/* =================== Presentation-class Implementations ====================*/
2015-05-04 17:03:54 -05:00
/* GncDateTime */
2015-03-26 19:59:06 -05:00
GncDateTime : : GncDateTime ( ) : m_impl ( new GncDateTimeImpl ) { }
2015-04-26 18:44:39 -05:00
GncDateTime : : GncDateTime ( const time64 time ) :
m_impl ( new GncDateTimeImpl ( time ) ) { }
GncDateTime : : GncDateTime ( const struct tm tm ) :
m_impl ( new GncDateTimeImpl ( tm ) ) { }
2018-02-24 12:55:03 -06:00
GncDateTime : : GncDateTime ( std : : string str ) :
2015-04-28 12:06:18 -05:00
m_impl ( new GncDateTimeImpl ( str ) ) { }
2015-03-26 19:59:06 -05:00
GncDateTime : : ~ GncDateTime ( ) = default ;
2015-04-07 17:36:40 -05:00
2017-04-20 15:58:35 -05:00
GncDateTime : : GncDateTime ( const GncDate & date , DayPart part ) :
m_impl ( new GncDateTimeImpl ( * ( date . m_impl ) , part ) ) { }
2015-04-07 17:36:40 -05:00
void
GncDateTime : : now ( )
{
m_impl - > now ( ) ;
}
2015-04-10 11:33:51 -05:00
GncDateTime : : operator time64 ( ) const
{
return m_impl - > operator time64 ( ) ;
2015-04-07 17:36:40 -05:00
}
2015-04-26 18:44:39 -05:00
GncDateTime : : operator struct tm ( ) const
{
return m_impl - > operator struct tm ( ) ;
}
long
GncDateTime : : offset ( ) const
{
return m_impl - > offset ( ) ;
}
2015-04-26 20:01:23 -05:00
2015-04-28 17:23:26 -05:00
struct tm
GncDateTime : : utc_tm ( ) const
{
return m_impl - > utc_tm ( ) ;
}
2015-04-28 12:06:18 -05:00
GncDate
GncDateTime : : date ( ) const
{
2016-04-07 17:41:15 -05:00
return GncDate ( m_impl - > date ( ) ) ;
2015-04-28 12:06:18 -05:00
}
2015-04-26 20:01:23 -05:00
std : : string
GncDateTime : : format ( const char * format ) const
{
return m_impl - > format ( format ) ;
}
2016-11-06 11:39:21 -06:00
std : : string
GncDateTime : : format_zulu ( const char * format ) const
{
return m_impl - > format_zulu ( format ) ;
}
2017-04-20 14:42:24 -05:00
/* GncDate */
GncDate : : GncDate ( ) : m_impl { new GncDateImpl } { }
GncDate : : GncDate ( int year , int month , int day ) :
m_impl ( new GncDateImpl ( year , month , day ) ) { }
2017-04-21 09:58:20 -05:00
GncDate : : GncDate ( const std : : string str , const std : : string fmt ) :
m_impl ( new GncDateImpl ( str , fmt ) ) { }
2017-04-20 14:42:24 -05:00
GncDate : : GncDate ( std : : unique_ptr < GncDateImpl > impl ) :
m_impl ( std : : move ( impl ) ) { }
2017-05-02 16:09:23 -05:00
GncDate : : GncDate ( const GncDate & a ) :
m_impl ( new GncDateImpl ( * a . m_impl ) ) { }
2017-04-20 14:42:24 -05:00
GncDate : : GncDate ( GncDate & & ) = default ;
GncDate : : ~ GncDate ( ) = default ;
2017-05-02 16:09:23 -05:00
GncDate &
GncDate : : operator = ( const GncDate & a )
{
m_impl . reset ( new GncDateImpl ( * a . m_impl ) ) ;
return * this ;
}
2017-04-20 14:42:24 -05:00
GncDate &
GncDate : : operator = ( GncDate & & ) = default ;
void
GncDate : : today ( )
{
m_impl - > today ( ) ;
}
std : : string
GncDate : : format ( const char * format )
{
return m_impl - > format ( format ) ;
}
ymd
GncDate : : year_month_day ( ) const
{
return m_impl - > year_month_day ( ) ;
}
2017-04-29 11:01:12 -05:00
bool operator < ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) < * ( b . m_impl ) ; }
bool operator > ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) > * ( b . m_impl ) ; }
bool operator = = ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) = = * ( b . m_impl ) ; }
bool operator < = ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) < = * ( b . m_impl ) ; }
bool operator > = ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) > = * ( b . m_impl ) ; }
bool operator ! = ( const GncDate & a , const GncDate & b ) { return * ( a . m_impl ) ! = * ( b . m_impl ) ; }