TimeUtils.hpp

source: wtcpp/folder98/folder02/folder1/file06.md

/*!
 * \file TimeUtils.hpp
 * \project	WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief 时间处理的封装
 */
#pragma once
#include <stdint.h>
#include <sys/timeb.h>
#ifdef _MSC_VER
#include <time.h>
#else
#include <sys/time.h>
#endif
#include <string>
#include <string.h>
#include<chrono>


/*
项目中大多数时间是数值型时间, 代码注释很难精确描述, 使用时建议查看源码
*/

/*
时间及结构体转换代码提示

struct timeb{
	time_t time;   // 为1970-01-01至今的秒数
	unsigned short millitm; // 千分之一秒即毫秒
	short timezone;  // 为时区和Greenwich相差的时间,单位为分钟
	short dstflag;   // 为日光节约时间的修正状态,如果为非0代表启用日光节约时间修正
};

timeb now;		// 时间结构体
ftime(&now);	// 取得当前日期和时间

struct tm {
	int tm_sec;         // 秒,范围从 0 到 59
	int tm_min;         // 分,范围从 0 到 59
	int tm_hour;        // 小时,范围从 0 到 23
	int tm_mday;        // 一月中的第几天,范围从 1 到 31
	int tm_mon;         // 月份,范围从 0 到 11
	int tm_year;        // 自 1900 起的年数
	int tm_wday;        // 一周中的第几天,范围从 0 到 6
	int tm_yday;        // 一年中的第几天,范围从 0 到 365
	int tm_isdst;       // 夏令时
};

// 获取本地时间结构体
tm * tNow = localtime(&(now.time));
*/

#define CTIME_BUF_SIZE 64

class TimeUtils {
	
public:
	// 获取本地数值型时间: 精确到毫秒
	static inline int64_t getLocalTimeNow(void)
	{
		timeb now;
		ftime(&now);
		return now.time * 1000 + now.millitm;
	}
	// 获取本地时间: 纳秒
	static inline int64_t getLocalTimeNano(void)
	{
		return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
	}
	// 获取本地时间: 字符串
	static inline std::string getLocalTime(bool bIncludeMilliSec = true)
	{
		timeb now;
		ftime(&now);
		tm * tNow = localtime(&(now.time));

		char str[64] = {0};
		if(bIncludeMilliSec)
			sprintf(str, "%02d:%02d:%02d,%03d", tNow->tm_hour, tNow->tm_min, tNow->tm_sec, now.millitm);
		else
			sprintf(str, "%02d:%02d:%02d", tNow->tm_hour, tNow->tm_min, tNow->tm_sec);
		return str;
	}

	// 返回当前时间字符串
	static inline std::string now(void) 
	{
		using namespace std; // For time_t, time and ctime;
		time_t now = time(0);
		std::string str = ctime(&now);
		return str;
	}

	// 获取格式化时间
	static inline std::string getYYYYMMDD(void)
	{
		std::string yyyymmdd;
		tm local;
		time_t now;
		time(&now);
#ifdef _WIN32
		localtime_s(&local, &now);
#else
		localtime_r(&now, &local);
#endif
		char year[5];
		sprintf(year, "%d", local.tm_year + 1900);
		char month[3];
		sprintf(month, "%02d",local.tm_mon+1);
		char day[3];
		sprintf(day, "%02d",local.tm_mday);
		std::string ofilename;
		yyyymmdd.append(year);
		yyyymmdd.append(month);
		yyyymmdd.append(day);
		return yyyymmdd;
	}
	// 获取格式化时间
	static inline uint64_t getYYYYMMDDhhmmss()
	{
		timeb now;		// 时间结构体
		ftime(&now);	// 取得当前日期和时间
		// 获取本地时间结构体
		tm * tNow = localtime(&(now.time));
		// 数值型日期(yyyymmdd) 20220208
		uint64_t date = (tNow->tm_year + 1900) * 10000 + (tNow->tm_mon + 1) * 100 + tNow->tm_mday;
		// 数值型时间(HHMMSS) 225900
		uint64_t time = tNow->tm_hour * 10000 + tNow->tm_min * 100 + tNow->tm_sec;
		return date * 1000000 + time;
	}
	// 获取当前数值型日期(yyyymmdd)和数值型时间(精确到毫秒: HHMMSS000)
	static inline void getDateTime(uint32_t &date, uint32_t &time)
	{
		timeb now;
		ftime(&now);

		tm * tNow = localtime(&(now.time));

		date = (tNow->tm_year+1900)*10000 + (tNow->tm_mon+1)*100 + tNow->tm_mday;
		
		time = tNow->tm_hour*10000 + tNow->tm_min*100 + tNow->tm_sec;
		time *= 1000;
		time += now.millitm;
	}

	// 获取当前数值型日期, 精确到日
	static inline uint32_t getCurDate()
	{
		timeb now;
		ftime(&now);

		tm * tNow = localtime(&(now.time));

		uint32_t date = (tNow->tm_year+1900)*10000 + (tNow->tm_mon+1)*100 + tNow->tm_mday;

		return date;
	}

	// 获取周几(0-6)
	static inline uint32_t getWeekDay(uint32_t uDate = 0)
	{
		time_t ts = 0;
		if(uDate == 0)
		{
			timeb now;
			ftime(&now);
			ts = now.time;
		}
		else
		{
			tm t;	
			memset(&t,0,sizeof(tm));
			t.tm_year = uDate/10000 - 1900;
			t.tm_mon = (uDate%10000)/100 - 1;
			t.tm_mday = uDate % 100;
			ts = mktime(&t);
		}

		tm * tNow = localtime(&ts);
	
		return tNow->tm_wday;
	}

	// 获取当前数值型时间, 精确到秒
	static inline uint32_t getCurMin()
	{
		timeb now;
		ftime(&now);

		tm * tNow = localtime(&(now.time));

		uint32_t time = tNow->tm_hour*10000 + tNow->tm_min*100 + tNow->tm_sec;

		return time;
	}

	// 获取时间字符串
	static inline std::string getYYYYMMDD_hhmmss(void)
	{
		std::string datetime_fmt_str = "";
		tm local;
		time_t now;
		time(&now);
#ifdef _WIN32
		localtime_s(&local, &now);
#else
		localtime_r(&now, &local);
#endif
		char year[5] = {'\0'};
		sprintf(year, "%d", local.tm_year + 1900);
		char month[3]  = {'\0'};
		sprintf(month, "%02d",local.tm_mon+1);
		char day[3]  = {'\0'};
		sprintf(day, "%02d",local.tm_mday);
		char hh[3]  = {'\0'};
		sprintf(hh, "%02d", local.tm_hour);
		char mm[3]  = {'\0'};
		sprintf(mm, "%02d", local.tm_min);
		char ss[3]  = {'\0'};
		sprintf(ss, "%02d", local.tm_sec);
		std::string ofilename;
		datetime_fmt_str.append(year);
		datetime_fmt_str.append(month);
		datetime_fmt_str.append(day);
		datetime_fmt_str.append("_");
		datetime_fmt_str.append(hh);
		datetime_fmt_str.append(mm);
		datetime_fmt_str.append(ss);
		return datetime_fmt_str;
	}

	//20120512 09:15:00 -> 毫秒
	//支持如下格式的字符串: 
	// 20120512 09:15:00 or 20120512 09:15:00 999
	// 20120512091500 or 20120512091500999
	static inline int64_t makeTime(std::string time_str)
	{
	    //time_str = StringUtils::trim(time_str, ' ');
		//time_str = StringUtils::trim(time_str, ':');
		uint32_t len = (uint32_t)time_str.size();
		if (len < 14) return 0;
		tm t;	
		memset(&t,0,sizeof(tm));
		t.tm_year = atoi(time_str.substr(0, 4).c_str()) - 1900;
		t.tm_mon = atoi(time_str.substr(4,2).c_str()) - 1;
		t.tm_mday = atoi(time_str.substr(6,2).c_str());
		t.tm_hour = atoi(time_str.substr(8,2).c_str());
		t.tm_min = atoi(time_str.substr(10,2).c_str());
		t.tm_sec = atoi(time_str.substr(12,2).c_str());
		int millisec = 0;
		if ( len == 17){ //说明还有毫秒
			millisec = atoi(time_str.substr(14,3).c_str());
		}
		//t.tm_isdst 	
		time_t ts = mktime(&t);
		if (ts == -1) return 0;
		return ts * 1000+ millisec;
	}

	static inline int32_t getTZOffset()
	{
		static int32_t offset = 99;
		if(offset == 99)
		{
			time_t now = time(NULL);
			tm tm_ltm = *localtime(&now);
			tm tm_gtm = *gmtime(&now);

			time_t _gt = mktime(&tm_gtm);
			tm _gtm2 = *localtime(&_gt);

			offset = (uint32_t)(((now - _gt) + (_gtm2.tm_isdst ? 3600 : 0)) / 60);
			offset /= 60;
		}

		return offset;
	}

	// 将数值型 lDate 和 lTime 转为数值型时间, 精确到毫秒
	static inline int64_t makeTime(long lDate, long lTimeWithMs, bool isGM = false)
	{
		tm t;	
		memset(&t,0,sizeof(tm));
		t.tm_year = lDate/10000 - 1900;
		t.tm_mon = (lDate%10000)/100 - 1;
		t.tm_mday = lDate % 100;
		t.tm_hour = lTimeWithMs/10000000;
		t.tm_min = (lTimeWithMs%10000000)/100000;
		t.tm_sec = (lTimeWithMs%100000)/1000;
		int millisec = lTimeWithMs%1000;
		//t.tm_isdst 	
		time_t ts = mktime(&t);
		if (isGM)
			ts -= getTZOffset() * 3600;
		if (ts == -1) return 0;
		return ts * 1000+ millisec;
	}

	// 将数值型时间(自动判断毫秒)转为字符串
	static std::string timeToString(int64_t mytime)
	{
		if (mytime == 0) return "";
		int64_t sec = mytime/1000;
		int msec = (int) (mytime - sec * 1000);
		if (msec < 0) return "";
		time_t tt =  sec;
		struct tm t;
#ifdef _WIN32
		localtime_s(&t, &tt);
#else
		localtime_r(&tt, &t);
#endif
		char tm_buf[64] = {'\0'};
		if (msec > 0) //是否有毫秒
		   sprintf(tm_buf,"%4d%02d%02d%02d%02d%02d.%03d",t.tm_year+1900, t.tm_mon+1, t.tm_mday,
			t.tm_hour, t.tm_min, t.tm_sec, msec);
		else 
		   sprintf(tm_buf,"%4d%02d%02d%02d%02d%02d",t.tm_year+1900, t.tm_mon+1, t.tm_mday,
			t.tm_hour, t.tm_min, t.tm_sec);
		return tm_buf;
	};

	// 数值型日期(精确到日)计算, 返回数值型日期
	static uint32_t getNextDate(uint32_t curDate, int days = 1)
	{
		tm t;	
		memset(&t,0,sizeof(tm));
		t.tm_year = curDate/10000 - 1900;
		t.tm_mon = (curDate%10000)/100 - 1;
		t.tm_mday = curDate % 100;
		//t.tm_isdst 	
		time_t ts = mktime(&t);
		ts += days*86400;

		tm* newT = localtime(&ts);
		return (newT->tm_year+1900)*10000 + (newT->tm_mon+1)*100 + newT->tm_mday;
	}

	// 数值型分钟(HHMM)计算
	static uint32_t getNextMinute(int32_t curTime, int32_t mins = 1)
	{
		int32_t curHour = curTime / 100;
		int32_t curMin = curTime % 100;
		int32_t totalMins = curHour * 60 + curMin;
		totalMins += mins;

		if (totalMins >= 1440)
			totalMins -= 1440;
		else if (totalMins < 0)
			totalMins += 1440;

		int32_t ret = (totalMins / 60) * 100 + totalMins % 60;
		return (uint32_t)ret;
	}

	// 数值型年月(yyyymm)计算
	static uint32_t getNextMonth(uint32_t curMonth, int months = 1)
	{
		uint32_t uYear = curMonth/100;
		uint32_t uMonth = curMonth%100;

		uint32_t uAddYear = months/12;
		uint32_t uAddMon = months%12;

		uYear += uAddYear;
		uMonth += uAddMon;
		if(uMonth > 12)
		{
			uYear ++;
			uMonth -= 12;
		}
		else if(uMonth <= 0)
		{
			uYear --;
			uMonth = 12;
		}

		return uYear*100 + uMonth;
	}

	static inline uint64_t timeToMinBar(uint32_t uDate, uint32_t uTime)
	{
		return (uint64_t)((uDate-19900000)*10000) + uTime;
	}

	static inline uint32_t minBarToDate(uint64_t minTime)
	{
		return (uint32_t)(minTime/10000 + 19900000);
	}

	static inline uint32_t minBarToTime(uint64_t minTime)
	{
		return (uint32_t)(minTime%10000);
	}

	// 判断是否是周末
	static inline bool isWeekends(uint32_t uDate)
	{
		tm t;	
		memset(&t,0,sizeof(tm));
		t.tm_year = uDate/1/10000 - 1900;
		t.tm_mon = (uDate/1%10000)/100 - 1;
		t.tm_mday = uDate/1 % 100;

		time_t tt = mktime(&t);
		tm* tmt = localtime(&tt);
		if(tmt == NULL)
			return true;
	
		if(tmt->tm_wday == 0 || tmt->tm_wday==6)
			return true;

		return false;
	}

public:
	class Time32
	{
	public:
		Time32():_msec(0){}

		Time32(time_t _time, uint32_t msecs = 0)
		{
#ifdef _WIN32
			localtime_s(&t, &_time);
#else
			localtime_r(&_time, &t);
#endif
			_msec = msecs;
		}

		Time32(uint64_t _time)
		{
			time_t _t = _time/1000;
			_msec = (uint32_t)_time%1000;
#ifdef _WIN32
			localtime_s(&t, &_t);
#else
			localtime_r(&_t, &t);
#endif
		}

		void from_local_time(uint64_t _time)
		{
			time_t _t = _time/1000;
			_msec = (uint32_t)_time%1000;
#ifdef _WIN32
			localtime_s(&t, &_t);
#else
			localtime_r(&_t, &t);
#endif
		}

		uint32_t date()
		{
			return (t.tm_year + 1900)*10000 + (t.tm_mon + 1)*100 + t.tm_mday;
		}

		uint32_t time()
		{
			return t.tm_hour*10000 + t.tm_min*100 + t.tm_sec;
		}

		uint32_t time_ms()
		{
			return t.tm_hour*10000000 + t.tm_min*100000 + t.tm_sec*1000 + _msec;
		}

		const char* fmt(const char* sfmt = "%Y.%m.%d %H:%M:%S", bool hasMilliSec = false) const
		{
			static char buff[1024];
			uint32_t length = (uint32_t)strftime(buff, 1023, sfmt, &t);
			if (hasMilliSec)
				sprintf(buff + length, ",%03u", _msec);
			return buff;
		}

	protected:
		struct tm t;
		uint32_t _msec;
	};

	class Ticker
	{
	public:
		Ticker()
		{
			_tick = std::chrono::high_resolution_clock::now();
		}

		void reset()
		{
			_tick = std::chrono::high_resolution_clock::now();
		}

		inline int64_t seconds() const 
		{
			auto now = std::chrono::high_resolution_clock::now();
			auto td = now - _tick;
			return std::chrono::duration_cast<std::chrono::seconds>(td).count();
		}

		inline int64_t milli_seconds() const
		{
			auto now = std::chrono::high_resolution_clock::now();
			auto td = now - _tick;
			return std::chrono::duration_cast<std::chrono::milliseconds>(td).count();
		}

		inline int64_t micro_seconds() const
		{
			auto now = std::chrono::high_resolution_clock::now();
			auto td = now - _tick;
			return std::chrono::duration_cast<std::chrono::microseconds>(td).count();
		}

		inline int64_t nano_seconds() const
		{
			auto now = std::chrono::high_resolution_clock::now();
			auto td = now - _tick;
			return std::chrono::duration_cast<std::chrono::nanoseconds>(td).count();
		}

	private:
		std::chrono::time_point<std::chrono::high_resolution_clock> _tick;
	};
};