|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r49893 - in branches/release: boost/date_time boost/date_time/gregorian libs/date_time/src/gregorian libs/date_time/test/gregorian libs/date_time/test/posix_time libs/date_time/xmldoc
From: andrey.semashev_at_[hidden]
Date: 2008-11-23 06:13:36
Author: andysem
Date: 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
New Revision: 49893
URL: http://svn.boost.org/trac/boost/changeset/49893
Log:
Merged fixes from trunk: tickets 2521, 2523.
Text files modified:
branches/release/boost/date_time/date_parsing.hpp | 15 ++--
branches/release/boost/date_time/filetime_functions.hpp | 112 ++++++++++++++++++++++-----------------
branches/release/boost/date_time/gregorian/greg_facet.hpp | 14 +++-
branches/release/boost/date_time/microsec_time_clock.hpp | 9 +-
branches/release/boost/date_time/time_facet.hpp | 4
branches/release/libs/date_time/src/gregorian/greg_month.cpp | 2
branches/release/libs/date_time/test/gregorian/testdate_input_facet.cpp | 6 ++
branches/release/libs/date_time/test/posix_time/testfiletime_functions.cpp | 62 ++++++++++++++++-----
branches/release/libs/date_time/test/posix_time/testtime_facet.cpp | 26 +++++++++
branches/release/libs/date_time/xmldoc/changes.xml | 20 ++++++
10 files changed, 186 insertions(+), 84 deletions(-)
Modified: branches/release/boost/date_time/date_parsing.hpp
==============================================================================
--- branches/release/boost/date_time/date_parsing.hpp (original)
+++ branches/release/boost/date_time/date_parsing.hpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -74,22 +74,23 @@
}
//! Find index of a string in either of 2 arrays
- /*! find_match searches both arrays for a match to 's'. Indexing of the
- * arrays is from 0 to 'limit'. The index of the match is returned.
+ /*! find_match searches both arrays for a match to 's'. Both arrays
+ * must contain 'size' elements. The index of the match is returned.
+ * If no match is found, 'size' is returned.
* Ex. "Jan" returns 0, "Dec" returns 11, "Tue" returns 2.
- * 'limit' can be sent in with: greg_month::max(),
- * greg_weekday::max() or date_time::NumSpecialValues */
+ * 'size' can be sent in with: greg_month::max() (which 12),
+ * greg_weekday::max() + 1 (which is 7) or date_time::NumSpecialValues */
template<class charT>
short find_match(const charT* const* short_names,
const charT* const* long_names,
- short limit,
+ short size,
const std::basic_string<charT>& s) {
- for(short i = 0; i <= limit; ++i){
+ for(short i = 0; i < size; ++i){
if(short_names[i] == s || long_names[i] == s){
return i;
}
}
- return static_cast<short>(limit + 1); // not-found, return a value out of range
+ return size; // not-found, return a value out of range
}
//! Generic function to parse a delimited date (eg: 2002-02-10)
Modified: branches/release/boost/date_time/filetime_functions.hpp
==============================================================================
--- branches/release/boost/date_time/filetime_functions.hpp (original)
+++ branches/release/boost/date_time/filetime_functions.hpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -27,37 +27,38 @@
#include <boost/date_time/time.hpp>
namespace boost {
+
namespace date_time {
namespace winapi {
#if !defined(BOOST_USE_WINDOWS_H)
-extern "C" {
+ extern "C" {
- struct FILETIME
- {
- boost::uint32_t dwLowDateTime;
- boost::uint32_t dwHighDateTime;
- };
- struct SYSTEMTIME
- {
- boost::uint16_t wYear;
- boost::uint16_t wMonth;
- boost::uint16_t wDayOfWeek;
- boost::uint16_t wDay;
- boost::uint16_t wHour;
- boost::uint16_t wMinute;
- boost::uint16_t wSecond;
- boost::uint16_t wMilliseconds;
- };
-
- __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(FILETIME* lpFileTime);
- __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const FILETIME* lpFileTime, FILETIME* lpLocalFileTime);
- __declspec(dllimport) void __stdcall GetSystemTime(SYSTEMTIME* lpSystemTime);
- __declspec(dllimport) int __stdcall SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, FILETIME* lpFileTime);
+ struct FILETIME
+ {
+ boost::uint32_t dwLowDateTime;
+ boost::uint32_t dwHighDateTime;
+ };
+ struct SYSTEMTIME
+ {
+ boost::uint16_t wYear;
+ boost::uint16_t wMonth;
+ boost::uint16_t wDayOfWeek;
+ boost::uint16_t wDay;
+ boost::uint16_t wHour;
+ boost::uint16_t wMinute;
+ boost::uint16_t wSecond;
+ boost::uint16_t wMilliseconds;
+ };
+
+ __declspec(dllimport) void __stdcall GetSystemTimeAsFileTime(FILETIME* lpFileTime);
+ __declspec(dllimport) int __stdcall FileTimeToLocalFileTime(const FILETIME* lpFileTime, FILETIME* lpLocalFileTime);
+ __declspec(dllimport) void __stdcall GetSystemTime(SYSTEMTIME* lpSystemTime);
+ __declspec(dllimport) int __stdcall SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, FILETIME* lpFileTime);
-} // extern "C"
+ } // extern "C"
#endif // defined(BOOST_USE_WINDOWS_H)
@@ -81,16 +82,18 @@
}
/*!
- * The function converts file_time into number of nanoseconds elapsed since 1970-Jan-01
+ * The function converts file_time into number of microseconds elapsed since 1970-Jan-01
+ *
+ * \note Only dates after 1970-Jan-01 are supported. Dates before will be wrapped.
*
* \note The function is templated on the FILETIME type, so that
* it can be used with both native FILETIME and the ad-hoc
* boost::date_time::winapi::file_time type.
*/
template< typename FileTimeT >
- inline boost::uint64_t file_time_to_nanoseconds(FileTimeT const& ft)
+ inline boost::uint64_t file_time_to_microseconds(FileTimeT const& ft)
{
- /* shift is difference between 1970-Jan-01 & 1601-Jan-01
+ /* shift is difference between 1970-Jan-01 & 1601-Jan-01
* in 100-nanosecond intervals */
const uint64_t c1 = 27111902UL;
const uint64_t c2 = 3577643008UL; // issues warning without 'UL'
@@ -98,41 +101,52 @@
union {
FileTimeT as_file_time;
- uint64_t as_integer;
+ uint64_t as_integer; // 100-nanos since 1601-Jan-01
} caster;
caster.as_file_time = ft;
caster.as_integer -= shift; // filetime is now 100-nanos since 1970-Jan-01
- return (caster.as_integer * 100); // upscale to nanoseconds
+ return (caster.as_integer / 10); // truncate to microseconds
}
} // namespace winapi
- //! Create a time object from an initialized FILETIME struct.
- /*!
- * Create a time object from an initialized FILETIME struct.
- * A FILETIME struct holds 100-nanosecond units (0.0000001). When
- * built with microsecond resolution the file_time's sub second value
- * will be truncated. Nanosecond resolution has no truncation.
- *
- * \note The function is templated on the FILETIME type, so that
- * it can be used with both native FILETIME and the ad-hoc
- * boost::date_time::winapi::file_time type.
- */
- template< typename TimeT, typename FileTimeT >
- inline
- TimeT time_from_ftime(const FileTimeT& ft)
- {
+//! Create a time object from an initialized FILETIME struct.
+/*!
+ * Create a time object from an initialized FILETIME struct.
+ * A FILETIME struct holds 100-nanosecond units (0.0000001). When
+ * built with microsecond resolution the file_time's sub second value
+ * will be truncated. Nanosecond resolution has no truncation.
+ *
+ * \note The function is templated on the FILETIME type, so that
+ * it can be used with both native FILETIME and the ad-hoc
+ * boost::date_time::winapi::file_time type.
+ */
+template< typename TimeT, typename FileTimeT >
+inline
+TimeT time_from_ftime(const FileTimeT& ft)
+{
typedef typename TimeT::date_type date_type;
typedef typename TimeT::date_duration_type date_duration_type;
typedef typename TimeT::time_duration_type time_duration_type;
- uint64_t nanos = winapi::file_time_to_nanoseconds(ft);
+ // https://svn.boost.org/trac/boost/ticket/2523
+ // Since this function can be called with arbitrary times, including ones that
+ // are before 1970-Jan-01, we'll have to cast the time a bit differently,
+ // than it is done in the file_time_to_microseconds function. This allows to
+ // avoid integer wrapping for dates before 1970-Jan-01.
+ union {
+ FileTimeT as_file_time;
+ uint64_t as_integer; // 100-nanos since 1601-Jan-01
+ } caster;
+ caster.as_file_time = ft;
- uint64_t sec = nanos / 1000000000UL;
- uint32_t sub_sec = (nanos % 1000000000UL); // nanoseconds since the last second
+ uint64_t sec = caster.as_integer / 10000000UL;
+ uint32_t sub_sec = (caster.as_integer % 10000000UL) // 100-nanoseconds since the last second
#if !defined(BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG)
- sub_sec /= 1000; // truncate to microseconds
+ / 10; // microseconds since the last second
+#else
+ * 100; // nanoseconds since the last second
#endif
// split sec into usable chunks: days, hours, minutes, & seconds
@@ -146,9 +160,9 @@
uint32_t seconds = tmp; // seconds
date_duration_type dd(days);
- date_type d = date_type(1970, Jan, 01) + dd;
+ date_type d = date_type(1601, Jan, 01) + dd;
return TimeT(d, time_duration_type(hours, minutes, seconds, sub_sec));
- }
+}
}} // boost::date_time
Modified: branches/release/boost/date_time/gregorian/greg_facet.hpp
==============================================================================
--- branches/release/boost/date_time/gregorian/greg_facet.hpp (original)
+++ branches/release/boost/date_time/gregorian/greg_facet.hpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -284,7 +284,8 @@
const facet_def& f = std::use_facet<facet_def>(is.getloc());
num = date_time::find_match(f.get_short_month_names(),
f.get_long_month_names(),
- (greg_month::max)(), s);
+ (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size,
+ // which is needed by find_match
}
/* bad_cast will be thrown if the desired facet is not accessible
* so we can generate the facet. This has the drawback of using english
@@ -294,10 +295,11 @@
std::auto_ptr< const facet_def > f(create_facet_def(a));
num = date_time::find_match(f->get_short_month_names(),
f->get_long_month_names(),
- (greg_month::max)(), s);
+ (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size,
+ // which is needed by find_match
}
- num += 1; // months numbered 1-12
+ ++num; // months numbered 1-12
m = greg_month(num);
return is;
@@ -324,7 +326,8 @@
const facet_def& f = std::use_facet<facet_def>(is.getloc());
num = date_time::find_match(f.get_short_weekday_names(),
f.get_long_weekday_names(),
- (greg_weekday::max)(), s);
+ (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed
+ // to form the array size which is needed by find_match
}
/* bad_cast will be thrown if the desired facet is not accessible
* so we can generate the facet. This has the drawback of using english
@@ -334,7 +337,8 @@
std::auto_ptr< const facet_def > f(create_facet_def(a));
num = date_time::find_match(f->get_short_weekday_names(),
f->get_long_weekday_names(),
- (greg_weekday::max)(), s);
+ (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed
+ // to form the array size which is needed by find_match
}
wd = greg_weekday(num); // weekdays numbered 0-6
Modified: branches/release/boost/date_time/microsec_time_clock.hpp
==============================================================================
--- branches/release/boost/date_time/microsec_time_clock.hpp (original)
+++ branches/release/boost/date_time/microsec_time_clock.hpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -87,10 +87,11 @@
#elif defined(BOOST_HAS_FTIME)
winapi::file_time ft;
winapi::get_system_time_as_file_time(ft);
- uint64_t nanos = winapi::file_time_to_nanoseconds(ft);
- std::time_t t = static_cast<time_t>(nanos / 1000000000UL); // seconds since epoch
+ uint64_t micros = winapi::file_time_to_microseconds(ft); // it will not wrap, since ft is the current time
+ // and cannot be before 1970-Jan-01
+ std::time_t t = static_cast<time_t>(micros / 1000000UL); // seconds since epoch
// microseconds -- static casts supress warnings
- boost::uint32_t sub_sec = static_cast<boost::uint32_t>((nanos % 1000000000UL) / 1000UL);
+ boost::uint32_t sub_sec = static_cast<boost::uint32_t>(micros % 1000000UL);
#else
#error Internal Boost.DateTime error: BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK is defined, however neither gettimeofday nor FILETIME support is detected.
#endif
@@ -101,7 +102,7 @@
curr_ptr->tm_mon + 1,
curr_ptr->tm_mday);
- //The following line will adjusts the fractional second tick in terms
+ //The following line will adjust the fractional second tick in terms
//of the current time system. For example, if the time system
//doesn't support fractional seconds then res_adjust returns 0
//and all the fractional seconds return 0.
Modified: branches/release/boost/date_time/time_facet.hpp
==============================================================================
--- branches/release/boost/date_time/time_facet.hpp (original)
+++ branches/release/boost/date_time/time_facet.hpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -18,6 +18,7 @@
#include <iomanip>
#include <iterator> // i/ostreambuf_iterator
#include <exception>
+#include <boost/assert.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/throw_exception.hpp>
#include <boost/algorithm/string/erase.hpp>
@@ -445,8 +446,7 @@
if (format.find(hours_format) != string_type::npos) {
if (hours_str.empty())
hours_str = hours_as_string(a_time_dur);
- if (hours_str.length() > 2)
- hours_str.erase(0, hours_str.length() - 2);
+ BOOST_ASSERT(hours_str.length() <= 2);
boost::algorithm::replace_all(format, hours_format, hours_str);
}
Modified: branches/release/libs/date_time/src/gregorian/greg_month.cpp
==============================================================================
--- branches/release/libs/date_time/src/gregorian/greg_month.cpp (original)
+++ branches/release/libs/date_time/src/gregorian/greg_month.cpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -75,7 +75,7 @@
special_value_names,
date_time::NumSpecialValues,
s);
- if(i > date_time::NumSpecialValues) { // match not found
+ if(i >= date_time::NumSpecialValues) { // match not found
return not_special;
}
else {
Modified: branches/release/libs/date_time/test/gregorian/testdate_input_facet.cpp
==============================================================================
--- branches/release/libs/date_time/test/gregorian/testdate_input_facet.cpp (original)
+++ branches/release/libs/date_time/test/gregorian/testdate_input_facet.cpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -399,6 +399,12 @@
check("Special values, default strings, not_a_date_time date",
d == date(not_a_date_time));
+ // in addition check that special_value_from_string also works correctly for other special values
+ check("Special values, default strings, not_special test",
+ special_value_from_string("not_special") == not_special);
+ check("Special values, default strings, junk test",
+ special_value_from_string("junk") == not_special);
+
// special values custom, strings
special_values_parser svp("NADT", "MINF", "INF", "MINDT", "MAXDT");
facet->special_values_parser(svp);
Modified: branches/release/libs/date_time/test/posix_time/testfiletime_functions.cpp
==============================================================================
--- branches/release/libs/date_time/test/posix_time/testfiletime_functions.cpp (original)
+++ branches/release/libs/date_time/test/posix_time/testfiletime_functions.cpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -14,6 +14,17 @@
#include <windows.h>
#endif
+template< typename T, typename U >
+inline bool check_equal(const std::string& testname, T const& left, U const& right)
+{
+ bool res = check(testname, left == right);
+ if (!res)
+ {
+ std::cout << " left = " << left << ", right = " << right << std::endl;
+ }
+ return res;
+}
+
int main()
{
#if defined(BOOST_HAS_FTIME) // skip tests if no FILETIME
@@ -33,21 +44,20 @@
ptime pt = from_ftime<ptime>(ft);
- check("ptime year matches systemtime year",
- st.wYear == pt.date().year());
- check("ptime month matches systemtime month",
- st.wMonth == pt.date().month());
- check("ptime day matches systemtime day",
- st.wDay == pt.date().day());
- check("ptime hour matches systemtime hour",
- st.wHour == pt.time_of_day().hours());
- check("ptime minute matches systemtime minute",
- st.wMinute == pt.time_of_day().minutes());
- check("ptime second matches systemtime second",
- st.wSecond == pt.time_of_day().seconds());
- check("truncated ptime fractional second matches systemtime millisecond",
- st.wMilliseconds == (pt.time_of_day().fractional_seconds() / adjustor)
- );
+ check_equal("ptime year matches systemtime year",
+ st.wYear, pt.date().year());
+ check_equal("ptime month matches systemtime month",
+ st.wMonth, pt.date().month());
+ check_equal("ptime day matches systemtime day",
+ st.wDay, pt.date().day());
+ check_equal("ptime hour matches systemtime hour",
+ st.wHour, pt.time_of_day().hours());
+ check_equal("ptime minute matches systemtime minute",
+ st.wMinute, pt.time_of_day().minutes());
+ check_equal("ptime second matches systemtime second",
+ st.wSecond, pt.time_of_day().seconds());
+ check_equal("truncated ptime fractional second matches systemtime millisecond",
+ st.wMilliseconds, (pt.time_of_day().fractional_seconds() / adjustor));
// burn up a little time
for (int j=0; j<100000; j++)
@@ -58,6 +68,28 @@
} // for loop
+ // check that time_from_ftime works for pre-1970-Jan-01 dates, too
+ // zero FILETIME should represent 1601-Jan-01 00:00:00.000
+ FILETIME big_bang_by_ms;
+ big_bang_by_ms.dwLowDateTime = big_bang_by_ms.dwHighDateTime = 0;
+ ptime pt = from_ftime<ptime>(big_bang_by_ms);
+
+ check_equal("big bang ptime year matches 1601",
+ 1601, pt.date().year());
+ check_equal("big bang ptime month matches Jan",
+ 1, pt.date().month());
+ check_equal("big bang ptime day matches 1",
+ 1, pt.date().day());
+ check_equal("big bang ptime hour matches 0",
+ 0, pt.time_of_day().hours());
+ check_equal("big bang ptime minute matches 0",
+ 0, pt.time_of_day().minutes());
+ check_equal("big bang ptime second matches 0",
+ 0, pt.time_of_day().seconds());
+ check_equal("big bang truncated ptime fractional second matches 0",
+ 0, (pt.time_of_day().fractional_seconds() / adjustor));
+
+
#else // BOOST_HAS_FTIME
// we don't want a forced failure here, not a shortcoming
check("FILETIME not available for this compiler/platform", true);
Modified: branches/release/libs/date_time/test/posix_time/testtime_facet.cpp
==============================================================================
--- branches/release/libs/date_time/test/posix_time/testtime_facet.cpp (original)
+++ branches/release/libs/date_time/test/posix_time/testtime_facet.cpp 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -54,6 +54,8 @@
ptime tf = t + microseconds(3);
time_period tp(t, tf + days(7) + time_duration(1,1,1));
time_duration td = hours(3) + minutes(2) + seconds(1) + milliseconds(9);
+ time_duration longer_td = hours(10) + minutes(22) + seconds(15) + milliseconds(980); // two characters in hours
+ time_duration long_td = hours(300) + minutes(2) + seconds(1) + milliseconds(9); // more than two characters in hours
{
std::stringstream ss;
ss << t;
@@ -94,6 +96,18 @@
ss << td;
check("Multiple literal '%'s in time_duration format", ss.str() == std::string("03:02:01 %01"));
ss.str("");
+
+ // Longer time durations
+ f->time_duration_format("%H:%M:%S");
+ ss << longer_td;
+ check("Longer time durations", ss.str() == std::string("10:22:15"));
+ ss.str("");
+
+ // Long time durations
+ f->time_duration_format("%O:%M:%S");
+ ss << long_td;
+ check("Long time durations", ss.str() == std::string("300:02:01"));
+ ss.str("");
}
{ // negative time_duration tests
std::string result;
@@ -168,7 +182,19 @@
ss << td4 - td3;
result = "-00 hours and -01 minutes";
check("Negative time_duration two sign flags" + ss.str(), result == ss.str());
+ ss.str("");
+
+ // Longer time durations
+ f->time_duration_format("%-%H:%M:%S");
+ ss << -longer_td;
+ check("Longer negative time durations", ss.str() == std::string("-10:22:15"));
+ ss.str("");
+ // Long time durations
+ f->time_duration_format("%-%O:%M:%S");
+ ss << -long_td;
+ check("Long negative time durations", ss.str() == std::string("-300:02:01"));
+ ss.str("");
}
#if !defined(BOOST_NO_STD_WSTRING)
Modified: branches/release/libs/date_time/xmldoc/changes.xml
==============================================================================
--- branches/release/libs/date_time/xmldoc/changes.xml (original)
+++ branches/release/libs/date_time/xmldoc/changes.xml 2008-11-23 06:13:35 EST (Sun, 23 Nov 2008)
@@ -29,7 +29,9 @@
A new formatter <code>%O</code> is used indicate such long durations in the
format string. The old <code>%H</code> format specifier is thus restricted
to represent durations that fit into two characters, in order to retain support
- for reading durations in ISO format.
+ for reading durations in ISO format. In case if it is detected that the <code>%H</code>
+ format specifier is used with longer durations, the results are not specified
+ (an assertion in debug builds is raised).
</entry>
</row>
@@ -93,6 +95,22 @@
</row>
<row>
+ <entry>Bug fix</entry>
+ <entry>
+ On Windows platform function <code>from_ftime</code> could return incorrect time if
+ the <code>FILETIME</code> that is being passed to the function contained dates before 1970-Jan-01.
+ </entry>
+ </row>
+
+ <row>
+ <entry>Bug fix</entry>
+ <entry>
+ Fixed a possible crash in <code>gregorian::special_value_from_string</code> if the string
+ did not represent a valid special value.
+ </entry>
+ </row>
+
+ <row>
<entry>Bug Fix</entry>
<entry>
</entry>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk