工具类库系列(六)-TimeTool

第六个工具类,TimeTool


用于秒精度的时间获取:距离一个参考时间所经历的秒数,用于时间戳

以及计算两个时间戳,按照特定时间分割点分割后的差值


比如:一般游戏项目中通常都会有这样的需求:

某个任务,1周之内只能接取5次,周6早上6点算下一周开始,次数清零,

某个活动,每月5号开启下一轮

等等


所以通常就会存在需要计算玩家的本次操作(比如申请接任务),距离 上一次操作(上一次的接任务),以一个特定时间点为分界(周6早上6点),是否是同一小时/天/周/月,经过了几小时/天/周/月


首先,一般用time(NULL),取当前时间距离1970/1/1 00:00:00 所经历的总秒数, 作为时间戳


但是需要注意的是这个time(NULL)都是UTC时间


如果,需求是比如周6早上6点算下一周,这个显然说的是我们东八区的时间,相对于time(NULL)还存在一个时区转换的问题


怎么算:

假设玩家 2016/12/30(周5) 20:00:00接的任务,服务端这边记录了一个时间戳 t1

玩家 2016/12/31(周6)07:00:00再次接任务,服务端这边记录了一个时间戳 t2

t1和t2都是time(NULL)得到的UTC时间

而1970/1/1是周四,1970/1/5是周一

为了计算周数,将t1,和t2,减去4天,得到一个秒数,这个秒数即为距离UTC时间1970/1/5 00:00:00 所经历的总秒数

需求要求是周六,

再将t1,和t2,减去(6-1)天,得到一个秒数,这个秒数即为距离UTC时间1970/1/10 00:00:00 所经历的总秒数

而东八区的早上6点,即UTC时间的前一天晚上22点

再将t1,和t2,加上2小时,得到一个秒数这个秒数即为距离UTC时间的1970/1/9 22:00:00(东八区时间1970/1/10 06:00:00 周六)所经历的总秒数

以这个时间做为第一周的开始

将t1,和t2,分别除以7天,则得到距离UTC时间的1970/1/9 22:00:00所经历的总周数

如果这两个周数相等,则这两个时间,以东八区的周6早上6点为界,属于同一周


是否属于同一天类似,但是就不用偏移到周一了,就用1月1号作为参考时间,转换一下时区,然后除以24小时就好了


是否属于同一小时,也类似,而且这个不存在时区问题,更简单,直接算


是否属于同一个月,这个不能用上面的方法来算了,因为每个月的天数是不一样的

只能将时间戳,用localtime(),转换成本地时间的年月日时分秒

比如每个月的5号早上6点,

则将时间戳,减去5天6小时,以每个月的5号早上6点做为一个月的开始

减完之后,转成本地时间,得到年月,

然后年数×12+月数,算出来的就是距离东八区的1970/1/5 06:00:00 的总月数

月数相等则为同一周

但是这个依然存在一个问题,就是分割用的时间,不能大于28号,因为2月只有28天

如果用比如30号做为分割的话,3月的1号,2号就会被算到2月去


示例代码:

以2分2秒为界

以2时2分2秒为界

以周2,2时2分2秒为界

以2号,2时2分2秒为界

分别判断是否属于同一个小时/天/周/月

int main(int argc, char* argv[])
{
#define SetTm(number, year, mon, day, hour, min, sec) \
	tm##number.tm_year = year - 1900; \
	tm##number.tm_mon = mon - 1; \
	tm##number.tm_mday = day; \
	tm##number.tm_hour = hour; \
	tm##number.tm_min = min; \
	tm##number.tm_sec = sec; \
	t##number = mktime(&tm##number);

#define PrintTM \
	std::cout << \
	(tm1.tm_year + 1900) << "/" << (tm1.tm_mon + 1) << "/" << tm1.tm_mday << " " << tm1.tm_hour << ":" << tm1.tm_min << ":" << tm1.tm_sec << \
	" -> " << \
	(tm2.tm_year + 1900) << "/" << (tm2.tm_mon + 1) << "/" << tm2.tm_mday << " " << tm2.tm_hour << ":" << tm2.tm_min << ":" << tm2.tm_sec << \
	std::endl;

#define PrintHour \
	PrintTM \
	std::cout << \
	"IsDifferentHour " << TimeTool::IsDifferentHour(t1, t2, 2, 2) << \
	", " << \
	"GetDeltaHour " << TimeTool::GetDeltaHour(t1, t2, 2, 2) << \
	std::endl;

#define PrintDay \
	PrintTM \
	std::cout << \
	"IsDifferentDay " << TimeTool::IsDifferentDay(t1, t2, 2, 2, 2) << \
	", " << \
	"GetDeltaDay " << TimeTool::GetDeltaDay(t1, t2, 2, 2, 2) << \
	std::endl;

#define PrintWeek \
	PrintTM \
	std::cout << \
	"IsDifferentWeek " << TimeTool::IsDifferentWeek(t1, t2, 2, 2, 2, 2) << \
	", "<< \
	"GetDeltaWeek " << TimeTool::GetDeltaWeek(t1, t2, 2, 2, 2, 2) << \
	std::endl;

#define PrintMonth \
	PrintTM \
	std::cout << \
	"IsDifferentMonth " << TimeTool::IsDifferentMonth(t1, t2, 2, 2, 2, 2) << \
	", " << \
	"GetDeltaMonth " << TimeTool::GetDeltaMonth(t1, t2, 2, 2, 2, 2) << \
	std::endl;

	tm tm1;
	tm tm2;

	time_t t1;
	time_t t2;

	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 0, 0, 0);
	PrintHour;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 0, 2, 1);
	PrintHour;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 0, 2, 2);
	PrintHour;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 1, 2, 2);
	PrintHour;

	std::cout << std::endl;

	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 0, 0, 0);
	PrintDay;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 2, 2, 1);
	PrintDay;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 2, 2, 2);
	PrintDay;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 3, 2, 2, 2);
	PrintDay;

	std::cout << std::endl;

	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 3, 0, 0, 0);
	PrintWeek;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 3, 2, 2, 1);
	PrintWeek;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 3, 2, 2, 2);
	PrintWeek;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 10, 2, 2, 2);
	PrintWeek;

	std::cout << std::endl;

	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 0, 0, 0);
	PrintMonth;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 2, 2, 1);
	PrintMonth;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 1, 2, 2, 2, 2);
	PrintMonth;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 2, 1, 2, 2, 2);
	PrintMonth;
	SetTm(1, 2017, 1, 1, 23, 59, 59);
	SetTm(2, 2017, 2, 2, 2, 2, 2);
	PrintMonth;

	return 0;
}

结果截图




最后完整代码:

TimeTool.h

#ifndef __TimeTool_h__
#define __TimeTool_h__

#include <time.h>

namespace common{
	namespace tool{

		class TimeTool
		{
		public:
			// 返回距离UTC时间1970/1/1 00:00:00的总秒数
			static time_t GetCurrSecond();


			// 返回本地日历日期,用于取年月日时分秒
			// t为GetCurrSecond获取到的UTC时间
			static tm GetDateTime(time_t t);
			// 返回当前本地日历日期,用于取年月日时分秒
			static tm GetCurrDateTime();


			// M分S秒为界(M分S秒之前算前一小时),返回两个秒数之间,相差几小时
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static unsigned int GetDeltaHour(time_t t1, time_t t2, unsigned int m, unsigned int s);

			// 以东八区时间每天H时M分S秒为界(H时M分S秒之前算前一天),返回两个秒数之间,相差几天
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static unsigned int GetDeltaDay(time_t t1, time_t t2, unsigned int h, unsigned int m, unsigned int s);

			// 以东八区时间每周星期W,H时M分S秒为界(星期W,H时M分S秒之前算上一周),返回两个秒数之间,相差几周
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// w:		1 ~ 7,东八区时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static unsigned int GetDeltaWeek(time_t t1, time_t t2, unsigned int w, unsigned int h, unsigned int m, unsigned int s);

			// 以东八区时间每月D号,H时M分S秒为界(D号,H时M分S秒之前算上一个月),返回两个秒数之间,相差几个月
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// d:		1 ~ 28,东八区时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static unsigned int GetDeltaMonth(time_t t1, time_t t2, unsigned int d, unsigned int h, unsigned int m, unsigned int s);


			// M分S秒为界(M分S秒之前算前一小时),判断两个秒数是否是同一小时
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static bool IsDifferentHour(time_t t1, time_t t2, unsigned int m, unsigned int s);

			// 以东八区时间每天H时M分S秒为界(H时M分S秒之前算前一天),判断两个秒数是否是同一天
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static bool IsDifferentDay(time_t t1, time_t t2, unsigned int h, unsigned int m, unsigned int s);

			// 以东八区时间每周星期W,H时M分S秒为界(星期W,H时M分S秒之前算上一周),判断两个秒数是否是同一周
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// w:		1 ~ 7,东八区时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static bool IsDifferentWeek(time_t t1, time_t t2, unsigned int w, unsigned int h, unsigned int m, unsigned int s);

			// 以东八区时间每月D号,H时M分S秒为界(D号,H时M分S秒之前算上一个月),判断两个秒数是否是同一月
			// t1,t2:	GetCurrSecond获取到的UTC时间
			// d:		1 ~ 28,东八区时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static bool IsDifferentMonth(time_t t1, time_t t2, unsigned int d, unsigned int h, unsigned int m, unsigned int s);


			// 将		距离UTC时间1970/1/1 00:00:00的总秒数
			// 换算成	距离UTC+8时间1970/1/1 h:m:s的总秒数
			// t:		GetCurrSecond获取到的UTC时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static time_t GetHMS_Utc8(time_t t, unsigned int h, unsigned int m, unsigned int s);

			// 将		距离UTC时间1970/1/1 00:00:00的总秒数
			// 换算成	距离UTC+8时间1970/1/(5+w-1) h:m:s的总秒数,1970/1/5为周一
			// t:		GetCurrSecond获取到的UTC时间
			// w:		1 ~ 7,东八区时间
			// h:		0 ~ 23,东八区时间
			// m:		0 ~ 59
			// s:		0 ~ 59
			static time_t GetWHMS_Utc8(time_t t, unsigned int w, unsigned int h, unsigned int m, unsigned int s);
		};

	}
}

#endif

TimeTool.cpp

#include "TimeTool.h"

namespace common{
	namespace tool{

		time_t TimeTool::GetCurrSecond()
		{
			return time(NULL);
		}

		tm TimeTool::GetDateTime(time_t t)
		{
			tm tm = *localtime(&t);
			tm.tm_year += 1900;	/* years since 1900 */
			tm.tm_mon += 1;		/* months since January - [0,11] */
			return tm;
		}

		tm TimeTool::GetCurrDateTime()
		{
			time_t t = GetCurrSecond();
			return GetDateTime(t);
		}

		unsigned int TimeTool::GetDeltaHour(time_t t1, time_t t2, unsigned int m, unsigned int s)
		{
			if (t1 != t2)
			{
				// 参数校验
				if (m > 59 || s > 59)
				{
					m = 0;
					s = 0;
				}

				// 更换参考时间
				t1 = t1 - (m * 60 + s);
				t2 = t2 - (m * 60 + s);

				// 换算成小时
				t1 = t1 / (60 * 60);
				t2 = t2 / (60 * 60);

				// 计算小时数的差值
				if (t1 > t2)
				{
					return static_cast<unsigned int>(t1 - t2);
				}
				else if (t1 < t2)
				{
					return static_cast<unsigned int>(t2 - t1);
				}
				else
				{
					return 0;
				}
			}
			else
			{
				return 0;
			}
		}

		unsigned int TimeTool::GetDeltaDay(time_t t1, time_t t2, unsigned int h, unsigned int m, unsigned int s)
		{
			if (t1 != t2)
			{
				// 参数校验
				if (h > 23 || m > 59 || s > 59)
				{
					h = 0;
					m = 0;
					s = 0;
				}

				// 更换参考时间
				t1 = GetHMS_Utc8(t1, h, m, s);
				t2 = GetHMS_Utc8(t2, h, m, s);

				// 换算成天数
				t1 = t1 / (24 * 60 * 60);
				t2 = t2 / (24 * 60 * 60);

				// 计算天数的差值
				if (t1 > t2)
				{
					return static_cast<unsigned int>(t1 - t2);
				}
				else if (t1 < t2)
				{
					return static_cast<unsigned int>(t2 - t1);
				}
				else
				{
					return 0;
				}
			}
			else
			{
				return 0;
			}
		}

		unsigned int TimeTool::GetDeltaWeek(time_t t1, time_t t2, unsigned int w, unsigned int h, unsigned int m, unsigned int s)
		{
			if (t1 != t2)
			{
				// 参数校验
				if (w < 1 || w > 7 || h > 23 || m > 59 || s > 59)
				{
					w = 1;
					h = 0;
					m = 0;
					s = 0;
				}

				// 更换参考时间
				t1 = GetWHMS_Utc8(t1, w, h, m, s);
				t2 = GetWHMS_Utc8(t2, w, h, m, s);

				// 换算成周数
				t1 = t1 / (7 * 24 * 60 * 60);
				t2 = t2 / (7 * 24 * 60 * 60);

				// 计算周数的差值
				if (t1 > t2)
				{
					return static_cast<unsigned int>(t1 - t2);
				}
				else if (t1 < t2)
				{
					return static_cast<unsigned int>(t2 - t1);
				}
				else
				{
					return 0;
				}
			}
			else
			{
				return 0;
			}
		}

		unsigned int TimeTool::GetDeltaMonth(time_t t1, time_t t2, unsigned int d, unsigned int h, unsigned int m, unsigned int s)
		{
			if (t1 != t2)
			{
				// 参数校验
				if (d < 1 || d > 28 || h > 23 || m > 59 || s > 59)
				{
					d = 1;
					h = 0;
					m = 0;
					s = 0;
				}

				// 更换参考时间,以d号h时m分s秒为参考时间
				// 不考虑时区,后面就是以本地时间计算
				t1 = t1 - ((d - 1) * 24 * 60 * 60 + h * 60 * 60 + m * 60 + s);
				t2 = t2 - ((d - 1) * 24 * 60 * 60 + h * 60 * 60 + m * 60 + s);

				// 转化为本地时间
				tm tm1 = *localtime(&t1);
				tm tm2 = *localtime(&t2);

				// 换算成月数
				t1 = tm1.tm_year * 12 + tm1.tm_mon;
				t2 = tm2.tm_year * 12 + tm2.tm_mon;

				if (t1 > t2)
				{
					return static_cast<unsigned int>(t1 - t2);
				}
				else if (t1 < t2)
				{
					return static_cast<unsigned int>(t2 - t1);
				}
				else
				{
					return 0;
				}
			}
			else
			{
				return 0;
			}
		}

		bool TimeTool::IsDifferentHour(time_t t1, time_t t2, unsigned int m, unsigned int s)
		{
			return 0 != GetDeltaHour(t1, t2, m, s);
		}

		bool TimeTool::IsDifferentDay(time_t t1, time_t t2, unsigned int h, unsigned int m, unsigned int s)
		{
			return 0 != GetDeltaDay(t1, t2, h, m, s);
		}

		bool TimeTool::IsDifferentWeek(time_t t1, time_t t2, unsigned int w, unsigned int h, unsigned int m, unsigned int s)
		{
			return 0 != GetDeltaWeek(t1, t2, w, h, m, s);
		}

		bool TimeTool::IsDifferentMonth(time_t t1, time_t t2, unsigned int d, unsigned int h, unsigned int m, unsigned int s)
		{
			return 0 != GetDeltaMonth(t1, t2, d, h, m, s);
		}

		time_t TimeTool::GetHMS_Utc8(time_t t, unsigned int h, unsigned int m, unsigned int s)
		{
			// 如:东八区时间的:9时30分30秒,则为UTC时间的:1时30分30秒(参考时间往后偏移,总秒数减少)
			// 如:东八区时间的:7时30分30秒,则为UTC时间的前一天:23时30分30秒(参考时间往前偏移,总秒数增加)
			unsigned int deltaT = h * 60 * 60 + m * 60 + s;
			unsigned int delta8 = 8 * 60 * 60;
			if (delta8 <= deltaT)
			{
				t = t - (deltaT - delta8);
			}
			else
			{
				t = t + (delta8 - deltaT);
			}

			return t;
		}

		time_t TimeTool::GetWHMS_Utc8(time_t t, unsigned int w, unsigned int h, unsigned int m, unsigned int s)
		{
			t = GetHMS_Utc8(t, h, m, s);

			// 1970/1/1 为周4
			// 1970/1/5 为周1
			// 换算成距离1970/1/5 h:m:s的总秒数,即减4天
			t = t - 4 * 24 * 60 * 60;

			// 换算成距离星期W,即距离1970/1/(5+w-1) h:m:s的总秒数,即减(w-1)天
			t = t - (w - 1) * 24 * 60 * 60;

			return t;
		}
	}
}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值