One of the attractions of writing software using the .NET framework is the wealth of support for doing simple things like translating between different data formats. These tasks are typically much harder to achieve in C++ due to the lack of an equivalent framework. One such task that I came across the other day is that date-times are often represented by a double in Windows, where the integer part represents the date since some epoch and the fractional part is the time as a fraction of 24 hours. Even with access to the Boost library, I still had to do some work to produce a simple transformation in C++.
#include <boost/format.hpp> #include <boost/date_time/gregorian/gregorian.hpp> #include <boost/date_time/posix_time/posix_time.hpp> typedef double DateTime; namespace { boost::gregorian::date parse_date( DateTime date_time ) { boost::gregorian::date dt = boost::date_time::parse_date<boost::gregorian::date>( "1899-12-30", boost::date_time::ymd_order_iso ); dt += boost::gregorian::date_duration( static_cast<long>( floor(date_time) ) ); } boost::posix_time::time_duration parse_time( DateTime date_time ) { double fractionalDay = date_time - floor(date_time); long milliseconds = static_cast<long>( floor( fractionalDay * 24.0 * 60.0 * 60.0 * 1000.0 + 0.5) ); return boost::posix_time::milliseconds( milliseconds ); } } std::string to_date_string( DateTime date_time ) { boost::gregorian::date dt = parse_date( date_time ); return (boost::format( "%4-%02d-%02d" ) % dt.year() % dt.month().as_number() % dt.day().as_number()).str(); } DateTime from_date_string( const std::string& value ) { boost::gregorian::date epoch = boost::date_time::parse_date<boost::gregorian::date>( "1899-12-30", boost::date_time::ymd_order_iso); boost::gregorian::date dt = boost::date_time::parse_date<boost::gregorian::date>( value, boost::date_time::ymd_order_iso); boost::gregorian::date_duration diff = dt - epoch; return diff.days(); } std::string to_date_time_string( DateTime date_time ) { boost::gregorian::date date_part = parse_date( date_time ); boost::posix_time::time_duration time_part = parse_time( date_time ); long long fractional_seconds = time_part.fractional_seconds(); boost::date_time::time_resolutions resolution = time_part.resolution(); if ( resolution == boost::date_time::micro ) { fractional_seconds /= 1000; } else { if (resolution != boost::date_time::milli) throw std::logic_error( "Unexpected time resolution" ); } return (boost::format( "%d-%02d-%02d %02d:%02d:%02d.%03d" ) % date_part.Year() % date_part.month().as_number() % date_part.day().as_number() % time_part.hours() % time_part.minutes() % time_part.seconds() % fractional_seconds ).str(); } DateTime from_date_time_string( const std::string& value ) { DateTime date = from_date_string( value ); boost::posix_time::ptime t = boost::posix_time::time_from_string( value ); double milliseconds = static_cast<double>(t.time_of_day().total_milliseconds()); return date + (milliseconds / 24.0 / 60.0 / 60.0 / 1000.0); }
Please comment if you know a more straight-forward way to achieve this transformation, especially using Boost. Syntactically, the code could be simplified using C++11 auto, but I’ve spelt out the types explicitly throughout because I found it helpful to see which parts of the boost library are being used.
Pingback: How to get file names under a folder in C++ | musingstudio