Skip to content
Snippets Groups Projects
Commit f5f0c112 authored by Luc Hermitte's avatar Luc Hermitte
Browse files

BUG: Fix Microseconds conversion on `ossimModifiedJulianDate`

A Julian Date is a fraction of a day, not of a second.
parent 96f6b10b
No related branches found
No related tags found
No related merge requests found
......@@ -99,12 +99,12 @@ namespace ossimplugins {
inline
void add(ossimKeywordlist & kwl, std::string const& prefix, std::string const& key, time::ModifiedJulianDate const& v)
{
add(kwl, prefix, key, v.as_seconds());
add(kwl, prefix, key, v.as_day_frac());
}
inline
void add(ossimKeywordlist & kwl, std::string const& prefix, time::ModifiedJulianDate const& v)
void add(ossimKeywordlist & kwl, std::string const& key, time::ModifiedJulianDate const& v)
{
add(kwl, prefix, v.as_seconds());
add(kwl, key, v.as_day_frac());
}
template <typename T>
......
......@@ -101,24 +101,31 @@ ossimplugins::time::ModifiedJulianDate ossimplugins::time::toModifiedJulianDate(
std::string ossimplugins::time::to_simple_string(ModifiedJulianDate const& d)
{
ossimDate date ;
date.setDateFromModifiedJulian(d.as_seconds());
date.setDateFromModifiedJulian(d.as_day_frac());
char buffer[1024] = {0};
size_t s = std::strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%S", &date);
if (s == 0) {
// TODO d.as_seconds() -> string
// TODO d.as_day_frac() -> string
throw std::runtime_error("Cannot encode date into a string");
}
assert(s < 1000); // should be more than enough
typedef unsigned long ulong;
const double frac_sec = date.getFractionalSecond();
// const double fs2 = fmod(d.as_day_frac() * 24L*60*60, 1);
// assert(fs2==frac_sec);
// std::cout << "From: " << d.as_day_frac() << " -> frac_sec: " << fs2
// << " --> *10^6: " << fs2*1000L*1000
// << " --> %10^6: " << ulong(fs2*1000L*1000)%(1000L*1000)
// << "\n";
s += std::snprintf(&buffer[s], sizeof(buffer)-s, ".%06ld",
std::abs(ulong((date.getFractionalSecond() * 1000 * 1000)) % (1000*1000)));
ulong(frac_sec * 1000L * 1000) % (1000L*1000));
return std::string(buffer, s);
}
std::string ossimplugins::time::to_simple_string(Duration const& d)
{
typedef unsigned long ulong;
const double fs = d.as_seconds();
const double fs = d.as_day_frac() * 24L * 60 * 60; // in seconds
const ulong ls(fs);
const ulong us = ulong(fs * 1000*1000) % (1000*1000);
const ulong s = ls % 60;
......
......@@ -22,18 +22,18 @@ namespace ossimplugins { namespace time {
// class Duration;
namespace details
{
class Seconds
class DayFrac
{
public:
typedef double scalar_type;
// Seconds(Seconds const&) = default;
// Seconds(Seconds &&) = default;
// Seconds& operator=(Seconds const&) = default;
// Seconds& operator=(Seconds &&) = default;
double as_seconds() const { return m_seconds; }
// DayFrac(DayFrac const&) = default;
// DayFrac(DayFrac &&) = default;
// DayFrac& operator=(DayFrac const&) = default;
// DayFrac& operator=(DayFrac &&) = default;
double as_day_frac() const { return m_day_frac; }
std::ostream & display(std::ostream & os) const { return os << m_seconds; }
std::istream & read (std::istream & is) { return is >> m_seconds; }
std::ostream & display(std::ostream & os) const { return os << m_day_frac; }
std::istream & read (std::istream & is) { return is >> m_day_frac; }
protected:
/**@name Construction/destruction
......@@ -41,22 +41,22 @@ namespace ossimplugins { namespace time {
//@{
/** Initialisation constructor.
*/
explicit Seconds() {} // = default;
explicit Seconds(double seconds) : m_seconds(seconds) {}
explicit DayFrac() {} // = default;
explicit DayFrac(double day_frac) : m_day_frac(day_frac) {}
/** Protected destructor.
*/
~Seconds() {}// = default;
~DayFrac() {}// = default;
//@}
/**@name Operations
*/
//@{
void add(Seconds const& rhs) { m_seconds += rhs.m_seconds; }
void sub(Seconds const& rhs) { m_seconds -= rhs.m_seconds; }
void mult(scalar_type coeff) { m_seconds *= coeff; }
void div(scalar_type coeff) { assert(coeff && "Cannot divide by 0"); m_seconds /= coeff; }
void add(DayFrac const& rhs) { m_day_frac += rhs.m_day_frac; }
void sub(DayFrac const& rhs) { m_day_frac -= rhs.m_day_frac; }
void mult(scalar_type coeff) { m_day_frac *= coeff; }
void div(scalar_type coeff) { assert(coeff && "Cannot divide by 0"); m_day_frac /= coeff; }
template <typename V> friend scalar_type ratio(V const& lhs, V const& rhs)
{ return lhs.as_seconds() / rhs.as_seconds(); }
{ return lhs.as_day_frac() / rhs.as_day_frac(); }
template <typename U, typename V> friend U& operator+=(U & u, V const& v) {
u.add(v);
......@@ -68,7 +68,7 @@ namespace ossimplugins { namespace time {
}
template <typename U, typename V> static U diff(V const& lhs, V const& rhs) {
U const res(lhs.as_seconds() - rhs.as_seconds());
U const res(lhs.as_day_frac() - rhs.as_day_frac());
return res;
}
......@@ -82,14 +82,14 @@ namespace ossimplugins { namespace time {
}
template <typename T> friend bool operator<(T const& lhs, T const& rhs) {
return lhs.as_seconds() < rhs.as_seconds();
return lhs.as_day_frac() < rhs.as_day_frac();
}
template <typename T> friend bool operator==(T const& lhs, T const& rhs) {
return lhs.as_seconds() == rhs.as_seconds();
return lhs.as_day_frac() == rhs.as_day_frac();
}
//@}
private:
double m_seconds;
double m_day_frac;
};
}
......@@ -105,17 +105,17 @@ namespace ossimplugins { namespace time {
* @see \c std::duration<>
*/
class Duration
: public details::Seconds
: public details::DayFrac
, private addable<Duration>
, private substractable<Duration>
, private streamable<Duration>
, private multipliable2<Duration, double>
, private dividable<Duration, details::Seconds::scalar_type>
, private dividable<Duration, details::DayFrac::scalar_type>
, private equality_comparable<Duration>
, private less_than_comparable<Duration>
{
public:
typedef details::Seconds::scalar_type scalar_type;
typedef details::DayFrac::scalar_type scalar_type;
/**@name Construction/destruction
*/
......@@ -123,15 +123,18 @@ namespace ossimplugins { namespace time {
/** Initialisation constructor.
*/
Duration() {} // = default;
explicit Duration(double seconds)
: details::Seconds(seconds) {}
explicit Duration(double day_frac)
: details::DayFrac(day_frac) {}
//@}
double total_seconds() const {
return as_day_frac() * 24 * 60 * 60;
}
double total_microseconds() const {
return as_seconds() * 1000 * 1000;
return total_seconds() * 1000 * 1000;
}
bool is_negative() const { return as_seconds() < 0.0; }
Duration invert_sign() { return Duration(- as_seconds()); }
bool is_negative() const { return as_day_frac() < 0.0; }
Duration invert_sign() { return Duration(- as_day_frac()); }
};
/**
......@@ -145,7 +148,7 @@ namespace ossimplugins { namespace time {
* @see \c std::time_point<>
*/
class ModifiedJulianDate
: public details::Seconds
: public details::DayFrac
, private addable<ModifiedJulianDate, Duration>
, private substractable<ModifiedJulianDate, Duration>
, private substractable_asym<Duration, ModifiedJulianDate>
......@@ -154,7 +157,7 @@ namespace ossimplugins { namespace time {
, private less_than_comparable<ModifiedJulianDate>
{
public:
typedef details::Seconds::scalar_type scalar_type;
typedef details::DayFrac::scalar_type scalar_type;
/**@name Construction/destruction
*/
......@@ -162,16 +165,16 @@ namespace ossimplugins { namespace time {
/** Initialisation constructor.
*/
ModifiedJulianDate() {} // = default;
explicit ModifiedJulianDate(double seconds)
: details::Seconds(seconds) {}
explicit ModifiedJulianDate(double day_frac)
: details::DayFrac(day_frac) {}
//@}
using details::Seconds::diff;
using details::DayFrac::diff;
};
ModifiedJulianDate toModifiedJulianDate(string_view const& utcTimeString);
inline Duration microseconds(double us) {
return Duration(us / (1000 * 1000));
return Duration(us / (24L * 60 * 60 * 1000 * 1000));
}
std::string to_simple_string(ModifiedJulianDate const& d);
std::string to_simple_string(Duration const& d);
......
......@@ -135,7 +135,7 @@ void check_time(char const* format, char const* sDate,
iso.setIso8601(sDate);
BOOST_CHECK_EQUAL(d.getModifiedJulian(), iso.getModifiedJulian());
// Is ossimDate |--> MJD bijective ?
// Is ossimDate |--> MJD bijective ?
const double dMJD = d.getModifiedJulian();
ossimDate d2; d2.setDateFromModifiedJulian(dMJD);
BOOST_CHECK_EQUAL(d2.getYear(), year);
......@@ -146,14 +146,14 @@ void check_time(char const* format, char const* sDate,
BOOST_CHECK_CLOSE_FRACTION(d2.getSec()+d2.getFractionalSecond(), sec+fsec, 0.0001);
// Alternative implementation
BOOST_CHECK_EQUAL(d.getModifiedJulian(), getModifiedJulianDate(sDate));
BOOST_CHECK_CLOSE_FRACTION(d.getModifiedJulian(), getModifiedJulianDate(sDate), 0.01);
// Check string conversion
// Yes, this is likelly to fail du to double imprecisions
// - official ossimDate string conversion
time::ModifiedJulianDate mjd = time::toModifiedJulianDate(sDate);
// std::cout << "MJD("<<sDate<<"): " << mjd.as_seconds() << std::endl;
BOOST_CHECK_EQUAL(d.getModifiedJulian(), mjd.as_seconds());
// std::cout << "MJD("<<sDate<<"): " << mjd.as_day_frac() << std::endl;
BOOST_CHECK_CLOSE_FRACTION(d.getModifiedJulian(), mjd.as_day_frac(), 0.01);
std::ostringstream oss;
oss << d.getYear() << '-' << std::setw(2) << std::setfill('0') << d.getMonth() << '-' << d.getDay() << 'T';
d.printTime(oss);
......@@ -162,6 +162,9 @@ void check_time(char const* format, char const* sDate,
}
BOOST_CHECK_EQUAL(oss.str(), sDate);
// - our string conversion
// std::cout << std::setprecision(20) ;
// std::cout << mjd.as_day_frac() << " -> " << to_simple_string(mjd) << " / " << d.getModifiedJulian() << "\n";
// std::cout << oss.str() << "\n";
BOOST_CHECK_EQUAL(to_simple_string(mjd), sDate);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment