【GNSS】GREAT多频多系统GREAT-UPD开源代码-第4.2章 代码解读之gtime.h/gtime.cpp

26 篇文章 7 订阅
6 篇文章 1 订阅

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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值