mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 07:00:17 -05:00
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.
679 lines
27 KiB
C++
679 lines
27 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (C) 2017 Statoil ASA
|
|
//
|
|
// ResInsight is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
|
// for more details.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "RiaQDateTimeTools.h"
|
|
|
|
#include <QDateTime>
|
|
#include <QLocale>
|
|
#include <QString>
|
|
#include <QTime>
|
|
|
|
#include "cafPdmOptionItemInfo.h"
|
|
#include "cafPdmUiItem.h"
|
|
|
|
#include "cafAssert.h"
|
|
|
|
#include <cmath>
|
|
#include <ctime>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_MINUTE = DateTimeSpan( 0, 0, 0, 0, 1 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_HOUR = DateTimeSpan( 0, 0, 0, 1 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_DAY = DateTimeSpan( 0, 0, 1 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_WEEK = DateTimeSpan( 0, 0, 7 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_MONTH = DateTimeSpan( 0, 1, 0 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_QUARTER = DateTimeSpan( 0, 3, 0 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_HALFYEAR = DateTimeSpan( 0, 6, 0 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_YEAR = DateTimeSpan( 1, 0, 0 );
|
|
const DateTimeSpan RiaQDateTimeTools::TIMESPAN_DECADE = DateTimeSpan( 10, 0, 0 );
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Qt::TimeSpec RiaQDateTimeTools::currentTimeSpec()
|
|
{
|
|
return Qt::UTC;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
quint64 RiaQDateTimeTools::secondsInMinute()
|
|
{
|
|
return 60;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
quint64 RiaQDateTimeTools::secondsInHour()
|
|
{
|
|
return 60 * 60;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
quint64 RiaQDateTimeTools::secondsInDay()
|
|
{
|
|
return 60 * 60 * 24;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
quint64 RiaQDateTimeTools::secondsInYear()
|
|
{
|
|
return 60 * 60 * 24 * 365;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::fromString( const QString& dateString, const QString& format )
|
|
{
|
|
QDateTime dt = QDateTime::fromString( dateString, format );
|
|
dt.setTimeSpec( currentTimeSpec() );
|
|
|
|
return dt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::fromYears( double years )
|
|
{
|
|
double yearsAfterEpoch = years - 1970.0;
|
|
|
|
QDateTime dt = RiaQDateTimeTools::epoch();
|
|
|
|
return RiaQDateTimeTools::addYears( dt, yearsAfterEpoch );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::fromTime_t( time_t t )
|
|
{
|
|
auto qdt = createUtcDateTime();
|
|
qdt.setSecsSinceEpoch( t );
|
|
return qdt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::addMSecs( const QDateTime& dt, double msecs )
|
|
{
|
|
return dt.addMSecs( msecs );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::addDays( const QDateTime& dt, double days )
|
|
{
|
|
double integerPart = 0.0;
|
|
double fractionPart = 0.0;
|
|
|
|
fractionPart = modf( days, &integerPart );
|
|
|
|
QDateTime tmp = dt.addDays( integerPart );
|
|
tmp = tmp.addSecs( fractionPart * RiaQDateTimeTools::secondsInDay() );
|
|
|
|
return tmp;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::addYears( const QDateTime& dt, double years )
|
|
{
|
|
double integerPart = 0.0;
|
|
double fractionPart = 0.0;
|
|
|
|
fractionPart = modf( years, &integerPart );
|
|
|
|
QDateTime tmp = dt.addYears( integerPart );
|
|
tmp = tmp.addSecs( fractionPart * RiaQDateTimeTools::secondsInYear() );
|
|
|
|
return tmp;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::addSpan( const QDateTime& dt, DateTimeSpan span )
|
|
{
|
|
return createUtcDateTime( dt )
|
|
.addYears( span.years() )
|
|
.addMonths( span.months() )
|
|
.addDays( span.days() )
|
|
.addSecs( span.hours() * RiaQDateTimeTools::secondsInHour() )
|
|
.addSecs( span.minutes() * RiaQDateTimeTools::secondsInMinute() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::subtractSpan( const QDateTime& dt, DateTimeSpan span )
|
|
{
|
|
return createUtcDateTime( dt )
|
|
.addYears( -span.years() )
|
|
.addMonths( -span.months() )
|
|
.addDays( -span.days() )
|
|
.addSecs( -span.hours() * RiaQDateTimeTools::secondsInHour() )
|
|
.addSecs( -span.minutes() * RiaQDateTimeTools::secondsInMinute() );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::addPeriod( const QDateTime& dt, RiaDefines::DateTimePeriod period )
|
|
{
|
|
return addSpan( dt, timeSpan( period ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::subtractPeriod( const QDateTime& dt, RiaDefines::DateTimePeriod period )
|
|
{
|
|
return subtractSpan( dt, timeSpan( period ) );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::createDateTime( const QDate& date, Qt::TimeSpec timeSpec /*= Qt::LocalTime*/ )
|
|
{
|
|
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 );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::epoch()
|
|
{
|
|
// NB: Not able to use QDateTime::fromMSecsSinceEpoch as this was introduced in Qt 4.7
|
|
|
|
QDateTime dt;
|
|
dt.setDate( QDate( 1970, 1, 1 ) );
|
|
dt.setTimeSpec( currentTimeSpec() );
|
|
|
|
return dt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::createUtcDateTime()
|
|
{
|
|
auto qdt = QDateTime();
|
|
qdt.setTimeSpec( currentTimeSpec() );
|
|
return qdt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDate& date )
|
|
{
|
|
auto qdt = createDateTime( date );
|
|
qdt.setTimeSpec( currentTimeSpec() );
|
|
return qdt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDate& date, const QTime& time )
|
|
{
|
|
auto qdt = QDateTime( date, time, currentTimeSpec() );
|
|
return qdt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::createUtcDateTime( const QDateTime& dt )
|
|
{
|
|
auto qdt = QDateTime( dt );
|
|
qdt.setTimeSpec( currentTimeSpec() );
|
|
return qdt;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool RiaQDateTimeTools::lessThan( const QDateTime& dt1, const QDateTime& dt2 )
|
|
{
|
|
// dt1 < dt2
|
|
return dt1.secsTo( dt2 ) > 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const DateTimeSpan RiaQDateTimeTools::timeSpan( RiaDefines::DateTimePeriod period )
|
|
{
|
|
switch ( period )
|
|
{
|
|
case RiaDefines::DateTimePeriod::MINUTE:
|
|
return TIMESPAN_MINUTE;
|
|
case RiaDefines::DateTimePeriod::HOUR:
|
|
return TIMESPAN_HOUR;
|
|
case RiaDefines::DateTimePeriod::DAY:
|
|
return TIMESPAN_DAY;
|
|
case RiaDefines::DateTimePeriod::WEEK:
|
|
return TIMESPAN_WEEK;
|
|
case RiaDefines::DateTimePeriod::MONTH:
|
|
return TIMESPAN_MONTH;
|
|
case RiaDefines::DateTimePeriod::QUARTER:
|
|
return TIMESPAN_QUARTER;
|
|
case RiaDefines::DateTimePeriod::HALFYEAR:
|
|
return TIMESPAN_HALFYEAR;
|
|
case RiaDefines::DateTimePeriod::YEAR:
|
|
return TIMESPAN_YEAR;
|
|
case RiaDefines::DateTimePeriod::DECADE:
|
|
return TIMESPAN_DECADE;
|
|
}
|
|
CAF_ASSERT( false );
|
|
return DateTimeSpan();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QDateTime RiaQDateTimeTools::truncateTime( const QDateTime& dt, RiaDefines::DateTimePeriod period )
|
|
{
|
|
int y = dt.date().year();
|
|
int m = dt.date().month();
|
|
int d = dt.date().day();
|
|
int dow = dt.date().dayOfWeek();
|
|
int h = dt.time().hour();
|
|
int minute = dt.time().minute();
|
|
|
|
switch ( period )
|
|
{
|
|
case RiaDefines::DateTimePeriod::MINUTE:
|
|
return createUtcDateTime( QDate( y, m, d ), QTime( h, minute, 0 ) );
|
|
case RiaDefines::DateTimePeriod::HOUR:
|
|
return createUtcDateTime( QDate( y, m, d ), QTime( h, 0, 0 ) );
|
|
case RiaDefines::DateTimePeriod::DAY:
|
|
return createUtcDateTime( QDate( y, m, d ) );
|
|
case RiaDefines::DateTimePeriod::WEEK:
|
|
return createUtcDateTime( QDate( y, m, d ).addDays( -dow + 1 ) );
|
|
case RiaDefines::DateTimePeriod::MONTH:
|
|
return createUtcDateTime( QDate( y, m, 1 ) );
|
|
case RiaDefines::DateTimePeriod::QUARTER:
|
|
return createUtcDateTime( QDate( y, ( ( m - 1 ) / 3 ) * 3 + 1, 1 ) );
|
|
case RiaDefines::DateTimePeriod::HALFYEAR:
|
|
return createUtcDateTime( QDate( y, ( ( m - 1 ) / 6 ) * 6 + 1, 1 ) );
|
|
case RiaDefines::DateTimePeriod::YEAR:
|
|
return createUtcDateTime( QDate( y, 1, 1 ) );
|
|
case RiaDefines::DateTimePeriod::DECADE:
|
|
return createUtcDateTime( QDate( ( y / 10 ) * 10, 1, 1 ) );
|
|
}
|
|
CAF_ASSERT( false );
|
|
return createUtcDateTime();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<RiaDefines::DateTimePeriod> RiaQDateTimeTools::dateTimePeriods()
|
|
{
|
|
std::vector<RiaDefines::DateTimePeriod> allPeriods;
|
|
|
|
for ( size_t i = 0; i < RiaDefines::DateTimePeriodEnum::size(); i++ )
|
|
{
|
|
allPeriods.push_back( RiaDefines::DateTimePeriodEnum::fromIndex( i ) );
|
|
}
|
|
|
|
return allPeriods;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::dateTimePeriodName( RiaDefines::DateTimePeriod period )
|
|
{
|
|
return RiaDefines::DateTimePeriodEnum::uiText( period );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::toStringUsingApplicationLocale( const QDateTime& dt, const QString& format )
|
|
{
|
|
// Default application locale is set in RiaMain
|
|
// QLocale::setDefault(QLocale(QLocale::English, QLocale::UnitedStates));
|
|
//
|
|
// QDate/QDateTime use system locale for toString() functions
|
|
|
|
QLocale defaultApplicationLocale;
|
|
|
|
return defaultApplicationLocale.toString( dt, format );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::createTimeFormatStringFromDates( const std::vector<QDateTime>& dates )
|
|
{
|
|
bool hasHoursAndMinutesInTimesteps = false;
|
|
bool hasSecondsInTimesteps = false;
|
|
bool hasMillisecondsInTimesteps = false;
|
|
|
|
for ( size_t i = 0; i < dates.size(); i++ )
|
|
{
|
|
if ( dates[i].time().msec() != 0.0 )
|
|
{
|
|
hasMillisecondsInTimesteps = true;
|
|
hasSecondsInTimesteps = true;
|
|
hasHoursAndMinutesInTimesteps = true;
|
|
break;
|
|
}
|
|
else if ( dates[i].time().second() != 0.0 )
|
|
{
|
|
hasHoursAndMinutesInTimesteps = true;
|
|
hasSecondsInTimesteps = true;
|
|
}
|
|
else if ( dates[i].time().hour() != 0.0 || dates[i].time().minute() != 0.0 )
|
|
{
|
|
hasHoursAndMinutesInTimesteps = true;
|
|
}
|
|
}
|
|
|
|
QString formatString = dateFormatString();
|
|
if ( hasHoursAndMinutesInTimesteps )
|
|
{
|
|
formatString += " - hh:mm";
|
|
if ( hasSecondsInTimesteps )
|
|
{
|
|
formatString += ":ss";
|
|
if ( hasMillisecondsInTimesteps )
|
|
{
|
|
formatString += ".zzz";
|
|
}
|
|
}
|
|
}
|
|
|
|
return formatString;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::dateFormatString()
|
|
{
|
|
return "dd.MMM yyyy";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QString> RiaQDateTimeTools::supportedDateFormats()
|
|
{
|
|
std::vector<QString> dateFormats;
|
|
|
|
// See enum DateFormatComponents in header
|
|
// The semi-colon separated components are:
|
|
// DATE_FORMAT_YEAR, ..YEAR_MONTH, ..YEAR_MONTH_DAY
|
|
dateFormats.push_back( "yyyy;yyyy-MM;yyyy-MM-dd" );
|
|
dateFormats.push_back( "yyyy;MMM yyyy;dd. MMM yyyy" );
|
|
dateFormats.push_back( "yyyy;MMM yyyy;MMM dd. yyyy" );
|
|
dateFormats.push_back( "yyyy;MM/yyyy;dd/MM/yyyy" );
|
|
dateFormats.push_back( "yyyy;M/yyyy;d/M/yyyy" );
|
|
dateFormats.push_back( "yyyy;M/yyyy;M/d/yyyy" );
|
|
dateFormats.push_back( "yy;M/yy;d/M/yy" );
|
|
dateFormats.push_back( "yy;M/yy;M/d/yy" );
|
|
dateFormats.push_back( "yyyy;MM-yyyy;dd-MM-yyyy" );
|
|
dateFormats.push_back( "yyyy;MM.yyyy;dd.MM.yyyy" );
|
|
dateFormats.push_back( "yyyy;MM-yyyy;MM-dd-yyyy" );
|
|
dateFormats.push_back( "yyyy;MM.yyyy;MM.dd.yyyy" );
|
|
dateFormats.push_back( "yy;MM-yy;dd-MM-yy" );
|
|
dateFormats.push_back( "yy;MM-yy;MM-dd-yy" );
|
|
|
|
return dateFormats;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QString> RiaQDateTimeTools::supportedTimeFormats()
|
|
{
|
|
std::vector<QString> timeFormats;
|
|
|
|
// See enum TimeFormatComponents in header
|
|
// The semi-colon separated components are:
|
|
// TIME_FORMAT_HOUR, ..HOUR_MINUTE, ..HOUR_MINUTE_SECOND and ..HOUR_MINUTE_MILLISECOND
|
|
timeFormats.push_back( "HH;HH:mm;HH:mm:ss;HH:mm:ss.zzz" );
|
|
timeFormats.push_back( "H;H:mm;H:mm:ss;H:mm:ss.zzz" );
|
|
timeFormats.push_back( "hh AP;hh:mm AP;hh:mm:ss AP;hh:mm:ss.zzz AP" );
|
|
timeFormats.push_back( "h AP;h:mm AP;h:mm:ss AP;h:mm:ss.zzz AP" );
|
|
|
|
return timeFormats;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::dateFormatString( const QString& fullDateFormat, RiaDefines::DateFormatComponents dateComponents )
|
|
{
|
|
if ( dateComponents == RiaDefines::DateFormatComponents::DATE_FORMAT_NONE ) return "";
|
|
|
|
auto enumValue = static_cast<std::underlying_type<RiaDefines::DateFormatComponents>::type>( dateComponents );
|
|
if ( enumValue < 0 ) return "";
|
|
|
|
QStringList allVariants = fullDateFormat.split( ";" );
|
|
if ( enumValue < allVariants.size() )
|
|
{
|
|
return allVariants[enumValue];
|
|
}
|
|
CAF_ASSERT( false && "Date format string is malformed" );
|
|
return "";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QString RiaQDateTimeTools::timeFormatString( const QString& fullTimeFormat, RiaDefines::TimeFormatComponents timeComponents )
|
|
{
|
|
if ( timeComponents == RiaDefines::TimeFormatComponents::TIME_FORMAT_NONE ) return "";
|
|
|
|
QStringList allVariants = fullTimeFormat.split( ";" );
|
|
if ( static_cast<int>( timeComponents ) < allVariants.size() )
|
|
{
|
|
return allVariants[static_cast<int>( timeComponents )];
|
|
}
|
|
CAF_ASSERT( false && "Time format string is malformed" );
|
|
return "";
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
QList<caf::PdmOptionItemInfo> RiaQDateTimeTools::createOptionItems( const std::vector<time_t>& timeSteps )
|
|
{
|
|
QList<caf::PdmOptionItemInfo> options;
|
|
|
|
std::vector<QDateTime> dateTimes;
|
|
for ( time_t timeT : timeSteps )
|
|
{
|
|
QDateTime dateTime = RiaQDateTimeTools::fromTime_t( timeT );
|
|
|
|
dateTimes.push_back( dateTime );
|
|
}
|
|
|
|
QString formatString = RiaQDateTimeTools::createTimeFormatStringFromDates( dateTimes );
|
|
|
|
for ( size_t i = 0; i < dateTimes.size(); i++ )
|
|
{
|
|
const auto& dt = dateTimes[i];
|
|
QString text = RiaQDateTimeTools::toStringUsingApplicationLocale( dt, formatString );
|
|
options.push_back( { text, static_cast<int>( i ) } );
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::set<QDateTime> RiaQDateTimeTools::createEvenlyDistributedDates( const std::vector<QDateTime>& inputDates, int numDates )
|
|
{
|
|
std::set<QDateTime> outputDates;
|
|
if ( inputDates.empty() || numDates <= 0 )
|
|
{
|
|
return {};
|
|
}
|
|
if ( static_cast<size_t>( numDates ) > inputDates.size() )
|
|
{
|
|
outputDates = std::set( inputDates.begin(), inputDates.end() );
|
|
return outputDates;
|
|
}
|
|
if ( numDates == 1 )
|
|
{
|
|
outputDates = { inputDates.front() };
|
|
return outputDates;
|
|
}
|
|
|
|
// Find the minimum and maximum dates in the input vector
|
|
QDateTime minDate = *std::min_element( inputDates.begin(), inputDates.end() );
|
|
QDateTime maxDate = *std::max_element( inputDates.begin(), inputDates.end() );
|
|
|
|
// Calculate the time step between each selected date
|
|
qint64 timeStep = ( maxDate.toMSecsSinceEpoch() - minDate.toMSecsSinceEpoch() ) / ( static_cast<qint64>( numDates ) - 1 );
|
|
|
|
// Find the index of the input date that is closest to each new date
|
|
for ( int i = 0; i < numDates; ++i )
|
|
{
|
|
qint64 targetTime = minDate.toMSecsSinceEpoch() + i * timeStep;
|
|
int closestIndex = 0;
|
|
qint64 closestTimeDiff = std::numeric_limits<qint64>::max();
|
|
for ( size_t j = 0; j < inputDates.size(); ++j )
|
|
{
|
|
qint64 timeDiff = std::abs( inputDates[j].toMSecsSinceEpoch() - targetTime );
|
|
if ( timeDiff < closestTimeDiff )
|
|
{
|
|
closestIndex = static_cast<int>( j );
|
|
closestTimeDiff = timeDiff;
|
|
}
|
|
}
|
|
|
|
// Add the closest date to the output vector
|
|
outputDates.insert( inputDates[closestIndex] );
|
|
}
|
|
|
|
return outputDates;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::vector<QDateTime> RiaQDateTimeTools::getTimeStepsWithinSelectedRange( const std::vector<QDateTime>& timeSteps,
|
|
const QDateTime& fromTimeStep,
|
|
const QDateTime& toTimeStep )
|
|
{
|
|
std::vector<QDateTime> selectedTimeSteps;
|
|
auto isTimeStepInSelectedRange = [&]( const QDateTime& timeStep ) -> bool { return fromTimeStep <= timeStep && timeStep <= toTimeStep; };
|
|
std::copy_if( timeSteps.begin(), timeSteps.end(), std::back_inserter( selectedTimeSteps ), isTimeStepInSelectedRange );
|
|
|
|
return selectedTimeSteps;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
std::set<QDateTime>
|
|
RiaQDateTimeTools::createEvenlyDistributedDatesInInterval( const QDateTime& fromTimeStamp, const QDateTime& toTimeStamp, int numDates )
|
|
{
|
|
if ( numDates < 2 ) return {};
|
|
|
|
// Calculate the time step between the two time stamps
|
|
qint64 timeStep = ( toTimeStamp.toMSecsSinceEpoch() - fromTimeStamp.toMSecsSinceEpoch() ) / ( static_cast<qint64>( numDates ) - 1 );
|
|
|
|
// Create a set of evenly spaced datetimes.
|
|
std::set<QDateTime> outputDates;
|
|
for ( int i = 0; i < numDates; ++i )
|
|
{
|
|
qint64 targetTime = i * timeStep;
|
|
outputDates.insert( RiaQDateTimeTools::addMSecs( fromTimeStamp, targetTime ) );
|
|
}
|
|
|
|
return outputDates;
|
|
}
|