id summary reporter owner description type status milestone component version severity resolution keywords cc 13159 Assert hit in wcsftime.cpp on MSVC due to tm_year out of range dstftw@… James E. King, III " The issue is only reproducible on MSVC (toolsets tested v120, v140, v141) and caused by a limitation imposed on `tm_year` of `tm` to belong to the range `[-1900; 8099]` (see assert below). Here is the sample code that reproduces the problem: {{{ #include ""stdafx.h"" #include #include int main() { std::ostringstream os; os.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_facet(""%Y""))); os << boost::posix_time::ptime(boost::gregorian::date(10000, 1, 1)); return 0; } }}} Stack trace: {{{ ucrtbased.dll!expand_time(__crt_locale_pointers * locale, wchar_t specifier, const tm * timeptr, wchar_t * * string, unsigned __int64 * left, const __crt_lc_time_data * lc_time, bool alternate_form) Line 971 C++ ucrtbased.dll!_Wcsftime_l(wchar_t * string, unsigned __int64 max_size, const wchar_t * format, const tm * timeptr, void * lc_time_arg, __crt_locale_pointers * locale) Line 1134 C++ ucrtbased.dll!_Strftime_l(char * const string, const unsigned __int64 maxsize, const char * const format, const tm * const timeptr, void * const lc_time_arg, __crt_locale_pointers * const locale) Line 169 C++ ucrtbased.dll!_Strftime(char * string, unsigned __int64 max_size, const char * format, const tm * timeptr, void * lc_time_arg) Line 197 C++ > msvcp140d.dll!std::time_put > >::do_put(std::ostreambuf_iterator > _Dest, std::ios_base & __formal, char __formal, const tm * _Pt, char _Specifier, char _Modifier) Line 799 C++ msvcp140d.dll!std::time_put > >::put(std::ostreambuf_iterator > _Dest, std::ios_base & _Iosbase, char _Fill, const tm * _Pt, const char * _Fmtfirst, const char * _Fmtlast) Line 732 C++ DateTimePlayground.exe!boost::date_time::date_facet > >::do_put_tm(std::ostreambuf_iterator > next, std::ios_base & a_ios, char fill_char, const tm & tm_value, std::basic_string,std::allocator > a_format) Line 342 C++ DateTimePlayground.exe!boost::date_time::time_facet > >::put(std::ostreambuf_iterator > next_arg, std::ios_base & ios_arg, char fill_arg, const boost::posix_time::ptime & time_arg) Line 427 C++ DateTimePlayground.exe!boost::posix_time::operator<< >(std::basic_ostream > & os, const boost::posix_time::ptime & p) Line 52 C++ DateTimePlayground.exe!main() Line 11 C++ [External Code] }}} Assert: {{{ Debug Assertion Failed! Program: ...\Projects\DateTimePlayground\x64\Debug\DateTimePlayground.exe File: minkernel\crts\ucrt\src\appcrt\time\wcsftime.cpp Line: 971 Expression: timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099 For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts. (Press Retry to debug the application) }}} Any date with year `10000` will hit this assert. Starting with year `10001` `boost::gregorian::bad_year` is thrown instead. Such behavior is caused by max year (include/boost/date_time/gregorian/greg_year.hpp#L28) that allows year `10000`. This causes `tm_year` of `tm` to be `8100` out of range `[-1900; 8099]` when converting ptime to tm (include/boost/date_time/time_facet.hpp#L428). I would expect consistent `boost::gregorian::bad_year` thrown in all cases without crashes. One possible solution is to consider changing max year to `9999`. This would also fix #12630 and make `%Y` format specifier to be more consistent with its definition (xmldoc/format_flags.xml#L220) - a `Four digit year`. Currently, the following code on Linux outputs `10000` instead of throwing `boost::gregorian::bad_year` that is at least confusing since `10000` does not look like a four digit number as promised by `%Y`: {{{ #include #include int main() { std::ostringstream os; os.imbue(std::locale(std::locale::classic(), new boost::posix_time::time_facet(""%Y""))); os << boost::posix_time::ptime(boost::gregorian::date(10000, 1, 1)); std::cout << os.str(); return 0; } }}}" Bugs closed Boost 1.67.0 date_time Boost 1.63.0 Problem fixed