#14543 Use time from simulation start in Show Plot Data

When the summary plot time axis is configured to show time from simulation start, the text produced by Show Plot Data and the ASCII export now reports the same values instead of date and time. The time column header becomes "Time [<unit>]", and each row reports the elapsed time relative to the first time step of the first curve, scaled to the display unit selected on the time axis. Plots using the date based time axis are unchanged.

Time in months and years is computed using calendar arithmetic instead of a fixed number of seconds per unit, so a time step exactly N calendar months or years after the simulation start reports exactly N. This makes resampled data report whole numbers also when a leap year is part of the interval. The calendar arithmetic is available as RiaQDateTimeTools::calendarYearsBetween() and calendarMonthsBetween(), and is used both when plotting the curves and when reporting the time column.
This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-08-20 11:26:56 +02:00
1 parent ce12272721
commit 9b268e6d98
12 files changed
+340 -32

No files matched your search

@@ -207,6 +207,60 @@ QDateTime RiaQDateTimeTools::createDateTime( const QDate& date, Qt::TimeSpec tim
return date.startOfDay( timeSpec );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarYearsBetween( const QDateTime& startTime, const QDateTime& endTime )
{
return calendarUnitsBetween( startTime, endTime, false );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarMonthsBetween( const QDateTime& startTime, const QDateTime& endTime )
{
return calendarUnitsBetween( startTime, endTime, true );
}
//--------------------------------------------------------------------------------------------------
/// A calendar month or year has a varying number of seconds. Count the number of whole calendar units, and express the
/// remainder as a fraction of the calendar unit it falls inside.
//--------------------------------------------------------------------------------------------------
double RiaQDateTimeTools::calendarUnitsBetween( const QDateTime& startTime, const QDateTime& endTime, bool useMonths )
{
if ( startTime == endTime ) return 0.0;
auto addUnits = [&startTime, useMonths]( int unitCount )
{ return useMonths ? startTime.addMonths( unitCount ) : startTime.addYears( unitCount ); };
const int sign = ( endTime > startTime ) ? 1 : -1;
auto isBeyondEnd = [&endTime, sign]( const QDateTime& dt ) { return sign > 0 ? dt > endTime : dt < endTime; };
// Start off with an estimate based on the average length of the calendar unit, then adjust to the exact count
const double averageSecondsInUnit = useMonths ? 2629746.0 : 31556952.0;
int unitCount = static_cast<int>( std::abs( static_cast<double>( startTime.secsTo( endTime ) ) ) / averageSecondsInUnit );
while ( unitCount > 0 && isBeyondEnd( addUnits( unitCount * sign ) ) )
{
unitCount--;
}
while ( !isBeyondEnd( addUnits( ( unitCount + 1 ) * sign ) ) )
{
unitCount++;
}
const QDateTime lower = addUnits( unitCount * sign );
const QDateTime upper = addUnits( ( unitCount + 1 ) * sign );
const double secondsInUnit = std::abs( static_cast<double>( lower.secsTo( upper ) ) );
const double fraction = secondsInUnit > 0.0 ? std::abs( static_cast<double>( lower.secsTo( endTime ) ) ) / secondsInUnit : 0.0;
return sign * ( unitCount + fraction );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -22,6 +22,8 @@
#include <QString>
#include <ctime>
#include <set>
#include <string>
#include <vector>
@@ -58,6 +60,12 @@ public:
static QDateTime createDateTime( const QDate& date, Qt::TimeSpec timeSpec = Qt::LocalTime );
// Number of calendar years/months between two time steps. The remainder is expressed as a fraction of the calendar
// unit it falls inside, so a time step exactly N calendar years/months after the start reports exactly N. Time
// steps before the start time are reported as negative values.
static double calendarYearsBetween( const QDateTime& startTime, const QDateTime& endTime );
static double calendarMonthsBetween( const QDateTime& startTime, const QDateTime& endTime );
static QDateTime epoch();
static QDateTime createUtcDateTime();
@@ -99,6 +107,8 @@ public:
getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps, const QDateTime& fromTimeStep, const QDateTime& toTimeStep );
private:
static double calendarUnitsBetween( const QDateTime& startTime, const QDateTime& endTime, bool useMonths );
static const DateTimeSpan TIMESPAN_MINUTE;
static const DateTimeSpan TIMESPAN_HOUR;
static const DateTimeSpan TIMESPAN_DAY;
@@ -19,6 +19,7 @@
#include "RimAsciiDataCurve.h"
#include "RiaDefines.h"
#include "RiaQDateTimeTools.h"
#include "RimEclipseResultCase.h"
#include "RimProject.h"
@@ -137,15 +138,15 @@ void RimAsciiDataCurve::onLoadDataAndUpdate( bool updateParentPlot )
}
else
{
double timeScale = plot->timeAxisProperties()->fromTimeTToDisplayUnitScale();
auto* timeAxisProperties = plot->timeAxisProperties();
std::vector<double> times;
if ( !dateTimes.empty() )
{
time_t startDate = dateTimes[0];
const QDateTime startDate = RiaQDateTimeTools::fromTime_t( dateTimes[0] );
for ( time_t& date : dateTimes )
{
times.push_back( timeScale * ( date - startDate ) );
times.push_back( timeAxisProperties->timeFromSimulationStart( startDate, RiaQDateTimeTools::fromTime_t( date ) ) );
}
}
@@ -704,15 +704,16 @@ void RimSummaryCurve::onLoadDataAndUpdate( bool updateParentPlot )
}
else
{
double timeScale = plot->timeAxisProperties()->fromTimeTToDisplayUnitScale();
auto* timeAxisProperties = plot->timeAxisProperties();
std::vector<double> timeFromSimulationStart;
if ( !curveTimeStepsY.empty() )
{
time_t startDate = curveTimeStepsY[0];
const QDateTime startDate = RiaQDateTimeTools::fromTime_t( curveTimeStepsY[0] );
for ( const auto& date : curveTimeStepsY )
{
timeFromSimulationStart.push_back( timeScale * ( date - startDate ) );
timeFromSimulationStart.push_back(
timeAxisProperties->timeFromSimulationStart( startDate, RiaQDateTimeTools::fromTime_t( date ) ) );
}
}
@@ -19,6 +19,7 @@
#include "RimSummaryCurvesData.h"
#include "RiaGuiApplication.h"
#include "RiaQDateTimeTools.h"
#include "RiaTimeHistoryCurveResampler.h"
#include "Summary/RiaSummaryCurveDefinition.h"
#include "Summary/RiaSummaryTools.h"
@@ -35,6 +36,36 @@
#include <QMessageBox>
namespace
{
//--------------------------------------------------------------------------------------------------
/// Header text for the time column, either date and time or time from simulation start
//--------------------------------------------------------------------------------------------------
QString timeColumnHeaderText( const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( timeFromSimulationStart ) return QString( "Time [%1]" ).arg( timeFromSimulationStart->displayUnitText );
return "Date and time";
}
//--------------------------------------------------------------------------------------------------
/// Text for a single time step, either date and time or time from simulation start
//--------------------------------------------------------------------------------------------------
QString timeStepText( const QDateTime& timeStep, const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( timeFromSimulationStart )
{
double timeSinceSimulationStart = RimSummaryTimeAxisProperties::timeFromSimulationStart( timeFromSimulationStart->simulationStartTime,
timeStep,
timeFromSimulationStart->displayUnit );
return QString::number( timeSinceSimulationStart, 'g', RimSummaryPlot::precision() );
}
return timeStep.toString( "yyyy-MM-dd hh:mm:ss " );
}
} // namespace
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -135,11 +166,12 @@ void RimSummaryCurvesData::addCurveDataNoSearch( const QString& c
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString )
QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
if ( curves.empty() && asciiCurves.empty() && gridCurves.empty() ) return {};
@@ -152,14 +184,14 @@ QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryC
RimSummaryCurvesData::populateSummaryCurvesData( curves, SummaryCurveType::CURVE_TYPE_OBSERVED, &summaryCurvesObsData );
RimSummaryCurvesData::populateTimeHistoryCurvesData( gridCurves, &gridCurvesData );
RimSummaryCurvesData::appendToExportData( out, { summaryCurvesObsData }, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, { summaryCurvesObsData }, showTimeAsLongString, timeFromSimulationStart );
std::vector<RimSummaryCurvesData> exportData( 2 );
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, summaryCurvesData, &exportData[0] );
RimSummaryCurvesData::prepareCaseCurvesForExport( resamplingPeriod, gridCurvesData, &exportData[1] );
RimSummaryCurvesData::appendToExportData( out, exportData, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, exportData, showTimeAsLongString, timeFromSimulationStart );
{
// Handle observed data pasted into plot from clipboard
@@ -167,7 +199,7 @@ QString RimSummaryCurvesData::createTextForExport( const std::vector<RimSummaryC
RimSummaryCurvesData asciiCurvesData;
RimSummaryCurvesData::populateAsciiDataCurvesData( asciiCurves, &asciiCurvesData );
RimSummaryCurvesData::appendToExportData( out, { asciiCurvesData }, showTimeAsLongString );
RimSummaryCurvesData::appendToExportData( out, { asciiCurvesData }, showTimeAsLongString, timeFromSimulationStart );
}
return out;
@@ -328,20 +360,23 @@ void RimSummaryCurvesData::prepareCaseCurvesForExport( RiaDefines::DateTimePerio
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurvesData::appendToExportDataForCase( QString& out, const std::vector<time_t>& timeSteps, const std::vector<CurveData>& curveData )
void RimSummaryCurvesData::appendToExportDataForCase( QString& out,
const std::vector<time_t>& timeSteps,
const std::vector<CurveData>& curveData,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
for ( size_t j = 0; j < timeSteps.size(); j++ ) // time steps & data points
{
if ( j == 0 )
{
out += "Date and time";
out += timeColumnHeaderText( timeFromSimulationStart );
for ( const auto& k : curveData ) // curves
{
out += "\t" + ( k.name );
}
}
out += "\n";
out += QDateTime::fromSecsSinceEpoch( timeSteps[j] ).toUTC().toString( "yyyy-MM-dd hh:mm:ss " );
out += timeStepText( RiaQDateTimeTools::fromTime_t( timeSteps[j] ), timeFromSimulationStart );
for ( const auto& k : curveData ) // curves
{
@@ -358,7 +393,10 @@ void RimSummaryCurvesData::appendToExportDataForCase( QString& out, const std::v
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<RimSummaryCurvesData>& curvesData, bool showTimeAsLongString )
void RimSummaryCurvesData::appendToExportData( QString& out,
const std::vector<RimSummaryCurvesData>& curvesData,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart )
{
RimSummaryCurvesData data = RimSummaryCurvesData::concatCurvesData( curvesData );
@@ -392,7 +430,7 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
}
out += "\n\n";
out += "Date and time";
out += timeColumnHeaderText( timeFromSimulationStart );
for ( size_t i = 0; i < data.caseIds.size(); i++ )
{
for ( auto& j : data.allCurveData[i] )
@@ -411,7 +449,11 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
QDateTime timseStepUtc = QDateTime::fromSecsSinceEpoch( timeStep ).toUTC();
QString timeText;
if ( showTimeAsLongString )
if ( timeFromSimulationStart )
{
timeText = timeStepText( timseStepUtc, timeFromSimulationStart );
}
else if ( showTimeAsLongString )
{
timeText = timseStepUtc.toString( "yyyy-MM-dd hh:mm:ss " );
}
@@ -502,7 +544,7 @@ void RimSummaryCurvesData::appendToExportData( QString& out, const std::vector<R
out += "\n";
}
appendToExportDataForCase( out, data.timeSteps[i], data.allCurveData[i] );
appendToExportDataForCase( out, data.timeSteps[i], data.allCurveData[i], timeFromSimulationStart );
}
}
}
@@ -21,8 +21,13 @@
#include "RiaDateTimeDefines.h"
#include "RifEclipseSummaryAddress.h"
#include "RimSummaryTimeAxisProperties.h"
#include <QDateTime>
#include <QString>
#include <optional>
class RimSummaryCurve;
class RimGridTimeHistoryCurve;
class RimAsciiDataCurve;
@@ -34,6 +39,14 @@ struct CurveData
std::vector<double> values;
};
// Used to report the time column as time from simulation start instead of date and time
struct TimeFromSimulationStartInfo
{
QDateTime simulationStartTime;
RimSummaryTimeAxisProperties::TimeUnitType displayUnit = RimSummaryTimeAxisProperties::YEARS;
QString displayUnitText;
};
enum class SummaryCurveType
{
CURVE_TYPE_SUMMARY = 0x1,
@@ -53,11 +66,12 @@ public:
const std::vector<time_t>& curvetimeSteps,
const std::vector<CurveData>& curveDataVector );
static QString createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString );
static QString createTextForExport( const std::vector<RimSummaryCurve*>& curves,
const std::vector<RimAsciiDataCurve*>& asciiCurves,
const std::vector<RimGridTimeHistoryCurve*>& gridCurves,
RiaDefines::DateTimePeriod resamplingPeriod,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart = {} );
static QString createTextForCrossPlotCurves( const std::vector<RimSummaryCurve*>& curves );
@@ -70,8 +84,14 @@ private:
const RimSummaryCurvesData& inputCurvesData,
RimSummaryCurvesData* resultCurvesData );
static void appendToExportDataForCase( QString& out, const std::vector<time_t>& timeSteps, const std::vector<CurveData>& curveData );
static void appendToExportData( QString& out, const std::vector<RimSummaryCurvesData>& curvesData, bool showTimeAsLongString );
static void appendToExportDataForCase( QString& out,
const std::vector<time_t>& timeSteps,
const std::vector<CurveData>& curveData,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart );
static void appendToExportData( QString& out,
const std::vector<RimSummaryCurvesData>& curvesData,
bool showTimeAsLongString,
const std::optional<TimeFromSimulationStartInfo>& timeFromSimulationStart );
RimSummaryCurvesData static concatCurvesData( const std::vector<RimSummaryCurvesData>& curvesData );
private:
@@ -26,6 +26,7 @@
#include "RiaPlotDefines.h"
#include "RiaPreferences.h"
#include "RiaPreferencesSummary.h"
#include "RiaQDateTimeTools.h"
#include "RiaRegressionTestRunner.h"
#include "RiaStdStringTools.h"
#include "RiuMessageDialog.h"
@@ -93,10 +94,28 @@
#include <algorithm>
#include <cmath>
#include <limits>
#include <optional>
#include <set>
CAF_PDM_SOURCE_INIT( RimSummaryPlot, "SummaryPlot" );
namespace
{
//--------------------------------------------------------------------------------------------------
/// Returns the info required to report time as time from simulation start. Returns nothing if the
/// time axis is configured to show dates.
//--------------------------------------------------------------------------------------------------
std::optional<TimeFromSimulationStartInfo> createTimeFromSimulationStartInfo( RimSummaryPlot* summaryPlot )
{
auto* timeAxisProperties = summaryPlot->timeAxisProperties();
if ( !timeAxisProperties || timeAxisProperties->timeMode() != RimSummaryTimeAxisProperties::TIME_FROM_SIMULATION_START ) return {};
return TimeFromSimulationStartInfo{ RiaQDateTimeTools::fromTime_t( summaryPlot->firstTimeStepOfFirstCurve() ),
timeAxisProperties->timeUnit(),
caf::AppEnum<RimSummaryTimeAxisProperties::TimeUnitType>::uiText( timeAxisProperties->timeUnit() ) };
}
} // namespace
struct RimSummaryPlot::CurveInfo
{
int curveCount = 0;
@@ -368,13 +387,21 @@ QString RimSummaryPlot::asciiDataForSummaryPlotExport( RiaDefines::DateTimePerio
auto gridCurves = m_gridTimeHistoryCurves.childrenByType();
auto asciiCurves = m_asciiDataCurves.childrenByType();
auto timeFromSimulationStart = createTimeFromSimulationStartInfo( const_cast<RimSummaryPlot*>( this ) );
QString text;
text += RimSummaryCurvesData::createTextForExport( curves, asciiCurves, gridCurves, resamplingPeriod, showTimeAsLongString );
text +=
RimSummaryCurvesData::createTextForExport( curves, asciiCurves, gridCurves, resamplingPeriod, showTimeAsLongString, timeFromSimulationStart );
if ( !observedCurves.empty() )
{
text += "\n\n------------ Observed Curves --------------";
text += RimSummaryCurvesData::createTextForExport( observedCurves, {}, {}, RiaDefines::DateTimePeriod::NONE, showTimeAsLongString );
text += RimSummaryCurvesData::createTextForExport( observedCurves,
{},
{},
RiaDefines::DateTimePeriod::NONE,
showTimeAsLongString,
timeFromSimulationStart );
}
text += RimSummaryCurvesData::createTextForCrossPlotCurves( crossPlotCurves );
@@ -667,13 +667,44 @@ void RimSummaryTimeAxisProperties::setTimeMode( TimeModeType val )
m_timeMode = val;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSummaryTimeAxisProperties::TimeUnitType RimSummaryTimeAxisProperties::timeUnit() const
{
return m_timeUnit();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSummaryTimeAxisProperties::timeFromSimulationStart( const QDateTime& simulationStartTime,
const QDateTime& timeStep,
TimeUnitType displayUnit )
{
// A calendar month or year has a varying number of seconds, use calendar arithmetic for these units to make a time
// step exactly N calendar months/years after the simulation start report exactly N.
if ( displayUnit == MONTHS ) return RiaQDateTimeTools::calendarMonthsBetween( simulationStartTime, timeStep );
if ( displayUnit == YEARS ) return RiaQDateTimeTools::calendarYearsBetween( simulationStartTime, timeStep );
return scaleFromSecondsToDisplayUnit( displayUnit ) * static_cast<double>( simulationStartTime.secsTo( timeStep ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSummaryTimeAxisProperties::timeFromSimulationStart( const QDateTime& simulationStartTime, const QDateTime& timeStep ) const
{
return timeFromSimulationStart( simulationStartTime, timeStep, m_timeUnit() );
}
//--------------------------------------------------------------------------------------------------
/// https://www.unitconverters.net/time-converter.html
//--------------------------------------------------------------------------------------------------
double RimSummaryTimeAxisProperties::fromTimeTToDisplayUnitScale()
double RimSummaryTimeAxisProperties::scaleFromSecondsToDisplayUnit( TimeUnitType displayUnit )
{
double scale = 1.0;
switch ( m_timeUnit() )
switch ( displayUnit )
{
case SECONDS:
break;
@@ -701,6 +732,14 @@ double RimSummaryTimeAxisProperties::fromTimeTToDisplayUnitScale()
return scale;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSummaryTimeAxisProperties::fromTimeTToDisplayUnitScale()
{
return scaleFromSecondsToDisplayUnit( m_timeUnit() );
}
//--------------------------------------------------------------------------------------------------
/// https://www.unitconverters.net/time-converter.html
//--------------------------------------------------------------------------------------------------
@@ -93,9 +93,17 @@ public:
int valuesFontSize() const override;
TimeModeType timeMode() const;
void setTimeMode( TimeModeType val );
TimeUnitType timeUnit() const;
double fromTimeTToDisplayUnitScale();
double fromDaysToDisplayUnitScale();
static double scaleFromSecondsToDisplayUnit( TimeUnitType displayUnit );
// Time from simulation start expressed in the given display unit. MONTHS and YEARS are computed using calendar
// arithmetic, so a time step exactly N calendar months/years after the start reports exactly N.
static double timeFromSimulationStart( const QDateTime& simulationStartTime, const QDateTime& timeStep, TimeUnitType displayUnit );
double timeFromSimulationStart( const QDateTime& simulationStartTime, const QDateTime& timeStep ) const;
RiaDefines::DateFormatComponents
dateComponents( RiaDefines::DateFormatComponents fallback = RiaDefines::DateFormatComponents::DATE_FORMAT_UNSPECIFIED ) const;
RiaDefines::TimeFormatComponents
@@ -87,6 +87,7 @@ set(SOURCE_UNITTEST_FILES
${CMAKE_CURRENT_LIST_DIR}/RimDataFilterCollection-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseCollection-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCaseMainCollection-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimSummaryTimeAxisProperties-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RimDeltaSummaryEnsemble-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifActiveCellsReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifCsvDataTableFormatter-Test.cpp
@@ -96,6 +97,7 @@ set(SOURCE_UNITTEST_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaInterpolationTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifWellMeasurementReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaDateStringParser-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaQDateTimeTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RigHexGradientTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifSurfaceImporter-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifFormationNamesReader-Test.cpp
@@ -0,0 +1,59 @@
#include "gtest/gtest.h"
#include "RiaQDateTimeTools.h"
#include <QDate>
namespace
{
QDateTime utcTime( int year, int month, int day )
{
return RiaQDateTimeTools::createUtcDateTime( QDate( year, month, day ) );
}
} // namespace
//--------------------------------------------------------------------------------------------------
/// Time steps landing on a calendar year boundary must report a whole number of years, also when a
/// leap year is part of the interval.
//--------------------------------------------------------------------------------------------------
TEST( RiaQDateTimeToolsTest, CalendarYearsBetween )
{
const QDateTime start = utcTime( 2000, 1, 1 );
for ( int i = 0; i <= 10; i++ )
{
EXPECT_NEAR( static_cast<double>( i ), RiaQDateTimeTools::calendarYearsBetween( start, utcTime( 2000 + i, 1, 1 ) ), 1e-9 );
}
// Half way into a non-leap year
EXPECT_NEAR( 1.5, RiaQDateTimeTools::calendarYearsBetween( start, utcTime( 2001, 7, 2 ) ), 1e-2 );
// Start time that is not at a year boundary
EXPECT_NEAR( 3.0, RiaQDateTimeTools::calendarYearsBetween( utcTime( 1997, 11, 6 ), utcTime( 2000, 11, 6 ) ), 1e-9 );
// Time steps before the start time are reported as negative
EXPECT_NEAR( -2.0, RiaQDateTimeTools::calendarYearsBetween( start, utcTime( 1998, 1, 1 ) ), 1e-9 );
EXPECT_NEAR( 0.0, RiaQDateTimeTools::calendarYearsBetween( start, start ), 1e-9 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaQDateTimeToolsTest, CalendarMonthsBetween )
{
const QDateTime start = utcTime( 2000, 1, 1 );
for ( int i = 0; i <= 36; i++ )
{
int year = 2000 + i / 12;
int month = 1 + i % 12;
EXPECT_NEAR( static_cast<double>( i ), RiaQDateTimeTools::calendarMonthsBetween( start, utcTime( year, month, 1 ) ), 1e-9 );
}
// 16 days into a 31 day month
EXPECT_NEAR( 16.0 / 31.0, RiaQDateTimeTools::calendarMonthsBetween( start, utcTime( 2000, 1, 17 ) ), 1e-9 );
EXPECT_NEAR( -1.0, RiaQDateTimeTools::calendarMonthsBetween( start, utcTime( 1999, 12, 1 ) ), 1e-9 );
}
@@ -0,0 +1,45 @@
#include "gtest/gtest.h"
#include "RimSummaryTimeAxisProperties.h"
#include "RiaQDateTimeTools.h"
#include <QDate>
namespace
{
QDateTime utcTime( int year, int month, int day )
{
return RiaQDateTimeTools::createUtcDateTime( QDate( year, month, day ) );
}
} // namespace
//--------------------------------------------------------------------------------------------------
/// MONTHS and YEARS use calendar arithmetic, the shorter units are a plain scaling of the number of
/// seconds since the simulation start.
//--------------------------------------------------------------------------------------------------
TEST( RimSummaryTimeAxisPropertiesTest, TimeFromSimulationStart )
{
const QDateTime start = utcTime( 2000, 1, 1 );
// 2000 is a leap year, a fixed seconds per year scaling would report 1.002074 years
EXPECT_NEAR( 1.0,
RimSummaryTimeAxisProperties::timeFromSimulationStart( start, utcTime( 2001, 1, 1 ), RimSummaryTimeAxisProperties::YEARS ),
1e-9 );
EXPECT_NEAR( 12.0,
RimSummaryTimeAxisProperties::timeFromSimulationStart( start, utcTime( 2001, 1, 1 ), RimSummaryTimeAxisProperties::MONTHS ),
1e-9 );
EXPECT_NEAR( 366.0,
RimSummaryTimeAxisProperties::timeFromSimulationStart( start, utcTime( 2001, 1, 1 ), RimSummaryTimeAxisProperties::DAYS ),
1e-9 );
EXPECT_NEAR( 24.0,
RimSummaryTimeAxisProperties::timeFromSimulationStart( start, utcTime( 2000, 1, 2 ), RimSummaryTimeAxisProperties::HOURS ),
1e-9 );
EXPECT_NEAR( 86400.0,
RimSummaryTimeAxisProperties::timeFromSimulationStart( start, utcTime( 2000, 1, 2 ), RimSummaryTimeAxisProperties::SECONDS ),
1e-9 );
}