• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lutraconsulting / MDAL / 3748625157

pending completion
3748625157

push

github

GitHub
Fix#391 (#439)

2 of 2 new or added lines in 1 file covered. (100.0%)

8869 of 9910 relevant lines covered (89.5%)

76013.65 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.84
/mdal/mdal_datetime.cpp
1
/*
2
 MDAL - Mesh Data Abstraction Library (MIT License)
3
 Copyright (C) 2019 Vincent Cloarec (vcloarec at gmail dot com)
4
*/
5
#include "mdal_datetime.hpp"
6
#include "mdal_utils.hpp"
7

8

9
constexpr double MILLISECONDS_IN_SECOND = 1000;
10
constexpr double MILLISECONDS_IN_MINUTE = 1000 * 60;
11
constexpr double MILLISECONDS_IN_HOUR = 1000 * 60 * 60;
12
constexpr double MILLISECONDS_IN_DAY = 1000 * 60 * 60 * 24;
13
constexpr double MILLISECONDS_IN_WEEK = 1000 * 60 * 60 * 24 * 7;
14

15
//https://www.unidata.ucar.edu/software/netcdf-java/current/CDM/CalendarDateTime.html
16
constexpr double MILLISECONDS_IN_EXACT_YEAR = 3.15569259747e10; //CF Compliant
17
constexpr double MILLISECONDS_IN_MONTH_CF = MILLISECONDS_IN_EXACT_YEAR / 12.0; //CF Compliant
18

19
MDAL::DateTime::DateTime() = default;
1,377✔
20

21
MDAL::DateTime::DateTime( int year, int month, int day, int hours, int minutes, double seconds, MDAL::DateTime::Calendar calendar )
246✔
22
{
23
  DateTimeValues value{year, month, day, hours, minutes, seconds};
246✔
24

25
  switch ( calendar )
246✔
26
  {
27
    case MDAL::DateTime::Gregorian:
242✔
28
      setWithGregorianJulianCalendarDate( value );
242✔
29
      break;
242✔
30
    case MDAL::DateTime::ProlepticGregorian:
3✔
31
      setWithGregorianCalendarDate( value );
3✔
32
      break;
3✔
33
    case MDAL::DateTime::Julian:
1✔
34
      setWithJulianCalendarDate( value );
1✔
35
      break;
1✔
36
  }
37
}
246✔
38

39
MDAL::DateTime::DateTime( double value, Epoch epoch ):  mValid( true )
1,193✔
40
{
41
  switch ( epoch )
1,193✔
42
  {
43
    case MDAL::DateTime::Unix:
144✔
44
      mJulianTime = ( DateTime( 1970, 01, 01, 0, 0, 0, Gregorian ) + RelativeTimestamp( value, RelativeTimestamp::seconds ) ).mJulianTime;
144✔
45
      break;
144✔
46
    case MDAL::DateTime::JulianDay:
1,049✔
47
      mJulianTime = int64_t( value * MILLISECONDS_IN_DAY + 0.5 );
1,049✔
48
      break;
1,049✔
49
  }
50
}
1,193✔
51

52
MDAL::DateTime::DateTime( const std::string &fromISO8601 )
22✔
53
{
54
  std::vector<std::string> splitedDateTime = split( fromISO8601, 'T' );
22✔
55

56
  if ( splitedDateTime.size() != 2 )
22✔
57
    return;
×
58
  //parse date
59
  std::vector<std::string> splitedDate = split( splitedDateTime.at( 0 ), '-' );
22✔
60
  if ( splitedDate.size() != 3 )
22✔
61
    return;
×
62

63
  //parse time
64
  splitedDateTime[1] = replace( splitedDateTime.at( 1 ), "Z", "", ContainsBehaviour::CaseInsensitive );
22✔
65
  std::vector<std::string> splitedTime = split( splitedDateTime.at( 1 ), ':' );
22✔
66
  if ( splitedTime.size() < 2 || splitedTime.size() > 3 )
22✔
67
    return;
×
68

69
  DateTimeValues dateTimeValues;
70
  dateTimeValues.year = toInt( splitedDate[0] );
22✔
71
  dateTimeValues.month = toInt( splitedDate[1] );
22✔
72
  dateTimeValues.day = toInt( splitedDate[2] );
22✔
73
  dateTimeValues.hours = toInt( splitedTime[0] );
22✔
74
  dateTimeValues.minutes = toInt( splitedTime[1] );
22✔
75
  if ( splitedTime.size() == 3 )
22✔
76
    dateTimeValues.seconds = toDouble( splitedTime[2] );
21✔
77
  else
78
    dateTimeValues.seconds = 0.0;
1✔
79

80
  setWithGregorianCalendarDate( dateTimeValues );
22✔
81
}
22✔
82

83
std::string MDAL::DateTime::toStandardCalendarISO8601() const
1,086✔
84
{
85
  if ( mValid )
1,086✔
86
  {
87
    DateTimeValues value = dateTimeGregorianProleptic();
1,060✔
88
    if ( value.year > 0 )
1,060✔
89
      return toString( value );
1,060✔
90
  }
91

92
  return "";
26✔
93
}
94

95
double MDAL::DateTime::toJulianDay() const
6✔
96
{
97
  return mJulianTime / MILLISECONDS_IN_DAY;
6✔
98
}
99

100
std::string MDAL::DateTime::toJulianDayString() const
6✔
101
{
102
  return std::to_string( toJulianDay() );
6✔
103
}
104

105
std::vector<int> MDAL::DateTime::expandToCalendarArray() const
2✔
106
{
107
  std::vector<int> dateTimeArray( 6, 0 );
2✔
108
  if ( mValid )
2✔
109
  {
110
    DateTimeValues value = dateTimeGregorianProleptic();
2✔
111
    dateTimeArray[0] = value.year;
2✔
112
    dateTimeArray[1] = value.month;
2✔
113
    dateTimeArray[2] = value.day;
2✔
114
    dateTimeArray[3] = value.hours;
2✔
115
    dateTimeArray[4] = value.minutes;
2✔
116
    dateTimeArray[5] = int( value.seconds + 0.5 );
2✔
117
  }
118

119
  return dateTimeArray;
2✔
120
}
×
121

122

123
MDAL::DateTime MDAL::DateTime::operator+( const MDAL::RelativeTimestamp &duration ) const
263✔
124
{
125
  if ( !mValid )
263✔
126
    return DateTime();
×
127
  return DateTime( mJulianTime + duration.mDuration );
263✔
128
}
129

130

131
MDAL::DateTime MDAL::DateTime::operator-( const MDAL::RelativeTimestamp &duration ) const
1✔
132
{
133
  if ( !mValid )
1✔
134
    return DateTime();
×
135
  return DateTime( mJulianTime - duration.mDuration );
1✔
136
}
137

138
bool MDAL::DateTime::operator==( const MDAL::DateTime &other ) const
69✔
139
{
140
  if ( !mValid && !other.mValid )
69✔
141
    return true;
1✔
142

143
  return ( mValid && other.mValid ) && ( mJulianTime == other.mJulianTime );
68✔
144
}
145

146
bool MDAL::DateTime::operator!=( const MDAL::DateTime &other ) const
53✔
147
{
148
  return ! operator==( other );
53✔
149
}
150

151
bool MDAL::DateTime::operator<( const MDAL::DateTime &other ) const
8✔
152
{
153
  if ( !mValid && !other.mValid )
8✔
154
    return false;
×
155
  return ( mValid && other.mValid ) && ( mJulianTime < other.mJulianTime );
8✔
156
}
157

158
bool MDAL::DateTime::isValid() const { return mValid; }
397✔
159

160
MDAL::DateTime::DateTime( int64_t julianTime ): mJulianTime( julianTime ), mValid( true )
264✔
161
{}
264✔
162

163
/*
164
MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianJulianCalendar() const
165
{
166
  // https://fr.wikipedia.org/wiki/Jour_julien
167
  DateTimeValues values;
168
  int Z = int( mJulianTime / MILLISECONDS_IN_DAY + 0.5 ); // integer part of julian days count
169
  double F = ( mJulianTime - MILLISECONDS_IN_DAY * ( Z - 0.5 ) ) / MILLISECONDS_IN_DAY; // fractional part of julian days count;
170
  int S;
171

172
  if ( Z < 2299161 )
173
    S = Z;
174
  else
175
  {
176
    int alpha = int( ( Z - 1867216.25 ) / 36524.25 );
177
    S = Z + 1 + alpha - int( alpha / 4 );
178
  }
179

180
  int B = S + 1524;
181
  int C = int( ( B - 122.1 ) / 365.25 );
182
  int D = int( 365.25 * C );
183
  int E = int( ( B - D ) / 30.6001 );
184

185
  values.day = B - D - int( 30.6001 * E );
186
  if ( E < 14 )
187
    values.month = E - 1;
188
  else
189
    values.month = E - 13;
190

191
  if ( values.month > 2 )
192
    values.year = C - 4716;
193
  else
194
    values.year = C - 4715;
195

196
  values.hours = int( F / MILLISECONDS_IN_HOUR );
197
  F = int( F - values.hours * MILLISECONDS_IN_HOUR );
198
  values.minutes = int( F / MILLISECONDS_IN_MINUTE );
199
  F = int( F  - values.minutes * MILLISECONDS_IN_MINUTE );
200
  values.seconds = int( F / MILLISECONDS_IN_SECOND );
201

202
  return values;
203
}
204
*/
205

206
MDAL::DateTime::DateTimeValues MDAL::DateTime::dateTimeGregorianProleptic() const
1,062✔
207
{
208
  // https://fr.wikipedia.org/wiki/Jour_julien
209
  DateTimeValues values;
210
  int Z = int( mJulianTime / MILLISECONDS_IN_DAY + 0.5 ); // integer part of julian days count
1,062✔
211
  int F = int( mJulianTime - MILLISECONDS_IN_DAY * ( Z - 0.5 ) ) ; // fractional part of julian days count in ms;
1,062✔
212

213
  int alpha = int( ( Z - 1867216.25 ) / 36524.25 );
1,062✔
214
  int S = Z + 1 + alpha - int( alpha / 4 );
1,062✔
215

216
  int B = S + 1524;
1,062✔
217
  int C = int( ( B - 122.1 ) / 365.25 );
1,062✔
218
  int D = int( 365.25 * C );
1,062✔
219
  int E = int( ( B - D ) / 30.6001 );
1,062✔
220

221
  values.day = B - D - int( 30.6001 * E );
1,062✔
222
  if ( E < 14 )
1,062✔
223
    values.month = E - 1;
866✔
224
  else
225
    values.month = E - 13;
196✔
226

227
  if ( values.month > 2 )
1,062✔
228
    values.year = C - 4716;
866✔
229
  else
230
    values.year = C - 4715;
196✔
231

232
  values.hours = int( F / MILLISECONDS_IN_HOUR );
1,062✔
233
  F = int( F - values.hours * MILLISECONDS_IN_HOUR );
1,062✔
234
  values.minutes = int( F / MILLISECONDS_IN_MINUTE );
1,062✔
235
  F = int( F  - values.minutes * MILLISECONDS_IN_MINUTE );
1,062✔
236
  values.seconds = int( F / MILLISECONDS_IN_SECOND );
1,062✔
237

238
  return values;
1,062✔
239
}
240

241

242
void MDAL::DateTime::setWithGregorianCalendarDate( MDAL::DateTime::DateTimeValues values )
262✔
243
{
244
  // https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
245
  if ( values.month <= 2 )
262✔
246
  {
247
    values.year--;
216✔
248
    values.month += 12;
216✔
249
  }
250

251
  int A = values.year / 100;
262✔
252
  int B = A / 4;
262✔
253
  int C = 2 - A + B;
262✔
254
  int E = int( 365.25 * ( values.year + 4716 ) );
262✔
255
  int F = int( 30.6001 * ( values.month + 1 ) );
262✔
256
  double julianDay = C + values.day + E + F - 1524.5;
262✔
257

258
  mValid = true;
262✔
259
  mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY +
262✔
260
                         ( values.hours ) * MILLISECONDS_IN_HOUR +
262✔
261
                         values.minutes * MILLISECONDS_IN_MINUTE +
262✔
262
                         values.seconds * MILLISECONDS_IN_SECOND );
262✔
263
}
262✔
264

265
void MDAL::DateTime::setWithJulianCalendarDate( MDAL::DateTime::DateTimeValues values )
6✔
266
{
267
  // https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
268
  if ( values.month <= 2 )
6✔
269
  {
270
    values.year--;
×
271
    values.month += 12;
×
272
  }
273

274
  int E = int( 365.25 * ( values.year + 4716 ) );
6✔
275
  int F = int( 30.6001 * ( values.month + 1 ) );
6✔
276
  double julianDay = values.day + E + F - 1524.5;
6✔
277

278
  mValid = true;
6✔
279
  mJulianTime = int64_t( julianDay * MILLISECONDS_IN_DAY +
6✔
280
                         ( values.hours ) * MILLISECONDS_IN_HOUR +
6✔
281
                         values.minutes * MILLISECONDS_IN_MINUTE +
6✔
282
                         values.seconds * MILLISECONDS_IN_SECOND );
6✔
283
}
6✔
284

285
void MDAL::DateTime::setWithGregorianJulianCalendarDate( MDAL::DateTime::DateTimeValues values )
242✔
286
{
287
  // https://quasar.as.utexas.edu/BillInfo/JulianDatesG.html
288

289
  mValid = true;
242✔
290

291
  if ( values.year > 1582 ||
242✔
292
       ( values.year == 1582 && ( values.month > 10 || ( values.month == 10 && values.day >= 15 ) ) ) ) // gregorian calendar
5✔
293
  {
294
    setWithGregorianCalendarDate( values );
237✔
295
  }
296
  else
297
    setWithJulianCalendarDate( values );
5✔
298
}
242✔
299

300
std::string MDAL::DateTime::toString( MDAL::DateTime::DateTimeValues values ) const
1,060✔
301
{
302
  int milliseconds = int( ( values.seconds - int( values.seconds ) ) * 1000 + 0.5 );
1,060✔
303
  std::string msStr;
1,060✔
304
  if ( milliseconds > 0 )
1,060✔
305
  {
306
    if ( milliseconds < 10 )
×
307
      msStr = prependZero( std::to_string( milliseconds ), 3 );
×
308
    else if ( milliseconds < 100 )
×
309
      msStr = prependZero( std::to_string( milliseconds ), 2 );
×
310
    else if ( milliseconds < 1000 )
×
311
      msStr = std::to_string( milliseconds );
×
312

313
    msStr = std::string( "," ).append( msStr );
×
314
  }
315

316
  std::string strDateTime = prependZero( std::to_string( values.year ), 4 ) + "-" +
2,120✔
317
                            prependZero( std::to_string( values.month ), 2 ) + "-" +
4,240✔
318
                            prependZero( std::to_string( values.day ), 2 ) + "T" +
4,240✔
319
                            prependZero( std::to_string( values.hours ), 2 ) + ":" +
4,240✔
320
                            prependZero( std::to_string( values.minutes ), 2 ) + ":" +
4,240✔
321
                            prependZero( std::to_string( int( values.seconds ) ), 2 ) +
2,120✔
322
                            msStr;
1,060✔
323

324
  return strDateTime;
2,120✔
325
}
1,060✔
326

327
MDAL::RelativeTimestamp MDAL::DateTime::operator-( const MDAL::DateTime &other ) const
139✔
328
{
329
  if ( !mValid || !other.mValid )
139✔
330
    return RelativeTimestamp();
×
331
  return RelativeTimestamp( mJulianTime - other.mJulianTime );
139✔
332
}
333

334

335
MDAL::RelativeTimestamp::RelativeTimestamp() = default;
11,074✔
336

337
MDAL::RelativeTimestamp::RelativeTimestamp( double duration, MDAL::RelativeTimestamp::Unit unit )
4,516✔
338
{
339
  switch ( unit )
4,516✔
340
  {
341
    case MDAL::RelativeTimestamp::milliseconds:
×
342
      mDuration = int64_t( duration );
×
343
      break;
×
344
    case MDAL::RelativeTimestamp::seconds:
1,200✔
345
      mDuration = int64_t( duration * MILLISECONDS_IN_SECOND + 0.5 );
1,200✔
346
      break;
1,200✔
347
    case MDAL::RelativeTimestamp::minutes:
8✔
348
      mDuration = int64_t( duration * MILLISECONDS_IN_MINUTE + 0.5 );
8✔
349
      break;
8✔
350
    case MDAL::RelativeTimestamp::hours:
2,787✔
351
      mDuration = int64_t( duration * MILLISECONDS_IN_HOUR + 0.5 );
2,787✔
352
      break;
2,787✔
353
    case MDAL::RelativeTimestamp::days:
520✔
354
      mDuration = int64_t( duration * MILLISECONDS_IN_DAY + 0.5 );
520✔
355
      break;
520✔
356
    case MDAL::RelativeTimestamp::weeks:
1✔
357
      mDuration = int64_t( duration * MILLISECONDS_IN_WEEK + 0.5 );
1✔
358
      break;
1✔
359
    case MDAL::RelativeTimestamp::months_CF:
×
360
      mDuration = int64_t( duration * MILLISECONDS_IN_MONTH_CF + 0.5 );
×
361
      break;
×
362
    case MDAL::RelativeTimestamp::exact_years:
×
363
      mDuration = int64_t( duration * MILLISECONDS_IN_EXACT_YEAR + 0.5 );
×
364
      break;
×
365
  }
366
}
4,516✔
367

368
double MDAL::RelativeTimestamp::value( MDAL::RelativeTimestamp::Unit unit ) const
540✔
369
{
370
  switch ( unit )
540✔
371
  {
372
    case MDAL::RelativeTimestamp::milliseconds:
10✔
373
      return double( mDuration );
10✔
374
    case MDAL::RelativeTimestamp::seconds:
18✔
375
      return mDuration / MILLISECONDS_IN_SECOND;
18✔
376
    case MDAL::RelativeTimestamp::minutes:
10✔
377
      return mDuration  / MILLISECONDS_IN_MINUTE;
10✔
378
    case MDAL::RelativeTimestamp::hours:
462✔
379
      return mDuration / MILLISECONDS_IN_HOUR;
462✔
380
    case MDAL::RelativeTimestamp::days:
10✔
381
      return double( mDuration ) / MILLISECONDS_IN_DAY;
10✔
382
    case MDAL::RelativeTimestamp::weeks:
10✔
383
      return double( mDuration )  / MILLISECONDS_IN_WEEK;
10✔
384
    case MDAL::RelativeTimestamp::months_CF:
10✔
385
      return double( mDuration ) / MILLISECONDS_IN_MONTH_CF;
10✔
386
    case MDAL::RelativeTimestamp::exact_years:
10✔
387
      return double( mDuration )  / MILLISECONDS_IN_EXACT_YEAR;
10✔
388
  }
389

390
  return 0;
×
391
}
392

393
bool MDAL::RelativeTimestamp::operator==( const MDAL::RelativeTimestamp &other ) const
10✔
394
{
395
  return mDuration == other.mDuration;
10✔
396
}
397

398
bool MDAL::RelativeTimestamp::operator<( const MDAL::RelativeTimestamp &other ) const
3,837✔
399
{
400
  return mDuration < other.mDuration;
3,837✔
401
}
402

403
MDAL::RelativeTimestamp::RelativeTimestamp( int64_t ms ): mDuration( ms )
139✔
404
{}
139✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc