/* * Copyright (c) 2007 Tradescape Inc. All rights reserved. * @author lothar */ #include #include #include #include #include #include "boost/version.hpp" #include "boost/date_time/gregorian/gregorian.hpp" #include "boost/date_time/posix_time/posix_time.hpp" #include "boost/date_time/local_time/local_time.hpp" #include "cppunit/extensions/HelperMacros.h" #ifndef HIDE_BOOST_DATETIME_BUGS #if BOOST_VERSION <= 103400 #define HIDE_BOOST_DATETIME_BUGS true #else #define HIDE_BOOST_DATETIME_BUGS false #endif #endif namespace boost { /** Converts a std::wstring into a std::string with iso8859_1 encoding. * This method uses the fact that iso8859-1 is the same as the * low byte of UFT-16 or UTF-32 */ template < typename StringT > StringT iso8859_1 ( std::wstring const & rc_string ) { StringT result; typename StringT::value_type mask = ~0; result.reserve(rc_string.size()); for(typename StringT::size_type cnt = 0, max = rc_string.size(); cnt < max; ++cnt) { result.push_back(mask & rc_string[cnt]); } return result; } /** Converts a std::String with iso8859_1 encoding into a std::wstring. * This method uses the fact that iso8859-1 is the same as the * low byte of UFT-16 or UTF-32 */ template < typename StringT > StringT iso8859_1 ( std::string const & rc_string ) { StringT result; typename StringT::value_type mask = ~0; result.resize(rc_string.size()); for(typename StringT::size_type cnt = 0, max = rc_string.size(); cnt < max; ++cnt) { result.push_back(mask & rc_string[cnt]); } return result; } /** Nop specialization for std::string. */ template < > inline std::string iso8859_1 ( std::string const & rc_string ) { return rc_string; } /** Nop specialization for std::wstring. */ template < > inline std::wstring iso8859_1 ( std::wstring const & rc_string ) { return rc_string; } // boost::local_time does not (yet) support reading timezones, so do it manually template < class charT, class traits > void manualIsoTimezoneFix( std::basic_istream < charT, traits > & r_istream, boost::local_time::local_date_time & r_ldt ) { if(!r_ldt.zone().get()) { boost::local_time::time_zone_ptr zone; std::basic_string < charT, traits> tzsT; // try to read timezone string r_istream >> std::ws >> tzsT; if (!r_istream.fail()) { std::string tzs = iso8859_1< std::string >(std::basic_string < charT, traits >(tzsT)); // try to find timezone zone = boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone(tzs) ); r_ldt = r_ldt.local_time_in(zone); r_ldt -= zone->base_utc_offset(); } } } class BoostDateTimeTest : public CppUnit::TestFixture { private: public: void setUp ( ) { } void tearDown ( ) { } void testCreate() { std::stringstream ss; // switch locale to output ISO format boost::local_time::local_time_facet* output_facet = new boost::local_time::local_time_facet(); output_facet->format( boost::local_time::local_time_facet::iso_time_format_extended_specifier ); ss.imbue(std::locale(std::locale("C"), output_facet)); boost::posix_time::ptime pt( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 18, 25, 17 ) ); boost::local_time::time_zone_ptr zone( new boost::local_time::posix_time_zone("+01:00") ); boost::local_time::local_date_time ldt( pt, zone ); CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(18), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); ss.str(""); ss.clear(); ss << ldt; //@? lw: do we really expect "2005-09-30 19:25:17+01:00" instead of "2005-09-30 18:25:17+01:00" CPPUNIT_ASSERT_EQUAL(std::string("2005-09-30 19:25:17+01:00"), ss.str()); pt = boost::posix_time::ptime( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 11, 22, 17 ) ); zone = boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("-08:03") ); ldt = boost::local_time::local_date_time( pt, zone ); CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(11), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(22), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(-8), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(-3), ldt.zone()->base_utc_offset().minutes()); ss.str(""); ss.clear(); ss << ldt; //@? lw: do we really expect "2005-09-30 03:19:17-08:03" instead of "2005-09-30 11:22:17-08:03" CPPUNIT_ASSERT_EQUAL(std::string("2005-09-30 03:19:17-08:03"), ss.str()); } void testInput() { std::stringstream ss; boost::local_time::time_zone_ptr zone; boost::local_time::local_date_time ndt( boost::posix_time::not_a_date_time, zone ); boost::local_time::local_date_time ldt( boost::posix_time::not_a_date_time, zone ); ldt = ndt; ss.str("2005-Sep-30 19:25:17 CET+01:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(18), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); ldt = ndt; ss.str("2005-Sep-30 19:25:17 PST-08:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(10), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(3), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(-8), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); } void testOutput() { std::stringstream ss; //@? lw: should it not be "2005-Sep-30 19:25:17 CET+01:00" ? std::string str("2005-Sep-30 19:25:17 CET"); boost::local_time::local_date_time ldt( boost::posix_time::ptime( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 18, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("CET+01:00") ) ); ss.str(""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL(str, ss.str()); //@? lw: should it not be "2005-Sep-30 19:25:17 PST-08:00" ? str = "2005-Sep-30 19:25:17 PST"; ldt = boost::local_time::local_date_time( boost::posix_time::ptime( boost::gregorian::date( 2005, 10, 1 ), boost::posix_time::time_duration( 3, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("PST-08:00") ) ); ss.str(""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL(str, ss.str()); } void testInputIso() { std::stringstream ss; // switch locale to read ISO format boost::local_time::local_time_input_facet* input_facet = new boost::local_time::local_time_input_facet(); input_facet->set_iso_extended_format(); ss.imbue(std::locale(std::locale("C"), input_facet)); boost::local_time::time_zone_ptr zone; boost::local_time::local_date_time ndt( boost::posix_time::not_a_date_time, zone ); boost::local_time::local_date_time ldt( boost::posix_time::not_a_date_time, zone ); ldt = ndt; ss.str("2005-09-30 19:25:17+01:00"); ss.clear(); ss >> ldt; //@! lw: bug in boost::date_time #if HIDE_BOOST_DATETIME_BUGS manualIsoTimezoneFix(ss, ldt); #endif CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(18), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT(0 != ldt.zone().get()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); ldt = ndt; ss.str("2005-09-30 19:25:17-08:00"); ss.clear(); ss >> ldt; //@! lw: bug in boost::date_time #if HIDE_BOOST_DATETIME_BUGS manualIsoTimezoneFix(ss, ldt); #endif CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(10), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(3), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT(0 != ldt.zone().get()); CPPUNIT_ASSERT_EQUAL(static_cast(-8), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); } void testOutputIso() { std::stringstream ss; // switch locale to output ISO format boost::local_time::local_time_facet* output_facet = new boost::local_time::local_time_facet(); output_facet->format( boost::local_time::local_time_facet::iso_time_format_extended_specifier ); ss.imbue(std::locale(std::locale("C"), output_facet)); std::string str("2005-09-30 19:25:17+01:00"); boost::local_time::local_date_time ldt( boost::posix_time::ptime( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 18, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("CET+01:00") ) ); ss.str(""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL(str, ss.str()); str = "2005-09-30 19:25:17-08:00"; ldt = boost::local_time::local_date_time( boost::posix_time::ptime( boost::gregorian::date( 2005, 10, 1 ), boost::posix_time::time_duration( 3, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("PST-08:00") ) ); ss.str(""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL(str, ss.str()); } void testInputWide() { std::wstringstream ss; boost::local_time::time_zone_ptr zone; boost::local_time::local_date_time ndt( boost::posix_time::not_a_date_time, zone ); boost::local_time::local_date_time ldt( boost::posix_time::not_a_date_time, zone ); ldt = ndt; ss.str(L"2005-Sep-30 19:25:17 CET+01:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(18), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); ldt = ndt; ss.str(L"2005-Sep-30 19:25:17 PST-08:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(10), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(3), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT_EQUAL(static_cast(-8), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); } void testOutputWide() { std::wstringstream ss; std::wstring str(L"2005-Sep-30 19:25:17 CET"); boost::local_time::local_date_time ldt( boost::posix_time::ptime( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 18, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("CET+01:00") ) ); ss.str(L""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL( iso8859_1(str), iso8859_1(ss.str()) ); str = L"2005-Sep-30 19:25:17 PST"; ldt = boost::local_time::local_date_time( boost::posix_time::ptime( boost::gregorian::date( 2005, 10, 1 ), boost::posix_time::time_duration( 3, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("PST-08:00") ) ); ss.str(L""); ss.clear(); ss << ldt; CPPUNIT_ASSERT_EQUAL( iso8859_1(str), iso8859_1(ss.str()) ); } void testInputIsoWide() { //@! lw: bug in boost::date_time #if HIDE_BOOST_DATETIME_BUGS // boost::date_time can not parse from wstream correctly in ISO format return; #endif std::wstringstream ss; // switch locale to read ISO format boost::local_time::local_time_input_facet* input_facet = new boost::local_time::local_time_input_facet(); input_facet->set_iso_extended_format(); ss.imbue(std::locale(std::locale("C"), input_facet)); boost::local_time::time_zone_ptr zone; boost::local_time::local_date_time ndt( boost::posix_time::not_a_date_time, zone ); boost::local_time::local_date_time ldt( boost::posix_time::not_a_date_time, zone ); ldt = ndt; ss.str(L"2005-09-30 19:25:17+01:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(19), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT(0 != ldt.zone().get()); CPPUNIT_ASSERT_EQUAL(static_cast(1), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); ldt = ndt; ss.str(L"2005-09-30 19:25:17-08:00"); ss.clear(); ss >> ldt; CPPUNIT_ASSERT_EQUAL(static_cast(2005), ldt.date().year()); CPPUNIT_ASSERT_EQUAL(static_cast(9), ldt.date().month()); CPPUNIT_ASSERT_EQUAL(static_cast(30), ldt.date().day()); CPPUNIT_ASSERT_EQUAL(static_cast(19), ldt.utc_time().time_of_day().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(25), ldt.utc_time().time_of_day().minutes()); CPPUNIT_ASSERT_EQUAL(static_cast(17), ldt.utc_time().time_of_day().seconds()); CPPUNIT_ASSERT(0 != ldt.zone().get()); CPPUNIT_ASSERT_EQUAL(static_cast(-8), ldt.zone()->base_utc_offset().hours()); CPPUNIT_ASSERT_EQUAL(static_cast(0), ldt.zone()->base_utc_offset().minutes()); } void testOutputIsoWide() { std::wstringstream ss; // switch locale to output ISO format boost::local_time::local_time_facet* output_facet = new boost::local_time::local_time_facet(); output_facet->format( boost::local_time::local_time_facet::iso_time_format_extended_specifier ); ss.imbue(std::locale(std::locale("C"), output_facet)); std::wstring str(L"2005-09-30 19:25:17+01:00"); boost::local_time::local_date_time ldt( boost::posix_time::ptime( boost::gregorian::date( 2005, 9, 30 ), boost::posix_time::time_duration( 18, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("CET+01:00") ) ); ss.str(L""); ss.clear(); ss << ldt; //@! lw: bug in boost::date_time #if HIDE_BOOST_DATETIME_BUGS CPPUNIT_ASSERT_EQUAL( std::string("2005-Sep-30 19:25:17 CET"), iso8859_1(ss.str()) ); #else CPPUNIT_ASSERT_EQUAL( iso8859_1(str), iso8859_1(ss.str()) ); #endif str = L"2005-09-30 19:25:17-08:00"; ldt = boost::local_time::local_date_time( boost::posix_time::ptime( boost::gregorian::date( 2005, 10, 1 ), boost::posix_time::time_duration( 3, 25, 17 ) ), boost::local_time::time_zone_ptr( new boost::local_time::posix_time_zone("PST-08:00") ) ); ss.str(L""); ss.clear(); ss << ldt; //@! lw: bug in boost::date_time #if HIDE_BOOST_DATETIME_BUGS CPPUNIT_ASSERT_EQUAL( std::string("2005-Sep-30 19:25:17 PST"), iso8859_1(ss.str()) ); #else CPPUNIT_ASSERT_EQUAL( iso8859_1(str), iso8859_1(ss.str()) ); #endif } CPPUNIT_TEST_SUITE(BoostDateTimeTest); CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testInput); CPPUNIT_TEST(testOutput); CPPUNIT_TEST(testInputIso); CPPUNIT_TEST(testOutputIso); CPPUNIT_TEST(testInputWide); CPPUNIT_TEST(testOutputWide); CPPUNIT_TEST(testInputIsoWide); CPPUNIT_TEST(testOutputIsoWide); CPPUNIT_TEST_SUITE_END(); }; CPPUNIT_TEST_SUITE_REGISTRATION(BoostDateTimeTest); } /* end of namespace boost */