Skip to content

Commit

Permalink
Merge pull request #548 from ut-issl/feature/add-time-system-library
Browse files Browse the repository at this point in the history
Update time system library
  • Loading branch information
200km committed Dec 6, 2023
2 parents 8d83f04 + 9e7261e commit 336981b
Show file tree
Hide file tree
Showing 10 changed files with 425 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/library/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ add_library(${PROJECT_NAME} STATIC
planet_rotation/moon_rotation_utilities.cpp

time_system/date_time_format.cpp
time_system/epoch_time.cpp
time_system/gps_time.cpp

external/igrf/igrf.cpp
external/inih/ini.c
Expand Down
31 changes: 31 additions & 0 deletions src/library/time_system/date_time_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,43 @@
* @brief Class to handle Gregorian date and time format
*/

#define _CRT_SECURE_NO_WARNINGS // for sscanf

#include "date_time_format.hpp"

#include <cmath>
#include <iomanip>
#include <sstream>

DateTime::DateTime(const std::string date_time) {
sscanf(date_time.c_str(), "%zu/%zu/%zu %zu:%zu:%lf", &year_, &month_, &day_, &hour_, &minute_, &second_);
}

DateTime::DateTime(const EpochTime epoch_time) {
// No leap second calculation
const int mday[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //!< Number of days in a month
int days, sec, mon, day;

// leap year if year%4==0 in 1901-2099
days = (int)(epoch_time.GetTime_s() / 86400);
sec = (int)(epoch_time.GetTime_s() - (time_t)days * 86400);

for (day = days % 1461, mon = 0; mon < 48; mon++) {
if (day >= mday[mon])
day -= mday[mon];
else
break;
}

year_ = 1970 + days / 1461 * 4 + mon / 12;
month_ = mon % 12 + 1;
day_ = day + 1;
hour_ = sec / 3600;
minute_ = sec % 3600 / 60;
second_ = sec % 60 + epoch_time.GetFraction_s();
}

std::string DateTime::GetAsString() const {
std::stringstream stream;
stream << std::setw(4) << std::setfill('0') << (int)year_ << "/";
Expand Down
15 changes: 10 additions & 5 deletions src/library/time_system/date_time_format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
* @brief Class to handle Gregorian date and time format
*/

#define _CRT_SECURE_NO_WARNINGS // for sscanf

#ifndef S2E_LIBRARY_TIME_SYSTEM_DATE_TIME_FORMAT_HPP_
#define S2E_LIBRARY_TIME_SYSTEM_DATE_TIME_FORMAT_HPP_

#include <string>

#include "epoch_time.hpp"

class EpochTime;

/**
*@class DateTime
* @brief Class to handle Gregorian date and time format
Expand All @@ -28,9 +30,12 @@ class DateTime {
* @brief Constructor initialized with string expression as YYYY/MM/DD hh:mm:ss.s
* @note TODO: Support other format like dd.mm.yyyy
*/
DateTime(const std::string date_time = "0000/01/01 00:00:00.0") {
sscanf(date_time.c_str(), "%zu/%zu/%zu %zu:%zu:%lf", &year_, &month_, &day_, &hour_, &minute_, &second_);
}
DateTime(const std::string date_time = "0000/01/01 00:00:00.0");
/**
* @fn DateTime
* @brief Constructor initialized with epoch time
*/
DateTime(const EpochTime epoch_time);

// Getters
inline size_t GetYear() const { return year_; }
Expand Down
75 changes: 75 additions & 0 deletions src/library/time_system/epoch_time.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @file epoch_time.cpp
* @brief A class to handle time like UNIX time with fractions
*/

#include "epoch_time.hpp"

#include <cmath>

EpochTime::EpochTime(const DateTime date_time) {
// No leap second calculation
const int doy[] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; //!< Day of Year for the 1st day of each month
// Parse Calender
const size_t year = date_time.GetYear();
const size_t month = date_time.GetMonth();
const size_t day = date_time.GetDay();
const size_t hour = date_time.GetHour();
const size_t minute = date_time.GetMinute();
const size_t second = (size_t)std::floor(date_time.GetSecond());

// TODO: assertion
if (year < 1970 || month < 1 || 12 < month) return;
if (day < 1 || 32 <= day) return;
if (60 <= minute) return;
if (60 <= second) return;

// leap year if year%4==0 in 1901-2099
uint64_t days = (year - 1970) * 365 + (year - 1969) / 4 + doy[month - 1] + day - 2 + (year % 4 == 0 && month >= 3 ? 1 : 0);
time_s_ = (uint64_t)days * 86400 + hour * 3600 + minute * 60 + second;
fraction_s_ = date_time.GetSecond() - (double)second;
}

bool EpochTime::operator==(const EpochTime& target) const {
if (this->time_s_ != target.time_s_) return false;
if (this->fraction_s_ != target.fraction_s_) return false; // TODO: comparison of double
return true;
}

bool EpochTime::operator>(const EpochTime& right_side) const {
if (*this == right_side) return false;
if (this->time_s_ < right_side.time_s_) return false;
if (this->time_s_ > right_side.time_s_) return true;
if (this->fraction_s_ < right_side.fraction_s_) return false;
return true;
}

bool EpochTime::operator<(const EpochTime& right_side) const {
if (*this == right_side) return false;
if (this->time_s_ > right_side.time_s_) return false;
if (this->time_s_ < right_side.time_s_) return true;
if (this->fraction_s_ > right_side.fraction_s_) return false;
return true;
}

EpochTime EpochTime::operator+(const EpochTime& right_side) const {
time_t time_s = this->time_s_ + right_side.GetTime_s();
double fraction_s = this->fraction_s_ + right_side.GetFraction_s();
if (fraction_s > 1.0) {
fraction_s -= 1.0;
time_s += 1;
}
EpochTime result(time_s, fraction_s);
return result;
}

EpochTime EpochTime::operator-(const EpochTime& right_side) const {
time_t time_s = this->time_s_ - right_side.GetTime_s(); // TODO: assertion for negative value
double fraction_s = this->fraction_s_ - right_side.GetFraction_s();
if (fraction_s < 0.0) {
fraction_s += 1.0;
time_s -= 1;
}
EpochTime result(time_s, fraction_s);
return result;
}
70 changes: 70 additions & 0 deletions src/library/time_system/epoch_time.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* @file epoch_time.hpp
* @brief A class to handle time like UNIX time with fractions
*/

#ifndef S2E_LIBRARY_TIME_SYSTEM_EPOCH_TIME_HPP_
#define S2E_LIBRARY_TIME_SYSTEM_EPOCH_TIME_HPP_

#include <cstdint>

#include "date_time_format.hpp"

class DateTime;

/**
* @class EpochTime
* @brief A class to handle time like UNIX time with fractions.
* @note This class doesn't care leap seconds.
*/
class EpochTime {
public:
/**
* @fn EpochTime
* @brief Constructor initialized with week and second
*/
EpochTime(const uint64_t time_s = 0, const double fraction_s = 0.0) : time_s_(time_s), fraction_s_(fraction_s) {}
/**
* @fn EpochTime
* @brief Constructor initialized with date time expression
*/
EpochTime(const DateTime date_time);
/**
* @fn ~EpochTime
* @brief Destructor
*/
~EpochTime() {}

// Getter
/**
* @fn GetTime_s
* @return time [s]
*/
inline uint64_t GetTime_s() const { return time_s_; }
/**
* @fn GetFraction_s
* @return fraction time [s]
*/
inline double GetFraction_s() const { return fraction_s_; }
/**
* @fn GetTimeWithFraction_s
* @return time + fraction [s]
*/
inline double GetTimeWithFraction_s() const { return (double)(time_s_) + fraction_s_; }

// Operator
bool operator==(const EpochTime& target) const;
bool operator!=(const EpochTime& target) const { return !(*this == target); }
bool operator>(const EpochTime& right_side) const;
bool operator<=(const EpochTime& right_side) const { return !(*this > right_side); }
bool operator<(const EpochTime& right_side) const;
bool operator>=(const EpochTime& right_side) const { return !(*this < right_side); }
EpochTime operator+(const EpochTime& right_side) const;
EpochTime operator-(const EpochTime& right_side) const;

private:
uint64_t time_s_; //!< Number of seconds without leap seconds since 00:00:00 Jan 1 1970 UTC.
double fraction_s_; //!< Fraction of second under 1 sec [0, 1)
};

#endif // S2E_LIBRARY_TIME_SYSTEM_EPOCH_TIME_HPP_
25 changes: 25 additions & 0 deletions src/library/time_system/gps_time.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @file gps_time.cpp
* @brief A class to define GPS time expression
*/

#include "gps_time.hpp"

const DateTime GpsTime::kEpochOfGpsTimeInDateTime_ = DateTime("1980/1/6 00:00:00.0");
const EpochTime GpsTime::kEpochOfGpsTimeInEpochTime_ = EpochTime(kEpochOfGpsTimeInDateTime_);
const EpochTime GpsTime::kLeapSecondAheadFromUtc_ = EpochTime(18, 0); //!< Leap second ahead from UTC @ May 2023

void GpsTime::CalcGpsWeekTime() {
EpochTime time_diff = epoch_time_ - kEpochOfGpsTimeInEpochTime_;
week_ = (size_t)(time_diff.GetTime_s() / kSecondsInWeek_);
elapsed_time_from_week_s_ = (double)(time_diff.GetTime_s() - week_ * kSecondsInWeek_) + time_diff.GetFraction_s();
}

void GpsTime::CalcEpochTime() {
size_t integer_time_s = (size_t)elapsed_time_from_week_s_;
double fraction_s = elapsed_time_from_week_s_ - (double)(integer_time_s);
time_t time_s = week_ * kSecondsInWeek_ + integer_time_s;
EpochTime time_diff(time_s, fraction_s);

epoch_time_ = kEpochOfGpsTimeInEpochTime_ + time_diff;
}
60 changes: 58 additions & 2 deletions src/library/time_system/gps_time.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#include <cstddef>

#include "date_time_format.hpp"
#include "epoch_time.hpp"

/**
* @class GpsTime
* @brief A class to define GPS time expression
Expand All @@ -19,8 +22,25 @@ class GpsTime {
* @fn GpsTime
* @brief Constructor initialized with week and second
*/
GpsTime(const size_t week = 0, const double elapsed_time_from_week_s = 0.0) : week_(week), elapsed_time_from_week_s_(elapsed_time_from_week_s) {}
GpsTime(const size_t week = 0, const double elapsed_time_from_week_s = 0.0) : week_(week), elapsed_time_from_week_s_(elapsed_time_from_week_s) {
CalcEpochTime();
date_time_ = DateTime(epoch_time_);
}
/**
* @fn GpsTime
* @brief Constructor initialized with epoch time expression
*/
GpsTime(const EpochTime epoch_time) : date_time_(DateTime(epoch_time)), epoch_time_(epoch_time) { CalcGpsWeekTime(); }
/**
* @fn GpsTime
* @brief Constructor initialized with calender expression
*/
GpsTime(const DateTime date_time) : date_time_(date_time), epoch_time_(EpochTime(date_time_)) { CalcGpsWeekTime(); }

/**
* @fn ~GpsTime
* @brief Destructor
*/
~GpsTime() {}

/**
Expand All @@ -30,13 +50,49 @@ class GpsTime {
inline size_t GetWeek() const { return week_; }
/**
* @fn GetTime
* @return GPS time
* @return GPS time from week
*/
inline double GetElapsedTimeFromWeek_s() const { return elapsed_time_from_week_s_; }
/**
* @fn GetEpochTime
* @return GPS time in epoch time expression
*/
inline EpochTime GetEpochTime() const { return epoch_time_; }
/**
* @fn GetDateTime
* @return GPS time in date time expression
*/
inline DateTime GetDateTime() const { return date_time_; }
/**
* @fn GetDateTimeAsUtc
* @return DateTime as UTC including leap seconds
*/
inline DateTime GetDateTimeAsUtc() const { return epoch_time_ - kLeapSecondAheadFromUtc_; }

private:
size_t week_; //!< GPS week (week = 0 at 6th Jan. 1980)
double elapsed_time_from_week_s_; //!< Elapsed time from the GPS week [s] [0,0, 604800.0)
// Expressions
DateTime date_time_; //!< GPS time in date time expression
EpochTime epoch_time_; //!< GPS time in epoch time expression
// Epoch of GPS time
static const DateTime kEpochOfGpsTimeInDateTime_; //!< GPS time epoch in date time expression
static const EpochTime kEpochOfGpsTimeInEpochTime_; //!< GPS time epoch in epoch time expression
// Constants
static const size_t kSecondsInWeek_ = 86400 * 7; //!< Seconds in Week
static const EpochTime kLeapSecondAheadFromUtc_; //!< leap second ahead from UTC

// Functions
/**
* @fn CalcGpsWeekTime
* @brief Calculate GPS Time from epoch time
*/
void CalcGpsWeekTime();
/**
* @fn CalcEpochTime
* @brief Calculate Epoch time from GPS time
*/
void CalcEpochTime();
};

#endif // S2E_LIBRARY_TIME_SYSTEM_GPS_TIME_HPP_
16 changes: 16 additions & 0 deletions src/library/time_system/test_date_time_format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,22 @@ TEST(DateTime, ConstructorWithString) {
EXPECT_DOUBLE_EQ(59.4, date_time.GetSecond());
}

/**
* @brief Test Constructor with epoch time
*/
TEST(DateTime, ConstructorWithEpochTime) {
// Reference for correctness check: https://www.epochconverter.com/
EpochTime epoch_time(1686145305, 0.3);
DateTime date_time(epoch_time);

EXPECT_EQ(2023, date_time.GetYear());
EXPECT_EQ(6, date_time.GetMonth());
EXPECT_EQ(7, date_time.GetDay());
EXPECT_EQ(13, date_time.GetHour());
EXPECT_EQ(41, date_time.GetMinute());
EXPECT_DOUBLE_EQ(45.3, date_time.GetSecond());
}

/**
* @brief Test get as string
*/
Expand Down
Loading

0 comments on commit 336981b

Please sign in to comment.