GREAT多频多系统GREAT-UPD开源代码-第4.2章 代码解读之gtime.h/gtime.cpp
介绍
作为Gnut和GREAT-UPD的时间管理类,t_gtime类集成了如下功能:
- JD,MJD,GPST,UTC等各种时间系统间的相互转换
- 支持时间+,-,>,=,<等判断和计算
- 支持格式化输出
整个类的实现只使用了标准std库,可以直接利用到自己相关的GNSS开发当中,节约GNSS-Time相关部分的代码开发时间和精力。
在函数实现中,有着详细的变量介绍和函数解释,上手简单。
具体代码实现见下文。
头文件
#ifndef GTIME_H
#define GTIME_H
/* ----------------------------------------------------------------------
(c) 2011 Geodetic Observatory Pecny, http://www.pecny.cz (gnss@pecny.cz)
Research Institute of Geodesy, Topography and Cartography
Ondrejov 244, 251 65, Czech Republic
Purpose: implements gtime class (day and precise time)
Version: $ Rev: $
2011-01-10 /JD: created
2018-07-13 /JD: updated (fixed current_time, revised FIRST/LAST time, speeded etc.)
* Internal representation is in TAI time-system (TS)
* If input is in other TS, it needs to be set via constructor
* and all inputs are then converted from TS to TAI.
* All outputs are implicitely in TAI thus use of
* gps(), utc(), local() duplicating function is required.
* Input TS can be changed only via convert(TS) function.
-*/
#include <time.h>
#include <string>
#include <string.h>
#ifdef BMUTEX
#include <boost/thread/mutex.hpp> ///< Win/Lin mutex
#endif
#include "gutils/gmutex.h"
#include "gutils/ExportGnut.h"
using namespace std;
namespace gnut {
#if defined GTIME_TAI
#define DEFAULT_TIME TAI ///< default gtime TAI
#elif defined GTIME_UTC
#define DEFAULT_TIME UTC ///< default gtime UTC
#elif defined GTIME_USER
#define DEFAULT_TIME USER ///< default gtime USER
#elif defined GTIME_LOC
#define DEFAULT_TIME LOC ///< default gtime LOCAL
#elif defined GTIME_GPS
#define DEFAULT_TIME GPS ///< default gtime GPS
#else
#define DEFAULT_TIME GPS ///< default gtime GPS
#endif
#define MAX_DT 21 ///< number of time string identifiers /16 to 21/
#define MAXLEAP 50 ///< maximum number of leap second in table
#define TAI_GPS 19 ///< seconds of which GPS is ahead of TAI at 6.1.1980
#define TAI_BDS 33 ///< seconds of which BDS is ahead of TAI at 1.1.2006
#define TAI_GAL 19 ///< coincide with GPS time
#define TAI_TT 32
#define TAT_TT_DSEC 0.184
#define CONV_BWK2GWK 1356 ///< convert BDS to GPS week
const static string MON[13] = { " ", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const int monthdays[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
struct leapsec_table
{
int _year;
int _mon;
int _day;
int _leap;
};
const static struct leapsec_table leapseconds[] = {
{ 1971, 12, 31, 11 },
{ 1972, 12, 31, 12 },
{ 1973, 12, 31, 13 },
{ 1974, 12, 31, 14 },
{ 1975, 12, 31, 15 },
{ 1976, 12, 31, 16 },
{ 1977, 12, 31, 17 },
{ 1978, 12, 31, 18 },
{ 1979, 12, 31, 19 },
{ 1981, 06, 30, 20 },
{ 1982, 06, 30, 21 },
{ 1983, 06, 30, 22 },
{ 1985, 06, 30, 23 },
{ 1987, 12, 31, 24 },
{ 1989, 12, 31, 25 },
{ 1990, 12, 31, 26 },
{ 1992, 06, 30, 27 },
{ 1993, 06, 30, 28 },
{ 1994, 06, 30, 29 },
{ 1995, 12, 31, 30 },
{ 1997, 06, 30, 31 },
{ 1998, 12, 31, 32 },
{ 2005, 12, 31, 33 },
{ 2008, 12, 31, 34 },
{ 2011, 06, 30, 35 },
{ 2015, 06, 30, 36 },
{ 2017, 01, 01, 37 }
};
///< supported io keys of fixed size !
const static string TD[MAX_DT] = {
"Y", ///< [4] year (1900..2099)
"y", ///< [2] 2-dig year (80..99,00..79)
"m", ///< [2] month (1..12+)
"b", ///< [3] month (Jan..Dec)
"d", ///< [2] day of month (1..31+)
"j", ///< [3] day of year (0..365+)
"H", ///< [2] hours (0..23+)
"M", ///< [2] minutes (0..59+)
"S", ///< [2] seconds (0..59+)
"W", ///< [4] GPS week (0000..XXXX)
"w", ///< [1] day of week (0..6)
"v", ///< [6] seconds of week (0..604800+)
"s", ///< [5] seconds of day (0..86400+)
"J", ///< [5] modified julian date = integer only ! (e.g. 55725)
"I", ///< [11] modified julian date (e.g. 55725.81712)
"T", ///< [3] time-system string
"C", ///< [2] month for lsqclk, when single , no zero ( 1, 2,...,10,11,12)
"L", ///< [2] day for lsqclk, when single , no zero ( 1, 2,...,10,...,29,..)
"K", ///< [2] hour for lsqclk, when single , no zero ( 1, 2,...,10,...,24)
"O", ///< [2] minutes for lsqclk, when single , no zero ( 1, 2,...,10,...,60)
"P" ///< [9] seconds for lsqclk, when single , no zero for ten digit.( 1.000000, ...,59.000000)
};
///< conversion to GAL + GLO are not implemented
const static char t_tstr[8][4] = { "USR", "TAI", "UTC", "LOC", "GPS", "GAL", "GLO", "BDS" };
#ifdef BMUTEX
static boost::mutex _static_mutex;
#endif
class GNUT_LIBRARY_EXPORT t_gtime
{
public:
///< conversion to GAL + GLO are not implemented
enum t_tsys { USER, TAI, UTC, LOC, GPS, GAL, GLO, BDS, TT };
/**@brief convert string to tsys */
static string tsys2str(t_tsys ts);
/**@brief convert tsys to string */
static t_tsys str2tsys(string s);
/**@brief constructor */
t_gtime(const t_tsys& ts = DEFAULT_TIME);
t_gtime(const time_t& tt,
const double& dsec = 0,
const t_tsys& ts = DEFAULT_TIME);
t_gtime(const int& yr, const int& mn,
const int& dd, const int& hr,
const int& mi, const int& sc,
const double& ds = 0.0, const t_tsys& ts = DEFAULT_TIME);
t_gtime(const int& gw, const int& dw,
const int& sd, const double& ds = 0.0,
const t_tsys& ts = DEFAULT_TIME);
t_gtime(const int& gw, const double& sow,
const t_tsys& ts = DEFAULT_TIME);
t_gtime(const int& mjd, const int& sd,
const double& ds = 0.0, const t_tsys& ts = DEFAULT_TIME);
/**@brief destructor */
~t_gtime();
/**@brief get current time */
static t_gtime current_time(const t_tsys& ts = DEFAULT_TIME);
/**@brief set from time_t,dsec */
int from_time(const time_t& tt,
const double& ds = 0.0, const bool& conv = true);
/**@brief set from GPSwk,sow,dsec */
int from_gws(const int& gw,
const double& sow, const bool& conv = true);
/**@brief set from GPSwk+dw,sod,dsec */
int from_gwd(const int& gw, const int& dw, const int& sd,
const double& ds = 0.0, const bool& conv = true);
/**@brief set from yr+mn+dd,sod,dsec */
int from_ymd(const int& yr, const int& mn, const int& dd,
const int& sd, const double& ds = 0.0,
const bool& conv = true);
/**@brief set from yr+mn+dd + H+M+S */
int from_ymdhms(const int& yr, const int& mn, const int& dd,
const int& h, const int& m, const double& s,
const bool& conv = true);
/**@brief set from mjd,sod,dsec */
int from_mjd(const int& mjd, const int& sd,
const double& ds = 0.0, const bool& conv = true);
/**@brief set from dmjd */
int from_dmjd(const double& dmjd, const bool& conv = true);
/**@brief set from defined string */
int from_str(const string& ifmt, const string& dat,
const bool& conv = true);
/**@brief reset dsec only (in TAI)! */
int reset_dsec();
/**@brief reset sod + dsec only (in TAI)! */
int reset_sod();
/**@brief set new io time-system */
int tsys(const t_tsys& ts) { _tsys = ts; return 0; }
/**@brief get functions (default includes conversion to _tsys, if conv=false return TAI) */
int mjd(const bool& conv = true) const; ///< get MJD
double dmjd(const bool& conv = true) const; ///< get MJD
int sod(const bool& conv = true) const; ///< get seconds of day
double dsec(const bool& conv = true) const; ///< get fractional sec
/**@brief get functions (always includes conversion to _tsys, for TAI use only mjd, sod and dsec) */
time_t tim() const; ///< get time_t
int gwk() const; ///< get GPS week
int bwk() const; ///< get BDS week
int dow() const; ///< get integer day of GPS week
int sow() const; ///< get integer Sec of Week
int year() const; ///< get integer 4-char year
int yr() const; ///< get integer 2-char year (1980-2079 only)
int doy(const bool& conv = true) const; ///< get integer day of year
int day() const; ///< get integer day of month
int mon() const; ///< get integer day
int hour() const; ///< get integer hour
int mins() const; ///< get integer minute
int secs() const; ///< get integer seconds
string sys() const; ///< get time system identifier
/**@brief get hour, minute, seconds */
void hms(int& h, int& m, int& s, bool conv = true) const;
/**@brief get year, month, day */
void ymd(int& y, int& m, int& d, bool conv = true) const;
/**@brief get any string */
string str(const string& ofmt = "%Y-%m-%d %H:%M:%S",
const bool& conv = true) const;
/**@brief get fixed date string */
string str_ymd(const string& str = "",
const bool& conv = true) const;
/**@brief get fixed time string */
string str_hms(const string& str = "",
const bool& conv = true) const;
/**@brief get fixed date and time string */
string str_ymdhms(const string& str = "",
const bool& ts = true,
const bool& conv = true) const;
/**@brief get fixed mjd and sod string */
string str_mjdsod(const string& str = "",
const bool& ts = true,
const bool& conv = true) const;
/**@brief get strings of time ... */
string str_yyyydoy(const bool& conv = true) const;
string str_yyyy(const bool& conv = true) const;
string str_doy(const bool& conv = true) const;
string str_gwkd(const bool& conv = true) const;
string str_gwk(const bool& conv = true) const;
string str_yr(const bool& conv = true) const;
string str_mon(const bool& conv = true) const;
string str_day(const bool& conv = true) const;
/**@brief general conversion functions */
int yr(const int& y) const; ///< get integer 2-char year (1980-2079 only)
string mon(const int& m) const; ///< get month string
int mon(const string& str) const; ///< get month number
int tzdiff() const; ///< get UTC-LOC difference [sec]
int dstime() const; ///< get day-saving time [sec]
int leapsec() const; ///< get TAI-UTC leap seconds [sec]
int leapyear(const int& y) const; ///< get YEAR with leapsec [0,1]
int tai_tsys(const t_tsys& ts) const; ///< get TAI-tsys difference [sec]
double tai_tsys_dsec(const t_tsys& ts) const; ///< get TAI-tsys difference [dsec]
t_tsys tsys() const { return _tsys; } ///< get required inp/out time-system
void add_secs(const int& sec); ///< date/time with added X-seconds
void add_dsec(const double& dsec); ///< date/time with added X-dseconds
double diff(const t_gtime& t) const; ///< time difference (this - t) [s]
/**@brief overloading operator */
bool operator<(const t_gtime& t) const;
bool operator<=(const t_gtime& t) const;
bool operator>=(const t_gtime& t) const;
bool operator>(const t_gtime& t) const;
bool operator==(const t_gtime& t) const;
bool operator!=(const t_gtime& t) const;
double operator-(const t_gtime& t) const; ///< [sec]
bool operator<(const double& t) const;
t_gtime operator-(const double& sec) const; ///< gtime
t_gtime operator+(const double& sec) const; ///< gtime
t_gtime operator=(const t_gtime& t);
friend bool operator<(double left, const t_gtime &t);
friend bool operator<(const t_gtime &t, double left);
/**@brief multiplatform msleep function [ms] */
static void gmsleep(unsigned int ms);
/**@brief multiplatform usleep function [us] */
static void gusleep(unsigned int us);
protected:
private:
int _mjd; ///< integer MJD [TAI]
int _sod; ///< seconds of day [TAI]
double _dsec; ///< fractional seconds
t_tsys _tsys; ///< time system
t_gtime _tai_to(); ///< conversion from TAI to TS with changing gtime !
void _to_tai(); ///< conversion from TS to TAI with changing gtime !
void _norm_dsec(); ///< normalize dsec (range in 0-1 sec)
void _norm_sod(); ///< normalize sod (range in 0-86399 sec)
void _norm_year(int& year) const; ///< normalize year (range 1980 - 2079)
int _ymd_mjd(const int& yr,
const int& mn,
const int& dd) const;
enum t_tymd { _ymd = 0, _year = 1, _mon = 2, _day = 4 }; ///< internal counter
enum t_thms { _hms = 0, _hour = 1, _min = 2, _sec = 4 }; ///< internal counter
};
const static t_gtime FIRST_TIME(44239, 0, 0.0, t_gtime::TAI); ///< first valid time "1980-01-01 00:00:00"
const static t_gtime LAST_TIME(80763, 86399, 0.0, t_gtime::TAI); ///< last valid time "2079-12-31 23:59:59"
/**@brief get max time */
GNUT_LIBRARY_EXPORT t_gtime MAX_TIME(const t_gtime& A, const t_gtime& B);
/**@brief get min time */
GNUT_LIBRARY_EXPORT t_gtime MIN_TIME(const t_gtime& A, const t_gtime& B);
} // namespace
#endif
CPP
/* ----------------------------------------------------------------------
* G-Nut - GNSS software development library
*
(c) 2011 Geodetic Observatory Pecny, http://www.pecny.cz (gnss@pecny.cz)
Research Institute of Geodesy, Topography and Cartography
Ondrejov 244, 251 65, Czech Republic
This file is part of the G-Nut C++ library.
This library 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.
This library 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 for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see <http://www.gnu.org/licenses>.
-*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
#include <algorithm>
#if defined _WIN32 || defined _WIN64
#include <io.h>
#include <windows.h>
#else
#include <unistd.h>
#endif
#include "gutils/gtime.h"
#include "gutils/gtypeconv.h"
using namespace std;
namespace gnut {
t_gtime::t_gtime(const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(UTC)
{
from_time(time(NULL), 0.0, true); // input UTC time-system
_tsys = ts; // now switch to required TS
}
t_gtime::t_gtime(const time_t& tt, const double& ds, const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(UTC)
{
from_time(tt, ds, true); // input UTC time-system
_tsys = ts; // now switch to required TS
}
t_gtime::t_gtime(const int& yr, const int& mn,
const int& dd, const int& hr,
const int& mi, const int& sc,
const double& ds, const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(ts)
{
from_ymdhms(yr, mn, dd, hr, mi, sc + ds, true);
}
t_gtime::t_gtime(const int& gw, const int& dw, const int& sd,
const double& ds, const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(ts)
{
from_gwd(gw, dw, sd, ds, true);
}
t_gtime::t_gtime(const int& gw, const double& sow, const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(ts)
{
from_gws(gw, sow, true);
}
t_gtime::t_gtime(const int& mjd, const int& sd,
const double& ds, const t_tsys& ts)
: _mjd(0), _sod(0), _dsec(0.0), _tsys(ts)
{
from_mjd(mjd, sd, ds, true);
}
t_gtime::~t_gtime()
{}
string t_gtime::tsys2str(t_tsys ts)
{
switch (ts) {
case USER: return "USER";
case TAI: return "TAI";
case UTC: return "UTC";
case LOC: return "LOC";
case GPS: return "GPS";
case GLO: return "GLO";
case GAL: return "GAL";
case BDS: return "BDS";
case TT: return "TT";
default: { cout << "*** warning: unknown time system!\n"; cout.flush(); }
}
return "TAI";
}
t_gtime::t_tsys t_gtime::str2tsys(string s)
{
if (s.size() == 0) {
cout << "*** warning: not defined time system\n"; cout.flush();
return TAI;
}
transform(s.begin(), s.end(), s.begin(), ::toupper);
if (s == "USER") return USER;
else if (s == "TAI") return TAI;
else if (s == "UTC") return UTC;
else if (s == "LOC") return LOC;
else if (s == "GPS") return GPS;
else if (s == "GLO") return GLO;
else if (s == "GAL") return GAL;
else if (s == "BDS") return BDS;
else if (s == "TT") return TT;
else { cout << "*** warning: not defined correct time system [" << s[0] << "]\n"; cout.flush(); }
return TAI;
}
t_gtime t_gtime::current_time(const t_tsys& ts)
{
t_gtime tmp(UTC);
tmp.from_time(time(NULL), 0.0, true);
tmp.tsys(ts);
return tmp;
}
int t_gtime::from_time(const time_t& tt, const double& ds, const bool& conv)
{
struct tm* tm = gmtime(&tt);
from_ymd(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec,
ds, conv);
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_gws(const int& gw, const double& sow, const bool& conv)
{
int dw = (int)floor(sow / 86400);
_mjd = 44244 + 7 * gw + dw;
_sod = (int)floor(sow - dw * 86400.0);
_dsec = sow - dw * 86400.0 - _sod;
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_gwd(const int& gw, const int& dw, const int& sd,
const double& ds, const bool& conv)
{
_mjd = 44244 + 7 * gw + dw;
_sod = sd;
_dsec = ds;
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_ymd(const int& yr, const int& mn, const int& dd,
const int& sd, const double& ds, const bool& conv)
{
int year(yr);
_norm_year(year);
_mjd = _ymd_mjd(year, mn, dd);
_sod = sd;
_dsec = ds;
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_ymdhms(const int& yr, const int& mn,
const int& dd, const int& h,
const int& m, const double& s,
const bool& conv)
{
int year(yr);
_norm_year(year);
_mjd = _ymd_mjd(year, mn, dd);
_sod = int((h * 3600.0 + m * 60.0) + floor(s));
_dsec = s - 1.0 * (floor(s));
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_mjd(const int& mjd, const int& sd,
const double& ds, const bool& conv)
{
_mjd = mjd;
_sod = sd;
_dsec = ds;
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_dmjd(const double& dmjd, const bool& conv)
{
_mjd = (int)dmjd;
_sod = (int)((dmjd - _mjd) * 86400.0);
_dsec = (dmjd - _mjd) * 86400.0 - _sod;
if (conv) _to_tai(); // CONVERT
_norm_dsec();
_norm_sod();
return 0;
}
int t_gtime::from_str(const string& ifmt, const string& idat, const bool& conv)
{
int cYMD = _ymd;
int cHMS = _hms;
int y, b, d, h, m, s; y = b = d = h = m = s = 0;
size_t idx;
size_t fmtadd = 0;
size_t datadd = 0;
size_t fmtpos = 0;
size_t datpos = 0;
// search and process keys from left to right
while ((fmtpos < ifmt.length()) && (idx = ifmt.find('%', fmtpos)) != string::npos) {
fmtpos++; // a priori encrease
for (int i = 0; i < MAX_DT; ++i) {
string tmp = TD[i];
// too short ifmt format string, skip!
if (ifmt.length() - idx - 1 < tmp.length()) continue;
// dat string not identified, skipped !
if (ifmt.substr(idx + 1, tmp.length()).compare(tmp) != 0) continue;
fmtpos = idx + tmp.length() + 1; // end of format reading
datpos = idx - fmtadd + datadd; // sum of all idat characters
fmtadd += tmp.length() + 1; // sum of all ifmt characters
if (!tmp.compare("Y")) {
y = str2int(idat.substr(datpos, 4)); datadd += 4; cYMD += t_tymd(_year);
}
else if (!tmp.compare("y")) {
y = str2int(idat.substr(datpos, 2)); datadd += 2; cYMD += t_tymd(_year);
}
else if (!tmp.compare("b")) {
b = mon(idat.substr(datpos, 3)); datadd += 3; cYMD += t_tymd(_mon);
}
else if (!tmp.compare("m")) {
b = str2int(idat.substr(datpos, 2)); datadd += 2; cYMD += t_tymd(_mon);
}
else if (!tmp.compare("d")) {
d = str2int(idat.substr(datpos, 2)); datadd += 2; cYMD += t_tymd(_day);
}
else if (!tmp.compare("j")) {
b = 1; cYMD += t_tymd(_mon);
d = str2int(idat.substr(datpos, 3)); datadd += 3; cYMD += t_tymd(_day);
}
else if (!tmp.compare("H")) {
h = str2int(idat.substr(datpos, 2)); datadd += 2; cHMS += t_thms(_hour);
}
else if (!tmp.compare("M")) {
m = str2int(idat.substr(datpos, 2)); datadd += 2; cHMS += t_thms(_min);
}
else if (!tmp.compare("S")) {
s = str2int(idat.substr(datpos, 2)); datadd += 2; cHMS += t_thms(_sec);
}
else if (!tmp.compare("W")) {
y = 1980; cYMD += t_tymd(_year);
b = 1; cYMD += t_tymd(_mon);
d += 6 + str2int(idat.substr(datpos, 4)) * 7; datadd += 4;
}
else if (!tmp.compare("w")) {
d += str2int(idat.substr(datpos, 1)); datadd += 1; cYMD += t_tymd(_day);
}
else if (!tmp.compare("v")) {
s += str2int(idat.substr(datpos, 6)); datadd += 6; cYMD += t_tymd(_day);
cHMS += t_thms(_hour)
+ t_thms(_min)
+ t_thms(_sec);
}
else if (!tmp.compare("s")) {
s = str2int(idat.substr(datpos, 5)); datadd += 5; cHMS += t_thms(_hour)
+ t_thms(_min)
+ t_thms(_sec);
}
else if (!tmp.compare("I")) {
y = 2000; cYMD += t_tymd(_year);
b = 1; cYMD += t_tymd(_mon);
d = 1 - 51544 + (str2int(idat.substr(datpos, 11)));
cYMD += t_tymd(_day);
s = 86400 * (str2int(idat.substr(datpos, 11))
- (str2int(idat.substr(datpos, 11))));
datadd += 11; cHMS += t_thms(_hour)
+ t_thms(_min)
+ t_thms(_sec);
}
else if (!tmp.compare("J")) {
y = 2000; cYMD += t_tymd(_year);
b = 1; cYMD += t_tymd(_mon);
d = 1 - 51544 + str2int(idat.substr(datpos, 5));
datadd += 5; cYMD += t_tymd(_day);
}
else if (!tmp.compare("T")) {
cerr << "input time-system conversion not yet supported here!\n";
}
else {
cerr << " warning : t_gtime - unknown date/time identifier [" << tmp << "]\n";
}
}
}
if (cYMD == (_year | _mon | _day) && cHMS == (_hour | _min | _sec)) {
from_ymd(y, b, d, h * 3600 + m * 60 + s, 0.0, conv);
return 0;
}
if (cYMD == (_year | _mon | _day)) {
from_ymd(y, b, d, 0, 0.0, conv);
return 0;
}
return 1;
}
int t_gtime::reset_dsec() {
_norm_dsec();
_dsec = 0.0;
return 0;
}
int t_gtime::reset_sod() {
_norm_sod();
_tai_to();
_sod = 0;
_to_tai();
reset_dsec();
return 0;
}
int t_gtime::tzdiff() const
{
switch (_tsys) {
case USER: return 0;
case TAI: return 0;
case UTC: return 0;
case GPS: return 0;
case GLO: return 3 * 3600;
case GAL: return 0;
case BDS: return 0;
case LOC: { time_t local, utc;
local = time(NULL);
utc = mktime(gmtime(&local));
return int(local - utc);
}
default: cerr << " warning : t_tsys not recognized !\n";
}
return 0;
}
int t_gtime::dstime() const
{
switch (_tsys) {
case USER: return 0;
case TAI: return 0;
case UTC: return 0;
case GPS: return 0;
case GLO: return 0;
case BDS: return 0;
case GAL: return 0;
case LOC: {
struct tm tm;
ymd(tm.tm_year, tm.tm_mon, tm.tm_mday, false); // TAI !
hms(tm.tm_hour, tm.tm_min, tm.tm_sec, false); // TAI !
tm.tm_year -= 1900;
tm.tm_mon -= 1;
tm.tm_sec -= leapsec() + tzdiff(); // convert tai to LOC !
tm.tm_isdst = -1;
mktime(&tm);
return int(3600.0 * tm.tm_isdst); // [sec]
}
default: cerr << " warning : t_tsys not recognized !\n";
}
return 0;
}
int t_gtime::leapsec() const
{
int leap = 0;
for (int i = sizeof(leapseconds) / sizeof(*leapseconds) - 1; i >= 0; --i) {
double mjd_time = _mjd + _sod / 86400.0 - leapseconds[i]._leap / 86400.0;
double mjd_leap = static_cast<double>(_ymd_mjd(leapseconds[i]._year,
leapseconds[i]._mon,
leapseconds[i]._day));
if (mjd_leap <= mjd_time) {
leap = leapseconds[i]._leap;
break;
}
}
return leap;
}
int t_gtime::leapyear(const int& y) const
{
if (y % 4 == 0.0) return 1; // leap year !
if (y % 400 == 0.0) return 1; // leap year !
if (y % 100 == 0.0) return 0; // not leap year
return 0;
}
int t_gtime::mjd(const bool& conv) const
{
// do not convert
if (!conv || _tsys == USER || _tsys == TAI) return _mjd;
// do convert
int mjd = _mjd + floor( (_sod + tai_tsys(_tsys) + _dsec + tai_tsys_dsec(_tsys)) / 86400.0);// 86400.0 have to be float!
return mjd;
}
double t_gtime::dmjd(const bool& conv) const
{
double ret;
ret = dsec(conv) / 86400.0 + (double)sod(conv) / 86400.0 + (double)mjd(conv);
return ret;
}
int t_gtime::sod(const bool& conv) const
{
// do not convert
if (!conv || _tsys == USER || _tsys == TAI) return _sod;
// do convert
double sod = _sod + tai_tsys(_tsys) + _dsec + tai_tsys_dsec(_tsys);
while (sod >= 86400) { sod -= 86400; }
while (sod < 0) { sod += 86400; }
return sod;
}
double t_gtime::dsec(const bool& conv) const
{
// do not convert
if (!conv || _tsys == USER || _tsys == TAI) return _dsec;
// do convert
double dsec = 0.0;
dsec = _dsec + tai_tsys_dsec(_tsys);
while (dsec >= 1.0) { dsec -= 1.0; }
while (dsec < 0.0) { dsec += 1.0; }
return dsec;
}
time_t t_gtime::tim() const
{
int y, b, d, h, m, s;
ymd(y, b, d, true); // convert to UTC ?
hms(h, m, s, true); // convert to TAI UTC ?
struct tm t;
t.tm_year = y - 1900;
t.tm_mon = b - 1;
t.tm_mday = d;
t.tm_hour = h;
t.tm_min = m;
t.tm_sec = s;
t.tm_isdst = -1;
return mktime(&t);
}
int t_gtime::doy(const bool& conv) const
{
int y, m, d;
ymd(y, m, d, conv);
int doy = d;
for (int i = 0; i < m && i < 13; ++i) doy += monthdays[i];
if (m > 2) doy += leapyear(y); // count for leap year
return doy;
}
int t_gtime::bwk() const
{
return static_cast<int>((mjd(true) - 44244.0) / 7.0) - CONV_BWK2GWK; // return true TS
}
int t_gtime::gwk() const
{
return static_cast<int>((mjd(true) - 44244.0) / 7.0); // return true TS
}
int t_gtime::dow() const
{
return static_cast<int>(mjd(true) - 44244.0 - gwk() * 7); // no problem gwk for BDS here
}
int t_gtime::sow() const
{
return static_cast<int>(dow() * 86400.0 + sod()); // no problem gwk for BDS here
}
int t_gtime::year() const
{
int y, m, d;
ymd(y, m, d, false);
return static_cast<int>(y);
}
int t_gtime::yr() const
{
int y, m, d;
ymd(y, m, d, false);
int yr = this->yr(y);
return yr;
}
int t_gtime::mon() const
{
int y, m, d;
ymd(y, m, d, true);
return static_cast<int>(m);
}
int t_gtime::day() const
{
int y, m, d;
ymd(y, m, d, true);
return static_cast<int>(d);
}
int t_gtime::hour() const
{
return static_cast<int>((sod(true) % 86400) / 3600.0);
}
int t_gtime::mins() const
{
return static_cast<int>((sod(true) % 3600) / 60.0);
}
int t_gtime::secs() const
{
return static_cast<int>(sod(true) % 60);
}
void t_gtime::hms(int& h, int& m, int& s, bool conv) const
{
h = static_cast<int>((sod(conv) % 86400) / 3600.0);
m = static_cast<int>((sod(conv) % 3600) / 60.0);
s = static_cast<int>((sod(conv) % 60));
}
void t_gtime::ymd(int& y, int& m, int& d, bool conv) const
{
int jj, mm, dd;
long ih, ih1, ih2;
double t1, t2, t3, t4;
double mjd = 0.0;
mjd = this->mjd(conv) + (this->sod(conv)) / 86400.0;
t1 = 1.0 + mjd - fmod(mjd, 1.0) + 2400000.0;
t4 = fmod(mjd, 1.0);
ih = int((t1 - 1867216.25) / 36524.25);
t2 = t1 + 1 + ih - ih / 4;
t3 = t2 - 1720995.0;
ih1 = int((t3 - 122.1) / 365.25);
t1 = ih1 * 365.25 - fmod(ih1 * 365.25, 1.0);
ih2 = int((t3 - t1) / 30.6001);
dd = int(t3 - t1 - int(ih2 * 30.6001) + t4);
mm = ih2 - 1;
if (ih2 > 13) mm = ih2 - 13;
jj = ih1;
if (mm <= 2) jj = jj + 1;
y = jj;
m = mm;
d = dd;
}
string t_gtime::str(const string& ofmt, const bool& conv) const
{
t_gtime gt(*this);
char cstr[12] = "char";
string str = ofmt; // copy of requested format
size_t idx = 0;
int y, b, d, h, m, s;
gt.ymd(y, b, d, conv);
gt.hms(h, m, s, conv);
int y2 = gt.yr(y);
// search and process all % identificators
while ((idx = str.find('%')) != string::npos && idx + 1 <= str.length()) {
bool replace = false;
for (int i = 0; i < MAX_DT; ++i) {
string tmp = TD[i];
// dat string not identified, skipped !
if (str.substr(idx + 1, tmp.length()).compare(tmp) != 0) continue;
if (!tmp.compare("Y")) {
sprintf(cstr, "%04i", y);
}
else if (!tmp.compare("y")) {
sprintf(cstr, "%02i", y2);
}
else if (!tmp.compare("b")) {
sprintf(cstr, "%3.3s", gt.mon(b).c_str());
}
else if (!tmp.compare("m")) {
sprintf(cstr, "%02i", b);
}
else if (!tmp.compare("d")) {
sprintf(cstr, "%02i", d);
}
else if (!tmp.compare("j")) {
sprintf(cstr, "%03i", gt.doy());
}
else if (!tmp.compare("H")) {
sprintf(cstr, "%02i", h);
}
else if (!tmp.compare("M")) {
sprintf(cstr, "%02i", m);
}
else if (!tmp.compare("S")) {
sprintf(cstr, "%02i", s);
}
else if (!tmp.compare("W")) {
sprintf(cstr, "%04i", gt.gwk());
}
else if (!tmp.compare("w")) {
sprintf(cstr, "%01i", gt.dow());
}
else if (!tmp.compare("v")) {
sprintf(cstr, "%6i", gt.sow());
}
else if (!tmp.compare("s")) {
sprintf(cstr, "%5i", gt.sod(conv));
}
else if (!tmp.compare("J")) {
sprintf(cstr, "%5i", gt.mjd(conv));
}
else if (!tmp.compare("I")) {
sprintf(cstr, "%11.5f", gt.mjd(conv)
+ gt.sod(conv) / 86400.0
+ gt.dsec(conv) / 86400.0);
}
else if (!tmp.compare("T")) {
sprintf(cstr, "%3s", sys().c_str());
}
else if (!tmp.compare("C")) {
sprintf(cstr, "%2i", b);
}
else if (!tmp.compare("L")) {
sprintf(cstr, "%2i", d);
}
else if (!tmp.compare("K")) {
sprintf(cstr, "%2i", h);
}
else if (!tmp.compare("O")) {
sprintf(cstr, "%2i", m);
}
else if (!tmp.compare("P")) {
sprintf(cstr, "%9.6f", static_cast<double>(s));
}
else {
cerr << " warning : t_gtime - unknown date/time identifier [" << tmp << "]\n";
}
str.replace(idx, 2, cstr);
replace = true;
}
// replace unknown % occurance
if (!replace) str.replace(idx, 1, "");
}
return str;
}
string t_gtime::str_ymd(const string& str, const bool& conv) const
{
char cstr[12];
int y = 0, b = 0, d = 0;
this->ymd(y, b, d, conv);
sprintf(cstr, "%04i-%02i-%02i", y, b, d);
return str + " " + string(cstr);
}
string t_gtime::str_hms(const string& str, const bool& conv) const
{
char cstr[12];
int h = 0, m = 0, s = 0;
this->hms(h, m, s, conv);
sprintf(cstr, "%02i:%02i:%02i", h, m, s);
return str + " " + string(cstr);
}
string t_gtime::str_ymdhms(const string& str,
const bool& ts,
const bool& conv) const
{
char cstr[25];
int y = 0, b = 0, d = 0, h = 0, m = 0, s = 0;
this->ymd(y, b, d, conv);
this->hms(h, m, s, conv);
if (ts) sprintf(cstr, "%04i-%02i-%02i %02i:%02i:%02i[%3s]", y, b, d, h, m, s, sys().c_str());
else sprintf(cstr, "%04i-%02i-%02i %02i:%02i:%02i", y, b, d, h, m, s);
return str + " " + string(cstr);
}
string t_gtime::str_mjdsod(const string& str, const bool& ts, const bool& conv) const
{
char cstr[25];
int mjd = this->mjd(ts);
double sod = (this->dmjd(ts) - mjd) * 86400.0;
int isod = 0;
if (fabs(sod - (int)(sod)) < 0.5e0)
{
isod = round(sod);
sprintf(cstr, "%05i %10.4f", mjd, static_cast<double>(isod));
}
else
{
sprintf(cstr, "%05i %10.4f", mjd, sod);
}
return str + " " + string(cstr);
}
string t_gtime::str_yyyydoy(const bool& conv) const
{
int year, doy;
string tmp;
year = this->year();
doy = this->doy(conv);
string cdoy = int2str(doy);
if (doy >= 10 && doy < 100) cdoy = "0" + cdoy;
if (doy < 10) cdoy = "00" + cdoy;
tmp = int2str(year) + cdoy;
return tmp;
}
string t_gtime::str_yyyy(const bool& conv) const
{
return int2str(this->year());
};
string t_gtime::str_doy(const bool& conv) const
{
string tmp = int2str(this->doy());
if (tmp.size() == 1) return "00" + tmp;
else if (tmp.size() == 2) return "0" + tmp;
else return tmp;
};
string t_gtime::str_gwkd(const bool& conv) const
{
return int2str(this->gwk()) + int2str(this->dow());
}
string t_gtime::str_gwk(const bool& conv) const
{
return int2str(this->gwk());
}
string t_gtime::str_yr(const bool& conv) const
{
string tmp = int2str(this->yr());
if (tmp.size() == 1) return "0" + tmp;
else return tmp;
}
string t_gtime::str_mon(const bool& conv) const
{
string tmp = int2str(this->mon());
if (tmp.size() == 1) return "0" + tmp;
else return tmp;
}
string t_gtime::str_day(const bool& conv) const
{
string tmp = int2str(this->day());
if (tmp.size() == 1) return "0" + tmp;
else return tmp;
}
int t_gtime::yr(const int& y) const
{
if (y <= 2079 && y >= 2000) return y - 2000;
if (y < 2000 && y >= 1980) return y - 1900;
return -1;
}
string t_gtime::mon(const int& m) const
{
if (m < 1 || m > 12) return "XXX";
return MON[m];
}
int t_gtime::mon(const string& str) const
{
for (int i = 1; i <= 12; ++i) {
if (str.compare(MON[i]) == 0)
return i;
}
return 0;
}
string t_gtime::sys() const
{
string ts(t_tstr[_tsys]);
return ts;
}
double t_gtime::operator-(const t_gtime& t) const
{
return (this->diff(t));
}
bool t_gtime::operator<(const double& t) const
{
return (this->sow() + this->dsec() < t);
}
t_gtime t_gtime::operator-(const double& sec) const
{
t_gtime tmp(*this);
tmp.add_secs(-static_cast<int>(sec));
tmp.add_dsec(-static_cast<double>(sec - static_cast<int>(sec))); // already normed
return tmp;
}
t_gtime t_gtime::operator+(const double& sec) const
{
t_gtime tmp(*this);
int second = floor(sec);
double dsecond = sec - second;
tmp.add_secs(second);
tmp.add_dsec(dsecond);
return tmp;
}
bool t_gtime::operator<(const t_gtime& t) const
{
return ((mjd(true) < t.mjd(true))
|| (mjd(true) == t.mjd(true) && sod(true) < t.sod(true))
|| (mjd(true) == t.mjd(true) && sod(true) == t.sod(true) && dsec(true) < t.dsec(true))
);
}
bool t_gtime::operator<=(const t_gtime& t) const
{
return (*this < t || *this == t);
}
bool t_gtime::operator>=(const t_gtime& t) const
{
return (*this > t || *this == t);
}
bool t_gtime::operator>(const t_gtime& t) const
{
return ((mjd(true) > t.mjd(true))
|| (mjd(true) == t.mjd(true) && sod(true) > t.sod(true))
|| (mjd(true) == t.mjd(true) && sod(true) == t.sod(true) && dsec(true) > t.dsec(true))
);
}
bool t_gtime::operator==(const t_gtime& t) const
{
return (mjd(true) == t.mjd(true) && sod(true) == t.sod(true) && dsec(true) == t.dsec(true));
}
bool t_gtime::operator!=(const t_gtime& t) const
{
return (mjd(true) != t.mjd(true) || sod(true) != t.sod(true) || dsec(true) != t.dsec(true));
}
t_gtime t_gtime::operator=(const t_gtime& t)
{
_mjd = t.mjd(false);
_sod = t.sod(false);
_dsec = t.dsec(false);
tsys(t.tsys());
return *this;
}
void t_gtime::add_secs(const int& sec)
{
_sod += sec;
_norm_sod();
}
void t_gtime::add_dsec(const double& dsec)
{
_dsec += dsec;
_norm_dsec();
_norm_sod();
}
double t_gtime::diff(const t_gtime& t) const
{
bool b = false; // compare in TAI
return ((dsec(b) - t.dsec(b)) + (sod(b) - t.sod(b)) + (mjd(b) * 86400.0 - t.mjd(b) * 86400.0));
}
// -----------------------------------------------------------------------------------
// private functions
// -----------------------------------------------------------------------------------
void t_gtime::_to_tai()
{
_norm_dsec();
_norm_sod();
switch (_tsys) {
case USER: break;;
case TAI: break;;
case UTC: _sod += leapsec(); break;;
case GPS: _sod += TAI_GPS; break;;
case GLO: _sod -= tzdiff();
_sod += leapsec(); break;;
case GAL: _sod += TAI_GAL; break;;
case BDS: _sod += TAI_BDS; break;;
case LOC: _sod -= tzdiff();
_sod -= dstime();
_sod += leapsec(); break;;
case TT: _sod-= TAI_TT;
_dsec -= TAT_TT_DSEC; break;;
default: break;;
}
_norm_dsec();
_norm_sod();
}
t_gtime t_gtime::_tai_to()
{
_sod += tai_tsys(_tsys);
_dsec += tai_tsys_dsec(_tsys);
_norm_dsec();
_norm_sod();
return *this;
}
int t_gtime::tai_tsys(const t_tsys& ts) const
{
double sec = 0.0;
switch (ts) {
case USER: break;;
case TAI: break;;
case UTC: sec -= leapsec(); break;;
case GPS: sec -= TAI_GPS; break;;
case GLO: sec -= leapsec();
sec += tzdiff(); break;;
case GAL: sec -= TAI_GAL; break;;
case BDS: sec -= TAI_BDS; break;;
case LOC: sec -= leapsec();
sec += dstime();
sec += tzdiff(); break;;
case TT: sec += TAI_TT; break;;
default: break;;
}
return sec;
}
double t_gtime::tai_tsys_dsec(const t_tsys & ts) const
{
double sec = 0.0;
switch (ts) {
case TT: sec += TAT_TT_DSEC; break;;
default: break;;
}
return sec;
}
void t_gtime::_norm_dsec()
{
while (_dsec >= 1.0) { _dsec -= 1.0; _sod += 1; }
while (_dsec < 0.0) { _dsec += 1.0; _sod -= 1; }
}
void t_gtime::_norm_sod()
{
while (_sod >= 86400) { _sod -= 86400; _mjd += 1; }
while (_sod < 0) { _sod += 86400; _mjd -= 1; }
}
void t_gtime::_norm_year(int& year) const
{
if (year < 100.0) year += year < 80 ? 2000 : 1900;
}
int t_gtime::_ymd_mjd(const int& yr, const int& mn, const int& dd) const
{
int year(yr);
int mon(mn);
_norm_year(year);
double mjd = 0.0;
if (mon <= 2) { mon = mon + 12; year = year - 1; }
mjd = 365.25 * year - fmod(365.25 * year, 1.0) - 679006.0;
mjd += floor(30.6001 * (mon + 1)) + 2.0 - floor(year / 100) + floor(year / 400) + dd;
return int(mjd);
}
// multiplatform ms sleep function
void t_gtime::gmsleep(unsigned int ms) // milisecond
{
#if defined __linux__
usleep(ms * 1000);
#elif defined __APPLE__
usleep(ms * 1000);
#elif defined _WIN32 || defined _WIN64
Sleep(ms);
#else
clock_t goal = ms + clock();
while (goal > clock());
#endif
}
void t_gtime::gusleep(unsigned int us)
{
#if defined __linux__
usleep(us);
#elif defined __APPLE__
usleep(us);
#elif defined _WIN32 || defined _WIN64
this_thread::sleep_for(chrono::microseconds(us)); // c++11 feature
#endif
}
bool operator<(double left, const t_gtime& t)
{
return (left < t.sow() + t.dsec());
}
bool operator<(const t_gtime& t, double left)
{
return (t.sow() + t.dsec(), left);
}
t_gtime MAX_TIME(const t_gtime& A, const t_gtime& B)
{
if (A > B) return A;
else return B;
}
t_gtime MIN_TIME(const t_gtime& A, const t_gtime& B)
{
if (A > B) return B;
else return A;
}
} // namespace