From 5def408547a2c258a4f5aa5a2364b3cc54417812 Mon Sep 17 00:00:00 2001 From: vcloarec Date: Tue, 10 Dec 2019 00:22:51 -0400 Subject: [PATCH] [WIP] severals modification in duration/DateTime and implementation in some formats --- mdal/CMakeLists.txt | 2 + mdal/frmts/mdal_3di.cpp | 2 +- mdal/frmts/mdal_ascii_dat.cpp | 4 +- mdal/frmts/mdal_binary_dat.cpp | 26 +-- mdal/frmts/mdal_cf.cpp | 103 +++++++-- mdal/frmts/mdal_cf.hpp | 6 +- mdal/frmts/mdal_driver.cpp | 2 +- mdal/frmts/mdal_driver.hpp | 2 +- mdal/frmts/mdal_flo2d.cpp | 11 +- mdal/frmts/mdal_hec2d.cpp | 19 +- mdal/frmts/mdal_selafin.cpp | 4 +- mdal/frmts/mdal_sww.cpp | 4 +- mdal/mdal.cpp | 3 +- mdal/mdal_data_model.cpp | 290 ----------------------- mdal/mdal_data_model.hpp | 132 +---------- mdal/mdal_date_time.cpp | 406 +++++++++++++++++++++++++++++++++ mdal/mdal_date_time.hpp | 141 ++++++++++++ mdal/mdal_utils.cpp | 55 ++++- mdal/mdal_utils.hpp | 4 +- tests/test_flo2d.cpp | 2 +- tests/test_hec2d.cpp | 2 +- tests/test_tuflowfv.cpp | 6 +- 22 files changed, 728 insertions(+), 498 deletions(-) create mode 100644 mdal/mdal_date_time.cpp create mode 100644 mdal/mdal_date_time.hpp diff --git a/mdal/CMakeLists.txt b/mdal/CMakeLists.txt index 6c0d5bea..42df6783 100644 --- a/mdal/CMakeLists.txt +++ b/mdal/CMakeLists.txt @@ -6,6 +6,7 @@ SET(MDAL_SOURCES mdal_utils.cpp mdal_driver_manager.cpp mdal_data_model.cpp + mdal_date_time.cpp mdal_memory_data_model.cpp frmts/mdal_driver.cpp frmts/mdal_2dm.cpp @@ -20,6 +21,7 @@ SET(MDAL_HEADERS mdal_utils.hpp mdal_driver_manager.hpp mdal_data_model.hpp + mdal_date_time.hpp mdal_memory_data_model.hpp frmts/mdal_driver.hpp frmts/mdal_2dm.hpp diff --git a/mdal/frmts/mdal_3di.cpp b/mdal/frmts/mdal_3di.cpp index c3848179..29b1a5ab 100644 --- a/mdal/frmts/mdal_3di.cpp +++ b/mdal/frmts/mdal_3di.cpp @@ -139,7 +139,7 @@ void MDAL::Driver3Di::addBedElevation( MemoryMesh *mesh ) group->setIsScalar( true ); std::shared_ptr dataset = std::make_shared< MemoryDataset2D >( group.get() ); - dataset->setTime( 0.0 ); + dataset->setTime( MDAL::Duration() ); double *values = dataset->values(); for ( size_t i = 0; i < faceCount; ++i ) { diff --git a/mdal/frmts/mdal_ascii_dat.cpp b/mdal/frmts/mdal_ascii_dat.cpp index 95dc66f9..5a38973e 100644 --- a/mdal/frmts/mdal_ascii_dat.cpp +++ b/mdal/frmts/mdal_ascii_dat.cpp @@ -253,7 +253,7 @@ void MDAL::DriverAsciiDat::loadNewFormat( } else if ( cardType == "RT_JULIAN" && items.size() >= 2 ) { - referenceTime = MDAL::DateTime::fromJulianDay( MDAL::toDouble( items[1] ) ); + referenceTime = MDAL::DateTime( MDAL::toDouble( items[1] ) ); } else if ( cardType == "TIMEUNITS" && items.size() >= 2 ) { @@ -268,7 +268,7 @@ void MDAL::DriverAsciiDat::loadNewFormat( else if ( cardType == "TS" && items.size() >= 3 ) { double rawTime = toDouble( items[2] ); - MDAL::Duration t = convertTimeData( rawTime, group->getMetadata( "TIMEUNITS" ) ); + MDAL::Duration t( rawTime, MDAL::parseUnitTime( group->getMetadata( "TIMEUNITS" ) ) ); if ( faceCentered ) { diff --git a/mdal/frmts/mdal_binary_dat.cpp b/mdal/frmts/mdal_binary_dat.cpp index a496a4e3..2c1cf076 100644 --- a/mdal/frmts/mdal_binary_dat.cpp +++ b/mdal/frmts/mdal_binary_dat.cpp @@ -78,26 +78,6 @@ static bool readIStat( std::ifstream &in, int sflg, char *flag ) return false; } -static MDAL::Duration convertTimeData( double time, const std::string &originalTimeDataUnit ) -{ - MDAL::Duration::Unit unit = MDAL::Duration::hours; - - if ( originalTimeDataUnit == "seconds" ) - { - unit = MDAL::Duration::seconds; - } - else if ( originalTimeDataUnit == "minutes" ) - { - unit = MDAL::Duration::minutes; - } - else if ( originalTimeDataUnit == "days" ) - { - unit = MDAL::Duration::days; - } - - return MDAL::Duration( time, unit ); -} - MDAL::DriverBinaryDat::DriverBinaryDat(): Driver( "BINARY_DAT", "Binary DAT", @@ -271,7 +251,7 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh, return exit_with_error( status, MDAL_Status::Err_UnknownFormat, "unable to read reference time" ); referenceTime = static_cast( time ); - group->setReferenceTime( DateTime::fromJulianDay( referenceTime ) ); + group->setReferenceTime( DateTime( referenceTime ) ); break; case CT_TIMEUNITS: @@ -309,7 +289,7 @@ void MDAL::DriverBinaryDat::load( const std::string &datFile, MDAL::Mesh *mesh, return exit_with_error( status, MDAL_Status::Err_UnknownFormat, "Invalid time step" ); double rawTime = static_cast( time ); - MDAL::Duration t = convertTimeData( rawTime, timeUnitStr ); + MDAL::Duration t( rawTime, MDAL::parseUnitTime( timeUnitStr ) ); if ( readVertexTimestep( mesh, group, groupMax, t, istat, sflg, in ) ) return exit_with_error( status, MDAL_Status::Err_UnknownFormat, "Unable to read vertex timestep" ); @@ -394,7 +374,7 @@ bool MDAL::DriverBinaryDat::readVertexTimestep( const MDAL::Mesh *mesh, } else { - dataset->setTime( time ); // TODO read TIMEUNITS + dataset->setTime( time ); dataset->setStatistics( MDAL::calculateStatistics( dataset ) ); group->datasets.push_back( dataset ); } diff --git a/mdal/frmts/mdal_cf.cpp b/mdal/frmts/mdal_cf.cpp index 80b46eba..39b9346b 100644 --- a/mdal/frmts/mdal_cf.cpp +++ b/mdal/frmts/mdal_cf.cpp @@ -161,7 +161,78 @@ static void populate_vals( bool is_vector, double *vals, size_t i, } } -void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vector ×, const MDAL::cfdataset_info_map &dsinfo_map ) +static MDAL::DateTime parseReferenceTime( std::string timeInformation, std::string calendar ) +{ + auto strings = MDAL::split( timeInformation, ' ' ); + if ( strings.size() < 3 ) + return MDAL::DateTime(); + + if ( strings[1] != "since" ) + return MDAL::DateTime(); + + std::string dateString = strings[2]; + + auto dateStringValues = MDAL::split( dateString, '-' ); + if ( dateStringValues.size() != 3 ) + return MDAL::DateTime(); + + int year = MDAL::toInt( dateStringValues[0] ); + int month = MDAL::toInt( dateStringValues[1] ); + int day = MDAL::toInt( dateStringValues[2] ); + + int hours = 0; + int minutes = 0; + double seconds = 0; + + if ( strings.size() > 3 ) + { + std::string timeString = strings[3]; + auto timeStringsValue = MDAL::split( timeString, ":" ); + if ( timeStringsValue.size() == 3 ) + { + hours = MDAL::toInt( timeStringsValue[0] ); + minutes = MDAL::toInt( timeStringsValue[0] ); + seconds = MDAL::toDouble( timeStringsValue[0] ); + } + } + + if ( calendar == "gregorian" || calendar == "standard" || calendar.empty() ) + return MDAL::DateTime( year, month, day, hours, minutes, seconds ); + + return MDAL::DateTime(); + +} + +static MDAL::Duration::Unit parseUnitCFTime( std::string timeInformation ) +{ + auto strings = MDAL::split( timeInformation, ' ' ); + if ( strings.size() < 3 ) + return MDAL::Duration::hours; //default value + + if ( strings[1] == "since" ) + { + std::string timeUnit = strings[0]; + if ( timeUnit == "month" || + timeUnit == "months" || + timeUnit == "mon" || + timeUnit == "mons" ) + { + return MDAL::Duration::months_CF; + } + else if ( timeUnit == "year" || + timeUnit == "years" || + timeUnit == "yr" || + timeUnit == "yrs" ) + { + return MDAL::Duration::exact_years; + } + return MDAL::parseUnitTime( strings[0] ); + } + + return MDAL::Duration::hours;//default value +} + +void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vector ×, const MDAL::cfdataset_info_map &dsinfo_map, const MDAL::DateTime &referenceTime ) { /* PHASE 2 - add dataset groups */ for ( const auto &it : dsinfo_map ) @@ -203,7 +274,6 @@ void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vector dataset; - double time = times[ts]; if ( dsi.outputType == CFDimensions::Volume3D ) { dataset = create3DDataset( @@ -220,7 +290,7 @@ void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vectorsetTime( time ); + dataset->setTime( times[ts] ); group->datasets.push_back( dataset ); } } @@ -234,7 +304,7 @@ void MDAL::DriverCF::addDatasetGroups( MDAL::Mesh *mesh, const std::vector × ) +MDAL::DateTime MDAL::DriverCF::parseTime( std::vector × ) { size_t nTimesteps = mDimensions.size( CFDimensions::Time ); @@ -242,17 +312,24 @@ void MDAL::DriverCF::parseTime( std::vector × ) { //if no time dimension is present creates only one time step to store the potential time-independent variable nTimesteps = 1; - times = std::vector( 1, 0 ); - return; + times = std::vector( 1, Duration() ); + return MDAL::DateTime(); } const std::string timeArrName = getTimeVariableName(); - times = mNcFile->readDoubleArr( timeArrName, nTimesteps ); - std::string units = mNcFile->getAttrStr( timeArrName, "units" ); - double div_by = MDAL::parseTimeUnits( units ); + std::vector rawTimes = mNcFile->readDoubleArr( timeArrName, nTimesteps ); + + std::string timeUnitInformation = mNcFile->getAttrStr( timeArrName, "units" ); + std::string calendar = mNcFile->getAttrStr( timeArrName, "calendar" ); + MDAL::DateTime referenceTime = parseReferenceTime( timeUnitInformation, calendar ); + MDAL::Duration::Unit unit = parseUnitCFTime( timeUnitInformation ); + + times = std::vector( nTimesteps ); for ( size_t i = 0; i < nTimesteps; ++i ) { - times[i] /= div_by; + times[i] = Duration( rawTimes[i], unit ); } + + return referenceTime; } std::shared_ptr MDAL::DriverCF::create2DDataset( std::shared_ptr group, size_t ts, const MDAL::CFDatasetGroupInfo &dsi, double fill_val_x, double fill_val_y ) @@ -356,7 +433,7 @@ std::unique_ptr< MDAL::Mesh > MDAL::DriverCF::load( const std::string &fileName, if ( status ) *status = MDAL_Status::None; //Dimensions dims; - std::vector times; + std::vector times; try { @@ -386,13 +463,13 @@ std::unique_ptr< MDAL::Mesh > MDAL::DriverCF::load( const std::string &fileName, setProjection( mesh.get() ); // Parse time array - parseTime( times ); + MDAL::DateTime referenceTime = parseTime( times ); // Parse dataset info cfdataset_info_map dsinfo_map = parseDatasetGroupInfo(); // Create datasets - addDatasetGroups( mesh.get(), times, dsinfo_map ); + addDatasetGroups( mesh.get(), times, dsinfo_map, referenceTime ); return std::unique_ptr( mesh.release() ); } diff --git a/mdal/frmts/mdal_cf.hpp b/mdal/frmts/mdal_cf.hpp index 34095ef8..0762773e 100644 --- a/mdal/frmts/mdal_cf.hpp +++ b/mdal/frmts/mdal_cf.hpp @@ -132,10 +132,10 @@ namespace MDAL void setProjection( MDAL::Mesh *m ); cfdataset_info_map parseDatasetGroupInfo(); - void parseTime( std::vector × ); + DateTime parseTime( std::vector × ); //Return the reference time void addDatasetGroups( Mesh *mesh, - const std::vector ×, - const cfdataset_info_map &dsinfo_map ); + const std::vector ×, + const cfdataset_info_map &dsinfo_map, const DateTime &referenceTime ); std::string mFileName; std::shared_ptr mNcFile; diff --git a/mdal/frmts/mdal_driver.cpp b/mdal/frmts/mdal_driver.cpp index 7bab31aa..a69368f9 100644 --- a/mdal/frmts/mdal_driver.cpp +++ b/mdal/frmts/mdal_driver.cpp @@ -82,7 +82,7 @@ void MDAL::Driver::createDatasetGroup( MDAL::Mesh *mesh, const std::string &grou mesh->datasetGroups.push_back( grp ); } -void MDAL::Driver::createDataset( MDAL::DatasetGroup *group, double time, const double *values, const int *active ) +void MDAL::Driver::createDataset( MDAL::DatasetGroup *group, MDAL::Duration time, const double *values, const int *active ) { std::shared_ptr dataset = std::make_shared< MemoryDataset2D >( group ); dataset->setTime( time ); diff --git a/mdal/frmts/mdal_driver.hpp b/mdal/frmts/mdal_driver.hpp index d250a253..7b6a1e7d 100644 --- a/mdal/frmts/mdal_driver.hpp +++ b/mdal/frmts/mdal_driver.hpp @@ -64,7 +64,7 @@ namespace MDAL // create new dataset from array virtual void createDataset( DatasetGroup *group, - double time, + Duration time, const double *values, const int *active ); diff --git a/mdal/frmts/mdal_flo2d.cpp b/mdal/frmts/mdal_flo2d.cpp index 6a4158ba..bf621c1b 100644 --- a/mdal/frmts/mdal_flo2d.cpp +++ b/mdal/frmts/mdal_flo2d.cpp @@ -89,7 +89,7 @@ void MDAL::DriverFlo2D::addStaticDataset( std::shared_ptr dataset = std::make_shared< MemoryDataset2D >( group.get() ); assert( vals.size() == dataset->valuesCount() ); - dataset->setTime( 0.0 ); + dataset->setTime( MDAL::Duration() ); double *values = dataset->values(); memcpy( values, vals.data(), vals.size() * sizeof( double ) ); dataset->setStatistics( MDAL::calculateStatistics( dataset ) ); @@ -187,7 +187,7 @@ void MDAL::DriverFlo2D::parseTIMDEPFile( const std::string &datFileName, const s size_t nVertexs = mMesh->verticesCount(); size_t ntimes = 0; - double time = 0.0; + Duration time = Duration(); size_t face_idx = 0; std::shared_ptr depthDsGroup = std::make_shared< DatasetGroup >( @@ -228,7 +228,7 @@ void MDAL::DriverFlo2D::parseTIMDEPFile( const std::string &datFileName, const s std::vector lineParts = MDAL::split( line, ' ' ); if ( lineParts.size() == 1 ) { - time = MDAL::toDouble( line ); + time = Duration( MDAL::toDouble( line ), Duration::hours ); ntimes++; if ( depthDataset ) addDatasetToGroup( depthDsGroup, depthDataset ); @@ -530,9 +530,14 @@ bool MDAL::DriverFlo2D::parseHDF5Datasets( MemoryMesh *mesh, const std::string & HdfGroup grp = timedataGroup.group( grpName ); if ( !grp.isValid() ) return true; + auto g = grp.objects(); + HdfAttribute groupType = grp.attribute( "Grouptype" ); if ( !groupType.isValid() ) return true; + HdfAttribute timeUnitAttribute = grp.attribute( "TimeUnits" ); + std::string timeUnitString = timeUnitAttribute.readString(); + /* Min and Max arrays in TIMDEP.HDF5 files have dimensions 1xntimesteps . HdfDataset minDs = grp.dataset("Mins"); if (!minDs.isValid()) return true; diff --git a/mdal/frmts/mdal_hec2d.cpp b/mdal/frmts/mdal_hec2d.cpp index 6df7fc4e..c1b61046 100644 --- a/mdal/frmts/mdal_hec2d.cpp +++ b/mdal/frmts/mdal_hec2d.cpp @@ -99,19 +99,6 @@ static std::string getDataTimeUnit( HdfDataset &dsTime ) return dataTimeUnit; } -static void convertTimeDataToHours( std::vector ×, const std::string &originalTimeDataUnit ) -{ - if ( originalTimeDataUnit != "Hours" ) - { - for ( size_t i = 0; i < times.size(); i++ ) - { - if ( originalTimeDataUnit == "Seconds" ) { times[i] /= 3600.0f; } - else if ( originalTimeDataUnit == "Minutes" ) { times[i] /= 60.0f; } - else if ( originalTimeDataUnit == "Days" ) { times[i] *= 24; } - } - } -} - static std::vector convertTimeData( std::vector ×, const std::string &originalTimeDataUnit ) { std::vector convertedTime( times.size() ); @@ -143,7 +130,7 @@ static MDAL::DateTime convertToDateTime( const std::string strDateTime ) { auto data = MDAL::split( strDateTime, " " ); if ( data.size() < 2 ) - return MDAL::DateTime::fromDefault(); + return MDAL::DateTime(); std::string dateStr = data[0]; @@ -199,7 +186,7 @@ static MDAL::DateTime convertToDateTime( const std::string strDateTime ) sec = MDAL::toDouble( timeData[2] ); } - return MDAL::DateTime::fromStandartValue( year, month, day, hours, min, sec ); + return MDAL::DateTime( year, month, day, hours, min, sec ); } static std::string readReferenceTime( const HdfFile &hdfFile ) @@ -226,7 +213,7 @@ static MDAL::DateTime readReferenceDateTime( const HdfFile &hdfFile ) if ( timeStamps.size() > 0 ) return convertToDateTime( timeStamps[0] ); - return MDAL::DateTime::fromDefault(); + return MDAL::DateTime(); } static std::vector readTimes( const HdfFile &hdfFile ) diff --git a/mdal/frmts/mdal_selafin.cpp b/mdal/frmts/mdal_selafin.cpp index 7ea9c3b5..36a57830 100644 --- a/mdal/frmts/mdal_selafin.cpp +++ b/mdal/frmts/mdal_selafin.cpp @@ -293,7 +293,7 @@ void MDAL::DriverSelafin::parseFile( std::vector &var_names, if ( params[9] == 1 ) { std::vector datetime = mReader.read_int_arr( 6 ); - MDAL_UNUSED( datetime ) + DateTime referenceTime( datetime[0], datetime[1], datetime[2], datetime[3], datetime[4], double( datetime[5] ) ); } /* 1 record containing the integers NELEM,NPOIN,NDP,1 (number of @@ -476,7 +476,7 @@ void MDAL::DriverSelafin::addData( const std::vector &var_names, co else { dataset = std::make_shared< MemoryDataset2D >( group.get() ); - dataset->setTime( it->first ); + dataset->setTime( it->first, Duration::seconds ); //seems that time unit in this format is only seconds group->datasets.push_back( dataset ); } double *values = dataset->values(); diff --git a/mdal/frmts/mdal_sww.cpp b/mdal/frmts/mdal_sww.cpp index 5357ce9e..097e65bc 100644 --- a/mdal/frmts/mdal_sww.cpp +++ b/mdal/frmts/mdal_sww.cpp @@ -299,7 +299,7 @@ std::shared_ptr MDAL::DriverSWW::readScalarGroup( { // TIME INDEPENDENT std::shared_ptr o = std::make_shared( mds.get() ); - o->setTime( 0.0 ); + o->setTime( Duration() ); double *values = o->values(); std::vector valuesX = ncFile.readDoubleArr( arrName, nPoints ); for ( size_t i = 0; i < nPoints; ++i ) @@ -315,7 +315,7 @@ std::shared_ptr MDAL::DriverSWW::readScalarGroup( for ( size_t t = 0; t < times.size(); ++t ) { std::shared_ptr mto = std::make_shared( mds.get() ); - mto->setTime( static_cast( times[t] ) / 3600. ); + mto->setTime( static_cast( times[t] ), Duration::seconds ); //time is always in seconds double *values = mto->values(); // fetching data for one timestep diff --git a/mdal/mdal.cpp b/mdal/mdal.cpp index 633a4aee..6b3f8b1c 100644 --- a/mdal/mdal.cpp +++ b/mdal/mdal.cpp @@ -673,8 +673,9 @@ DatasetH MDAL_G_addDataset( DatasetGroupH group, double time, const double *valu } const size_t index = g->datasets.size(); + MDAL::Duration t( time, MDAL::Duration::hours ); dr->createDataset( g, - time, + t, values, active ); diff --git a/mdal/mdal_data_model.cpp b/mdal/mdal_data_model.cpp index df291642..54623433 100644 --- a/mdal/mdal_data_model.cpp +++ b/mdal/mdal_data_model.cpp @@ -337,293 +337,3 @@ size_t MDAL::Mesh::faceVerticesMaximumCount() const MDAL::MeshVertexIterator::~MeshVertexIterator() = default; MDAL::MeshFaceIterator::~MeshFaceIterator() = default; - - - -MDAL::DateTime MDAL::DateTime::fromStandartValue( int year, int month, int day, int hours, int minutes, double seconds ) -{ - DateTime dateTime; - if ( month > 0 && day > 0 && hours >= 0 && minutes >= 0 && seconds >= 0 ) - { - dateTime.mValid = true; - DateTimeValues values{year, month, day, hours, minutes, seconds}; - dateTime.setWithGregorianJulianCalendarValues( values ); - } - - return dateTime; -} - -std::string MDAL::DateTime::toStandartCalendarISO8601() const -{ - DateTimeValues value = dateTimeGregorianJulianCalendar(); - if ( mValid ) - return toString( value ); - else - return "none"; -} - -double MDAL::DateTime::toJulianDay() const -{ - return mJulianTime / 24.0 / 3600 / 1000; -} - -MDAL::DateTime &MDAL::DateTime::operator=( const MDAL::DateTime &other ) -{ - mJulianTime = other.mJulianTime; - mValid = other.mValid; - return *this; -} - -MDAL::DateTime MDAL::DateTime::operator+( const MDAL::Duration &duration ) const -{ - if ( !mValid ) - return DateTime(); - return DateTime( mJulianTime + duration.mDuration ); -} - -MDAL::DateTime &MDAL::DateTime::operator+=( const MDAL::Duration &duration ) -{ - if ( !mValid ) - return *this; - mJulianTime += duration.mDuration; - return *this; -} - -MDAL::DateTime &MDAL::DateTime::operator-=( const MDAL::Duration &duration ) -{ - if ( !mValid ) - return *this; - mJulianTime -= duration.mDuration; - return *this; -} - -MDAL::DateTime MDAL::DateTime::operator-( const MDAL::Duration &duration ) const -{ - if ( !mValid ) - return DateTime(); - return DateTime( mJulianTime - duration.mDuration ); -} - -bool MDAL::DateTime::operator==( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return true; - - return ( mValid && other.mValid ) && ( mJulianTime == other.mJulianTime ); -} - -bool MDAL::DateTime::operator!=( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return true; - - return !operator==( other ); -} - -bool MDAL::DateTime::operator<( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return false; - return ( mValid && other.mValid ) && ( mJulianTime < other.mJulianTime ); -} - -bool MDAL::DateTime::operator>( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return false; - return ( mValid && other.mValid ) && ( mJulianTime > other.mJulianTime ); -} - -bool MDAL::DateTime::operator>=( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return true; - return ( mValid && other.mValid ) && ( mJulianTime >= other.mJulianTime ); -} - -bool MDAL::DateTime::operator<=( const MDAL::DateTime &other ) const -{ - if ( !mValid && !other.mValid ) - return true; - return ( mValid && other.mValid ) && ( mJulianTime <= other.mJulianTime ); -} - -MDAL::DateTime::DateTime( int64_t julianTime ): mJulianTime( julianTime ) -{} - -MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianJulianCalendar() const -{ - //https://fr.wikipedia.org/wiki/Jour_julien - DateTimeValues values; - int Z = int( mJulianTime / 24.0 / 3600 / 1000 + 0.5 ); //integer part of julian days count - double F = mJulianTime / 24.0 / 3600 / 1000 + 0.5 - Z; //fractional part of julian days count; - int S; - if ( Z < 2299161 ) - S = Z; - else - { - int alpha = int( ( Z - 1867216.25 ) / 36524.25 ); - S = Z + 1 + alpha - int( alpha / 4 ); - } - - int B = S + 1524; - int C = int( ( B - 122.1 ) / 365.25 ); - int D = int( 365.25 * C ); - int E = int( ( B - D ) / 30.6001 ); - - values.day = B - D - int( 30.6001 * E ); - if ( E < 14 ) - values.month = E - 1; - else - values.month = E - 13; - - if ( values.month > 2 ) - values.year = C - 4716; - else - values.year = C - 4715; - - values.hours = int( F * 24 ); - F = F / 24 - values.hours; - values.minutes = int( F * 60 ); - F = F / 60 - values.minutes; - values.seconds = F * 60; - - return values; -} - -void MDAL::DateTime::setWithGregorianCalendarDate( MDAL::DateTime::DateTimeValues values ) -{ - //https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html - if ( values.month <= 2 ) - { - values.year--; - values.month += 12; - } - - int A = values.year / 100; - int B = A / 4; - int C = 2 - A + B; - int E = int( 365.25 * ( values.year + 4716 ) ); - int F = int( 30.6001 * ( values.month + 1 ) ); - double julianDay = C + values.day + E + F - 1524.5; - - mJulianTime = int64_t( julianDay * 24 * 3600 * 1000 + - ( values.hours ) * 3600 * 1000 + //the formula set the day with hours at 00h - values.minutes * 60 * 1000 + - values.seconds * 1000 ); -} - -void MDAL::DateTime::setWithGregorianJulianCalendarValues( MDAL::DateTime::DateTimeValues values ) -{ - //https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html - - int C = 0; - int Y = values.year; - int M = values.month; - int D = values.day; - if ( M <= 2 ) - { - Y--; - M += 12; - } - if ( values.year > 1582 || - ( values.year == 1582 && ( values.month > 10 || ( values.month == 10 && values.day >= 15 ) ) ) ) //gregorian calendar - { - int A = Y / 100; - int B = A / 4; - C = 2 - A + B; - } - - int E = int( 365.25 * ( Y + 4716 ) ); - int F = int( 30.6001 * ( M + 1 ) ); - double julianDay = C + D + E + F - 1524.5; - - mJulianTime = int64_t( julianDay * 24 * 3600 * 1000 + - ( values.hours ) * 3600 * 1000 + //the formula set the day with hours at 00h - values.minutes * 60 * 1000 + - values.seconds * 1000 ); -} - -std::string MDAL::DateTime::toString( MDAL::DateTime::DateTimeValues values ) const -{ - std::string yearStr = std::to_string( values.year ); - - int miliseconds = int( ( values.seconds - int( values.seconds ) ) * 1000 + 0.5 ); - std::string msStr; - if ( miliseconds > 0 ) - { - if ( miliseconds < 10 ) - msStr = prependZero( std::to_string( miliseconds ), 3 ); - else if ( miliseconds < 100 ) - msStr = prependZero( std::to_string( miliseconds ), 2 ); - - msStr = std::string( "," ).append( msStr ); - } - - std::string strDateTime = prependZero( std::to_string( values.year ), 4 ) + "-" + - prependZero( std::to_string( values.month ), 2 ) + "-" + - prependZero( std::to_string( values.day ), 2 ) + "T" + - prependZero( std::to_string( values.hours ), 2 ) + ":" + - prependZero( std::to_string( values.minutes ), 2 ) + ":" + - prependZero( std::to_string( int( values.seconds ) ), 2 ) + - msStr; /// TODO use another way to translate seconds with fraction aprt - - return strDateTime; -} - -MDAL::Duration MDAL::DateTime::operator-( const MDAL::DateTime &other ) const -{ - if ( !mValid || !other.mValid ) - return Duration(); - return Duration( mJulianTime - other.mJulianTime ); -} - -MDAL::Duration::Duration(): mDuration( 0 ) -{} - -MDAL::Duration::Duration( double duration, MDAL::Duration::Unit unit ) -{ - switch ( unit ) - { - case MDAL::Duration::milliseconds: - mDuration = int64_t( duration ); - break; - case MDAL::Duration::seconds: - mDuration = int64_t( duration * 1000 ); - break; - case MDAL::Duration::minutes: - mDuration = int64_t( duration * 60 * 1000 ); - break; - case MDAL::Duration::hours: - mDuration = int64_t( duration * 60 * 60 * 1000 ); - break; - case MDAL::Duration::days: - mDuration = int64_t( duration * 24 * 60 * 60 * 1000 ); - break; - case MDAL::Duration::weeks: - mDuration = int64_t( duration * 7 * 24 * 60 * 60 * 1000 ); - break; - } -} - -double MDAL::Duration::value( MDAL::Duration::Unit unit ) const -{ - switch ( unit ) - { - case MDAL::Duration::milliseconds: - return double( mDuration ); - case MDAL::Duration::seconds: - return double( mDuration ) / 1000 ; - case MDAL::Duration::minutes: - return double( mDuration ) / 60 / 1000 ; - case MDAL::Duration::hours: - return double( mDuration ) / 60 / 60 / 1000 ; - case MDAL::Duration::days: - return double( mDuration ) / 24 / 60 / 60 / 1000 ; - case MDAL::Duration::weeks: - return double( mDuration ) / 7 / 24 / 60 / 60 / 1000; - } -} - -MDAL::Duration::Duration( int64_t ms ): mDuration( ms ) -{} diff --git a/mdal/mdal_data_model.hpp b/mdal/mdal_data_model.hpp index f2010780..8ab71726 100644 --- a/mdal/mdal_data_model.hpp +++ b/mdal/mdal_data_model.hpp @@ -13,6 +13,7 @@ #include #include #include "mdal.h" +#include "mdal_date_time.hpp" namespace MDAL { @@ -38,137 +39,6 @@ namespace MDAL typedef std::vector< std::pair< std::string, std::string > > Metadata; - class DateTime; - - class Duration - { - public: - enum Unit - { - milliseconds = 0, - seconds, - minutes, - hours, - days, - weeks - }; - - Duration(); - - ///TODO : implementation of operator, copy constructor, copy assignment, move operation - - Duration( double duration, Unit unit ); - - double value( Unit unit ) const; - - private: - Duration( int64_t ms ); - int64_t mDuration; //in ms - - friend class DateTime; - }; - - class DateTime - { - public: - - //! Defaul constructor - DateTime(): mValid( false ) - {} - //! Copy constructor - DateTime( const DateTime &other ): mJulianTime( other.mJulianTime ) - {} - - //static method returning DateTime - - //! Create an instance from gregorian/julian calendar (or standart) - static DateTime fromStandartValue( int year, int month, int day, int hours = 0, int minutes = 0, double seconds = 0 ); - - //! Create an instance from julian day - static DateTime fromJulianDay( double julianDay ) - { - return DateTime( int64_t( julianDay * 24 * 3600 * 1000 ) ); - } - - //! Create an default instance - static DateTime fromDefault() - { - return DateTime(); - } - - //! Returns a string with the date/time expressed in Greogrian/Julian calendar with ISO8601 format (local time zone) - std::string toStandartCalendarISO8601() const; - - //! Returns the Julian day value - double toJulianDay() const; - - //! Returns the Julain day value expressed with a string - std::string toJulianDayString() const - { - return std::to_string( toJulianDay() ); ///TODO : maybe change the precison - } - - //! operators - DateTime &operator=( const DateTime &other ); - Duration operator-( const DateTime &other ) const; - DateTime operator+( const Duration &duration ) const; - DateTime &operator+=( const Duration &duration ); - DateTime &operator-=( const Duration &duration ); - DateTime operator-( const Duration &duration ) const; - bool operator==( const DateTime &other ) const; - bool operator!=( const DateTime &other ) const; - bool operator<( const DateTime &other ) const; - bool operator>( const DateTime &other ) const; - bool operator>=( const DateTime &other ) const; - bool operator<=( const DateTime &other ) const; - - private: - - struct DateTimeValues - { - int year; - int month; - int day; - int hours; - int minutes; - double seconds; - }; - - DateTime( int64_t julianTime ); - - DateTimeValues dateTimeGregorianJulianCalendar() const; - - void setWithGregorianCalendarDate( DateTimeValues values ); - void setWithGregorianJulianCalendarValues( DateTimeValues values ); - void setWithJulianCalendarDate( DateTimeValues values ) - { - ///TODO - } - void setWith365dayCalendarDate( DateTimeValues values ) - { - ///TODO - } - void setWith366dayCalendarDate( DateTimeValues values ) - { - ///TODO - } - void setWith360dayCalendarDate( DateTimeValues values ) - { - ///TODO - } - void setWithNonStandartCalendarDate( DateTimeValues values, std::vector month_lengths, int leap_year, int leap_month ) - { - ///TODO - } - - std::string toString( DateTimeValues values ) const; - - int64_t mJulianTime; //Julian day in ms - - bool mValid = true; - }; - - class Dataset { public: diff --git a/mdal/mdal_date_time.cpp b/mdal/mdal_date_time.cpp new file mode 100644 index 00000000..b3b52b5e --- /dev/null +++ b/mdal/mdal_date_time.cpp @@ -0,0 +1,406 @@ +#include "mdal_date_time.hpp" +#include "mdal_utils.hpp" + + +constexpr double MILLISECONDS_IN_SECOND = 1000; +constexpr double MILLISECONDS_IN_MINUTE = 1000 * 60; +constexpr double MILLISECONDS_IN_HOUR = 1000 * 60 * 60; +constexpr double MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24; +constexpr double MILLISECONDS_IN_WEEK = 1000 * 60 * 60 * 24 * 7; + +//https://www.unidata.ucar.edu/software/netcdf-java/current/CDM/CalendarDateTime.html +constexpr double MILLISECONDS_IN_EXACT_YEAR = 3.15569259747e10; //CF Compliant +constexpr double MILLISECONDS_IN_MONTH_CF = MILLISECONDS_IN_EXACT_YEAR / 12; //CF Compliant + +constexpr double SECONDS_IN_DAY = 60 * 60 * 24; +constexpr double MINUTES_IN_DAY = 60 * 24; +constexpr double HOURS_IN_DAY = 24; + + +MDAL::DateTime::DateTime(): mValid( false ) +{} + +MDAL::DateTime::DateTime( const MDAL::DateTime &other ): mJulianTime( other.mJulianTime ) +{} + +MDAL::DateTime::DateTime( int year, int month, int day, int hours, int minutes, double seconds, MDAL::DateTime::Calendar calendar ) +{ + DateTimeValues value{year, month, day, hours, minutes, seconds}; + + switch ( calendar ) + { + case MDAL::DateTime::Gregorian: + setWithGregorianJulianCalendarDate( value ); + break; + case MDAL::DateTime::Gregorian_proleptic: + setWithGregorianCalendarDate( value ); + break; + case MDAL::DateTime::Julian: + setWithJulianCalendarDate( value ); + break; + } +} + +MDAL::DateTime::DateTime( double julianDay ): + mJulianTime( int64_t( julianDay * MILLISECONDS_IN_DAY ) ), + mValid( true ) +{ +} + +std::string MDAL::DateTime::toStandartCalendarISO8601() const +{ + DateTimeValues value = dateTimeGregorianJulianCalendar(); + if ( mValid ) + return toString( value ); + else + return "none"; +} + +double MDAL::DateTime::toJulianDay() const +{ + return mJulianTime / MILLISECONDS_IN_DAY; +} + +std::string MDAL::DateTime::toJulianDayString() const +{ + return std::to_string( toJulianDay() ); ///TODO : maybe change the precison +} + +MDAL::DateTime &MDAL::DateTime::operator=( const MDAL::DateTime &other ) +{ + mJulianTime = other.mJulianTime; + mValid = other.mValid; + return *this; +} + +MDAL::DateTime MDAL::DateTime::operator+( const MDAL::Duration &duration ) const +{ + if ( !mValid ) + return DateTime(); + return DateTime( mJulianTime + duration.mDuration ); +} + +MDAL::DateTime &MDAL::DateTime::operator+=( const MDAL::Duration &duration ) +{ + if ( !mValid ) + return *this; + mJulianTime += duration.mDuration; + return *this; +} + +MDAL::DateTime &MDAL::DateTime::operator-=( const MDAL::Duration &duration ) +{ + if ( !mValid ) + return *this; + mJulianTime -= duration.mDuration; + return *this; +} + +MDAL::DateTime MDAL::DateTime::operator-( const MDAL::Duration &duration ) const +{ + if ( !mValid ) + return DateTime(); + return DateTime( mJulianTime - duration.mDuration ); +} + +bool MDAL::DateTime::operator==( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return true; + + return ( mValid && other.mValid ) && ( mJulianTime == other.mJulianTime ); +} + +bool MDAL::DateTime::operator!=( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return true; + + return !operator==( other ); +} + +bool MDAL::DateTime::operator<( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return false; + return ( mValid && other.mValid ) && ( mJulianTime < other.mJulianTime ); +} + +bool MDAL::DateTime::operator>( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return false; + return ( mValid && other.mValid ) && ( mJulianTime > other.mJulianTime ); +} + +bool MDAL::DateTime::operator>=( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return true; + return ( mValid && other.mValid ) && ( mJulianTime >= other.mJulianTime ); +} + +bool MDAL::DateTime::operator<=( const MDAL::DateTime &other ) const +{ + if ( !mValid && !other.mValid ) + return true; + return ( mValid && other.mValid ) && ( mJulianTime <= other.mJulianTime ); +} + +MDAL::DateTime::DateTime( int64_t julianTime ): mJulianTime( julianTime ) +{} + +MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianJulianCalendar() const +{ + //https://fr.wikipedia.org/wiki/Jour_julien + DateTimeValues values; + int Z = int( mJulianTime / MILLISECONDS_IN_DAY + 0.5 ); //integer part of julian days count + double F = mJulianTime / MILLISECONDS_IN_DAY + 0.5 - Z; //fractional part of julian days count; + int S; + if ( Z < 2299161 ) + S = Z; + else + { + int alpha = int( ( Z - 1867216.25 ) / 36524.25 ); + S = Z + 1 + alpha - int( alpha / 4 ); + } + + int B = S + 1524; + int C = int( ( B - 122.1 ) / 365.25 ); + int D = int( 365.25 * C ); + int E = int( ( B - D ) / 30.6001 ); + + values.day = B - D - int( 30.6001 * E ); + if ( E < 14 ) + values.month = E - 1; + else + values.month = E - 13; + + if ( values.month > 2 ) + values.year = C - 4716; + else + values.year = C - 4715; + + values.hours = int( F * HOURS_IN_DAY ); + F = F - values.hours / HOURS_IN_DAY; + values.minutes = int( F * MINUTES_IN_DAY ); + F = F - values.minutes / MINUTES_IN_DAY; + values.seconds = F * SECONDS_IN_DAY; + + return values; +} + +void MDAL::DateTime::setWithGregorianCalendarDate( MDAL::DateTime::DateTimeValues values ) +{ + //https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html + if ( values.month <= 2 ) + { + values.year--; + values.month += 12; + } + + int A = values.year / 100; + int B = A / 4; + int C = 2 - A + B; + int E = int( 365.25 * ( values.year + 4716 ) ); + int F = int( 30.6001 * ( values.month + 1 ) ); + double julianDay = C + values.day + E + F - 1524.5; + + mValid = true; + mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY + + ( values.hours ) * MILLISECONDS_IN_HOUR + //the formula set the day with hours at 00h + values.minutes * MILLISECONDS_IN_MINUTE + + values.seconds * MILLISECONDS_IN_SECOND ); +} + +void MDAL::DateTime::setWithJulianCalendarDate( MDAL::DateTime::DateTimeValues values ) +{ + //https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html + if ( values.month <= 2 ) + { + values.year--; + values.month += 12; + } + + int E = int( 365.25 * ( values.year + 4716 ) ); + int F = int( 30.6001 * ( values.month + 1 ) ); + double julianDay = values.day + E + F - 1524.5; + + mValid = true; + mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY + + ( values.hours ) * MILLISECONDS_IN_HOUR + //the formula set the day with hours at 00h + values.minutes * MILLISECONDS_IN_MINUTE + + values.seconds * MILLISECONDS_IN_SECOND ); +} + +void MDAL::DateTime::setWithGregorianJulianCalendarDate( MDAL::DateTime::DateTimeValues values ) +{ + //https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html + + mValid = true; + + if ( values.year > 1582 || + ( values.year == 1582 && ( values.month > 10 || ( values.month == 10 && values.day >= 15 ) ) ) ) //gregorian calendar + { + setWithGregorianCalendarDate( values ); + } + else + setWithJulianCalendarDate( values ); +} + +std::string MDAL::DateTime::toString( MDAL::DateTime::DateTimeValues values ) const +{ + std::string yearStr = std::to_string( values.year ); + + int miliseconds = int( ( values.seconds - int( values.seconds ) ) * 1000 + 0.5 ); + std::string msStr; + if ( miliseconds > 0 ) + { + if ( miliseconds < 10 ) + msStr = prependZero( std::to_string( miliseconds ), 3 ); + else if ( miliseconds < 100 ) + msStr = prependZero( std::to_string( miliseconds ), 2 ); + + msStr = std::string( "," ).append( msStr ); + } + + std::string strDateTime = prependZero( std::to_string( values.year ), 4 ) + "-" + + prependZero( std::to_string( values.month ), 2 ) + "-" + + prependZero( std::to_string( values.day ), 2 ) + "T" + + prependZero( std::to_string( values.hours ), 2 ) + ":" + + prependZero( std::to_string( values.minutes ), 2 ) + ":" + + prependZero( std::to_string( int( values.seconds ) ), 2 ) + + msStr; /// TODO use another way to translate seconds with fraction part + + return strDateTime; +} + +MDAL::Duration MDAL::DateTime::operator-( const MDAL::DateTime &other ) const +{ + if ( !mValid || !other.mValid ) + return Duration(); + return Duration( mJulianTime - other.mJulianTime ); +} + +MDAL::Duration::Duration(): mDuration( 0 ) +{} + +MDAL::Duration::Duration( double duration, MDAL::Duration::Unit unit ) +{ + switch ( unit ) + { + case MDAL::Duration::milliseconds: + mDuration = int64_t( duration ); + break; + case MDAL::Duration::seconds: + mDuration = int64_t( duration * MILLISECONDS_IN_SECOND ); + break; + case MDAL::Duration::minutes: + mDuration = int64_t( duration * MILLISECONDS_IN_MINUTE ); + break; + case MDAL::Duration::hours: + mDuration = int64_t( duration * MILLISECONDS_IN_HOUR ); + break; + case MDAL::Duration::days: + mDuration = int64_t( duration * MILLISECONDS_IN_DAY ); + break; + case MDAL::Duration::weeks: + mDuration = int64_t( duration * MILLISECONDS_IN_WEEK ); + break; + case MDAL::Duration::months_CF: + mDuration = int64_t( duration * MILLISECONDS_IN_MONTH_CF ); + break; + case MDAL::Duration::exact_years: + mDuration = int64_t( duration * MILLISECONDS_IN_EXACT_YEAR ); + break; + } +} + +MDAL::Duration::Duration( const MDAL::Duration &other ) +{ + mDuration = other.mDuration; +} + +double MDAL::Duration::value( MDAL::Duration::Unit unit ) const +{ + switch ( unit ) + { + case MDAL::Duration::milliseconds: + return double( mDuration ); + case MDAL::Duration::seconds: + return mDuration / MILLISECONDS_IN_SECOND; + case MDAL::Duration::minutes: + return mDuration / MILLISECONDS_IN_MINUTE; + case MDAL::Duration::hours: + return mDuration / MILLISECONDS_IN_HOUR; + case MDAL::Duration::days: + return double( mDuration ) / MILLISECONDS_IN_DAY; + case MDAL::Duration::weeks: + return double( mDuration ) / MILLISECONDS_IN_WEEK; + case MDAL::Duration::months_CF: + return double( mDuration ) / MILLISECONDS_IN_MONTH_CF; + case MDAL::Duration::exact_years: + return double( mDuration ) / MILLISECONDS_IN_EXACT_YEAR; + } +} + +MDAL::Duration &MDAL::Duration::operator=( const MDAL::Duration &other ) +{ + mDuration = other.mDuration; + return *this; +} + +MDAL::Duration MDAL::Duration::operator-( const MDAL::Duration &other ) const +{ + return Duration( mDuration - other.mDuration ); +} + +MDAL::Duration MDAL::Duration::operator+( const MDAL::Duration &other ) const +{ + return Duration( mDuration + other.mDuration ); +} + +MDAL::Duration &MDAL::Duration::operator+=( const MDAL::Duration &other ) +{ + mDuration += other.mDuration; + return *this; +} + +MDAL::Duration &MDAL::Duration::operator-=( const MDAL::Duration &other ) +{ + mDuration -= other.mDuration; + return *this; +} + +bool MDAL::Duration::operator==( const MDAL::Duration &other ) const +{ + return mDuration == other.mDuration; +} + +bool MDAL::Duration::operator!=( const MDAL::Duration &other ) const +{ + return mDuration != other.mDuration; +} + +bool MDAL::Duration::operator<( const MDAL::Duration &other ) const +{ + return mDuration < other.mDuration; +} + +bool MDAL::Duration::operator>( const MDAL::Duration &other ) const +{ + return mDuration > other.mDuration; +} + +bool MDAL::Duration::operator>=( const MDAL::Duration &other ) const +{ + return mDuration >= other.mDuration; +} + +bool MDAL::Duration::operator<=( const MDAL::Duration &other ) const +{ + return mDuration <= other.mDuration; +} + +MDAL::Duration::Duration( int64_t ms ): mDuration( ms ) +{} diff --git a/mdal/mdal_date_time.hpp b/mdal/mdal_date_time.hpp new file mode 100644 index 00000000..14df28e8 --- /dev/null +++ b/mdal/mdal_date_time.hpp @@ -0,0 +1,141 @@ +#ifndef MDAL_DATE_TIME_HPP +#define MDAL_DATE_TIME_HPP + +#include +#include + +namespace MDAL +{ + + class Duration + { + public: + enum Unit + { + milliseconds = 0, + seconds, + minutes, + hours, + days, + weeks, + months_CF, + exact_years + }; + + Duration(); + + ///TODO : move operation + + Duration( double duration, Unit unit ); + Duration( const Duration &other ); + + double value( Unit unit ) const; + + Duration &operator=( const Duration &other ); + Duration operator-( const Duration &other ) const; + Duration operator+( const Duration &other ) const; + Duration &operator+=( const Duration &other ); + Duration &operator-=( const Duration &other ); + bool operator==( const Duration &other ) const; + bool operator!=( const Duration &other ) const; + bool operator<( const Duration &other ) const; + bool operator>( const Duration &other ) const; + bool operator>=( const Duration &other ) const; + bool operator<=( const Duration &other ) const; + + private: + Duration( int64_t ms ); + int64_t mDuration; //in ms + + friend class DateTime; + }; + + class DateTime + { + public: + + enum Calendar + { + Gregorian = 0, + Gregorian_proleptic, + Julian, + }; + + //! Defaul constructor + DateTime(); + //! Copy constructor + DateTime( const DateTime &other ); + //! Constructor with date/time value and calendar type + DateTime( int year, int month, int day, int hours = 0, int minutes = 0, double seconds = 0, Calendar calendar = Gregorian ); + //! Constructor with Jlian day + DateTime( double julianDay ); + + //! Returns a string with the date/time expressed in Greogrian/Julian calendar with ISO8601 format (local time zone) + std::string toStandartCalendarISO8601() const; + + //! Returns the Julian day value + double toJulianDay() const; + + //! Returns the Julain day value expressed with a string + std::string toJulianDayString() const; + + //! operators + DateTime &operator=( const DateTime &other ); + Duration operator-( const DateTime &other ) const; + DateTime operator+( const Duration &duration ) const; + DateTime &operator+=( const Duration &duration ); + DateTime &operator-=( const Duration &duration ); + DateTime operator-( const Duration &duration ) const; + bool operator==( const DateTime &other ) const; + bool operator!=( const DateTime &other ) const; + bool operator<( const DateTime &other ) const; + bool operator>( const DateTime &other ) const; + bool operator>=( const DateTime &other ) const; + bool operator<=( const DateTime &other ) const; + + private: + + struct DateTimeValues + { + int year; + int month; + int day; + int hours; + int minutes; + double seconds; + }; + + DateTime( int64_t julianTime ); + + DateTimeValues dateTimeGregorianJulianCalendar() const; + + void setWithGregorianCalendarDate( DateTimeValues values ); + void setWithJulianCalendarDate( DateTimeValues values ); + void setWithGregorianJulianCalendarDate( DateTimeValues values );//Uses the adapted formula depending of the date (< or > 1582-10-15) + + void setWith365dayCalendarDate( DateTimeValues values ) + { + ///TODO + } + void setWith366dayCalendarDate( DateTimeValues values ) + { + ///TODO + } + void setWith360dayCalendarDate( DateTimeValues values ) + { + ///TODO + } + void setWithNonStandartCalendarDate( DateTimeValues values, std::vector month_lengths, int leap_year, int leap_month ) + { + ///TODO + } + + std::string toString( DateTimeValues values ) const; + + int64_t mJulianTime = 0; //Julian day in ms + + bool mValid = true; + }; +} + +#endif // MDAL_DATE_TIME_HPP diff --git a/mdal/mdal_utils.cpp b/mdal/mdal_utils.cpp index 40ec558c..b4520a46 100644 --- a/mdal/mdal_utils.cpp +++ b/mdal/mdal_utils.cpp @@ -661,10 +661,59 @@ std::string MDAL::doubleToString( double value, int precision ) return oss.str(); } -std::string MDAL::prependZero( std::string str, size_t lengthObjectif ) +std::string MDAL::prependZero( const std::string &str, size_t length ) { - if ( lengthObjectif <= str.size() ) + if ( length <= str.size() ) return str; - return std::string( lengthObjectif - str.size(), '0' ).append( str ); + return std::string( length - str.size(), '0' ).append( str ); +} + +MDAL::Duration::Unit MDAL::parseUnitTime( const std::string &timeUnit ) +{ + MDAL::Duration::Unit unit = MDAL::Duration::hours; //default unit + + if ( timeUnit == "millisec" || + timeUnit == "msec" || + timeUnit == "millisecs" || + timeUnit == "msecs" + ) + { + unit = MDAL::Duration::milliseconds; + } + else if ( timeUnit == "second" || + timeUnit == "seconds" || + timeUnit == "Seconds" || + timeUnit == "sec" || + timeUnit == "secs" || + timeUnit == "s" || + timeUnit == "se" || //ascii_dat format + timeUnit == "2" ) //ascii_dat format + { + unit = MDAL::Duration::seconds; + } + else if ( timeUnit == "minute" || + timeUnit == "minutes" || + timeUnit == "Minutes" || + timeUnit == "min" || + timeUnit == "mins" || + timeUnit == "mi" || //ascii_dat format + timeUnit == "1" ) //ascii_dat format + { + unit = MDAL::Duration::minutes; + } + else if ( timeUnit == "day" || + timeUnit == "days" || + timeUnit == "Days" ) + { + unit = MDAL::Duration::days; + } + else if ( timeUnit == "week" || + timeUnit == "weeks" ) + { + unit = MDAL::Duration::weeks; + } + + + return unit; } diff --git a/mdal/mdal_utils.hpp b/mdal/mdal_utils.hpp index 777401ef..b9aff796 100644 --- a/mdal/mdal_utils.hpp +++ b/mdal/mdal_utils.hpp @@ -147,7 +147,9 @@ namespace MDAL } //! Prepend 0 to string to have n char - std::string prependZero( std::string str, size_t lengthObjectif ); + std::string prependZero( const std::string &str, size_t length ); + + Duration::Unit parseUnitTime( const std::string &timeUnit ); } // namespace MDAL #endif //MDAL_UTILS_HPP diff --git a/tests/test_flo2d.cpp b/tests/test_flo2d.cpp index b9e70cf6..e4090267 100644 --- a/tests/test_flo2d.cpp +++ b/tests/test_flo2d.cpp @@ -473,7 +473,7 @@ TEST( MeshFlo2dTest, BarnHDF5 ) ASSERT_NE( ds, nullptr ); double time = MDAL_D_time( ds ); - EXPECT_EQ( true, compareDurationInHours( 0.10124753560882101, time ) ); + EXPECT_TRUE( compareDurationInHours( 0.10124753560882101, time ) ); valid = MDAL_D_isValid( ds ); EXPECT_EQ( true, valid ); diff --git a/tests/test_hec2d.cpp b/tests/test_hec2d.cpp index e47454c9..f83408f8 100644 --- a/tests/test_hec2d.cpp +++ b/tests/test_hec2d.cpp @@ -361,7 +361,7 @@ TEST( MeshHec2dTest, model_505 ) EXPECT_DOUBLE_EQ( 43.28509521484375, max ); double time = MDAL_D_time( ds ); - EXPECT_EQ( true, compareDurationInHours( 0.083333335816860199, time ) ); + EXPECT_TRUE( compareDurationInHours( 0.083333335816860199, time ) ); const char *referenceTime = MDAL_G_referenceTime( g ); EXPECT_EQ( std::string( "2018-01-01T00:00:00" ), std::string( referenceTime ) ); diff --git a/tests/test_tuflowfv.cpp b/tests/test_tuflowfv.cpp index f560254f..7dba7ff2 100644 --- a/tests/test_tuflowfv.cpp +++ b/tests/test_tuflowfv.cpp @@ -165,7 +165,7 @@ TEST( MeshTuflowFVTest, TrapSteady053D ) EXPECT_DOUBLE_EQ( 34.741443634033203, max ); double time = MDAL_D_time( ds ); - EXPECT_EQ( true, compareDurationInHours( 0.502121734619141, time ) ); + EXPECT_TRUE( compareDurationInHours( 0.502121734619141, time ) ); } // ///////////////////////////////// @@ -219,7 +219,7 @@ TEST( MeshTuflowFVTest, TrapSteady053D ) EXPECT_DOUBLE_EQ( 1.7670363355554111, max ); double time = MDAL_D_time( ds ); - EXPECT_EQ( true, compareDurationInHours( 0.667265041139391, time ) ); + EXPECT_TRUE( compareDurationInHours( 0.667265041139391, time ) ); } // ///////////////////////////////// @@ -267,7 +267,7 @@ TEST( MeshTuflowFVTest, TrapSteady053D ) EXPECT_DOUBLE_EQ( 2.488835334777832, max ); double time = MDAL_D_time( ds ); - EXPECT_EQ( true, compareDurationInHours( 1.16755709277259, time ) ); + EXPECT_TRUE( compareDurationInHours( 1.16755709277259, time ) ); } // Close mesh