不含 MFC 的替代时间戳类
本文描述了一个时间戳类,它可以作为标准 C 日期时间函数的替代方案。
引言
这是一个时间戳类,可以存储从公元0年到公元9999年及以后的日期和时间。它以百分之一秒的精度存储时间戳。它可以根据各种不同的格式进行构造,可以输出单个组件以及各种格式的字符串,并且包含比较运算符以及一些基本的日期算术(加一天、加一月等)。此类能够识别闰年,但不能识别闰秒。
背景
我目前的主要项目涉及后端/前端架构,其中一项要求是后端可以在 Windows MFC 以外的系统上进行编译。当开始这个项目时,我四处寻找一个非 MFC 的日期时间类,结果我使用了 time_t
(http://en.wikipedia.org/wiki/Time_t)。不幸的是,我现在在处理早于1970年出生的人的日期时遇到了很多问题,经过一些研究,我发现 time_t
只能从1970年到2038年工作。这对于我的应用程序来说不够好。
我的后端应用程序使用 SQLite 存储数据,日期和时间存储在时间戳字段中。我一直找不到一个 C++ 类来存储时间戳数据,最后我不得不自己写了一个,在这里呈现给大家。
使用代码
这是一个简单的类,包含一个头文件和一个 CPP 文件。你应该将它们作为你的应用程序的一部分进行编译。
我将在本文后面为每个单独的函数提供完整的文档。这是一个快速演示如何在你的项目中使用的类。
下载包含许多文件,其中最重要的是
- RJMFTime.cpp
- RJMFTime.h
你应该将 *RJMFTimp.cpp* 和 *RJMFTime.h* 添加到你的项目中。完整的下载是一个 Visual Studio 6.0 项目,其中包含编译 TimeTest 所需的所有文件。TimeTest 是一个旨在完全测试该类的程序。将 *RJMFTime.cpp* 和 *RJMFTime.h* 添加到项目后,你需要在每个使用该类的文件中包含 *RJMFTime.h*。然后,你可以按照以下代码片段所示使用该类。
明天的日期是什么?
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO;
TSO.AddDay(1);
printf("%s\n",TSO.c_str());
return 0;
};
此示例显示了默认构造函数,它将类初始化为当前的日期和时间。然后使用 AddDay
函数增加一天。你也可以使用负数参数来减去天数。你还可以找到该函数的年份、月份、小时、分钟、秒和百分之一秒版本。最后,它使用 c_str
函数将结果输出为字符串。c_str
函数是 strftime
的替代方案,等同于 strftime(buf, "%d-%b-%Y %H:%M:%!")
。这主要是为那些还没有学会如何使用格式字符串的懒惰程序员准备的。
这个日期有效吗?
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
#define SAFE_DELETE(a) if (a!=NULL) {delete a; a=NULL;};
int main() {
char *sDates[] = {"29-FEB-1104",
"29-FEB-1999",
"29-FEB-2000",
"29-FEB-2002",
"29-FEB-2004",
"29-FEB-2100",
"29-FEB-2101" };
RJMF_TimeStamp* pTS1 = NULL;
for (int c=0;c<7;c++) {
pTS1 = new RJMF_TimeStamp(sDates[c],"DD-MON-YYYY");
if (pTS1->valid()) {
printf("%s is valid (%s)\n",sDates[c],pTS1->c_str());
} else {
printf("%s is NOT valid\n",sDates[c],pTS1->c_str());
};
SAFE_DELETE(pTS1);
};
return 0;
};
此示例使用七个日期,并检查它们是否是有效日期。(它也碰巧测试了类是否遵循闰年规则。)它循环七次,从字符串创建一个 RJMF_Timestamp
对象。然后使用 valid
函数确定日期是否有效。你可以使用类似的方法来测试用户输入的日期是否有效。
距离圣诞节还有多少天?
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dToday;
RJMF_TimeStamp dChristmass(0,0,0,0,31,12,dToday.GetYear());
char buf[100];
dToday.strftime(buf, "%A %d-%b-%Y %H:%M:%!");
printf("Today is %s\n",buf);
unsigned int d = dChristmass.DiffDay(&dToday);
printf("There are %u days until christmass\n",d);
return 0;
};
此示例创建一个指向今天的对象,然后使用 GetYear
函数查找年份。还有类似的 GetMonth
、GetDay
等函数。然后它展示了另一种创建类的方法,通过指定精确日期来初始化类。在这种情况下,是当前年份的12月31日。(该函数还接受时间,在本例中是0小时、0分钟、0秒和0百分之一秒。)它没有使用 c_str
函数,而是创建了一个缓冲区并使用了 strftime
函数。这给了我们更多对输出的控制,并允许我们包含星期几。最后,使用 DiffDay
函数计算两个日期之间的天数。你还会发现在类中包含了 DiffYear
、DiffMonth
等函数。
列出 Joe Blogg 生日和我生日之间的日期
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dBlogs("05-NOV-1979 15:31:11.25",
"DD-MON-YYYY hh:mm:ss.ss");
RJMF_TimeStamp dBase;
dBase = dBlogs;
dBase.AddDay(1);
while (dBase<dMe) {
printf("%s\n",dBase.c_str());
dBase.AddDay(1);
};
return 0;
};
此示例首先展示了创建对象的第三种方法。这种方法使用特定格式的字符串。这对于从 SQLite 等地方获取日期很有用。预先编码了特定数量的格式字符串。有关确切文档,请参阅本文后面。然后它使用赋值运算符(=)和小于运算符(<)。该类包含了范围或其他运算符(<= >= > == 等)。除了展示我们之前看到的 c_str
和 AddDay
函数之外,此示例还展示了一种方便的日期循环方式。
等等,一分钟(或者如果你愿意,10秒)
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
#define SAFE_DELETE(a) if (a!=NULL) {delete a; a=NULL;};
int main() {
printf("About to wait for 10 secs\n");
RJMF_TimeStamp* pCT = NULL;
RJMF_TimeStamp* pET = new RJMF_TimeStamp();
pET->AddSecond(10);
pCT = new RJMF_TimeStamp();
while ((*pCT)<(*pET)) {
SAFE_DELETE(pCT);
pCT = new RJMF_TimeStamp();
};
SAFE_DELETE(pCT);
SAFE_DELETE(pET);
printf("10 seconds is up");
};
这个最后的示例展示了如何使用该类使你的程序暂停10秒。可能有许多更好的方法来做到这一点,我不推荐使用此方法。这表明该类同时包含日期和时间。它通过创建一个具有当前日期和时间的对象,然后增加10秒来工作。然后,它不断地创建和销毁具有当前日期和时间的对象,并使用比较运算符来确定等待的时间是否已经过去。这种方法即使跨越年份边界也应该能正常工作。有一个注意事项是,无参数的构造函数仍然依赖于 <codec_time>
数据类型。这意味着这只能在1970年至2038年之间工作。有关更多解释,请参阅本文后面。
基本设计
大多数日期/时间类会将日期转换为自预定义开始时间以来的秒数。这就是为什么 time_t
结构无法在1970年之前工作的原因。开始时间是1970年。这样做的原因是它使日期计算更简单。我没有采用这种设计,而是开发了一个类,它存储年份,然后存储自年初以来的百分之一秒数。这使得所有计算都更加复杂,但这意味着它适用于更广泛的日期范围。
该类有三个私有成员变量
unsigned int m_year;
unsigned int m_hdth_secs; //hdthseconds since start of year
bool m_valid;
年份以 unsigned int
类型存储。
m_valid
简单地存储一个布尔值,如果类已正确构造,则为 true
,否则为 false
。这对于检查是否设置了有效日期很有用。
m_year
存储当前年份。这是无符号的,但该类也可能适用于有符号值。(我没有存储公元0年之前的日期需求。)
这种方法有一个有趣的副作用,即日期10-Jan-2000 和 10-Jan-2001 的 m_hdth_secs
值相同。然而,10-Dec-2000 和 10-Dec-2001 的 m_hdth_secs
值不同。这是因为2000年是闰年,10-Dec-2000 的 m_hdth_secs
值包含额外的一天(24 * 60 * 60 * 100 = 8,640,000 百分之一秒)。
单个函数描述
本节将描述每个单独的函数。还提供了每个函数用法的示例。
RJMF_TimeStamp();
当使用无参数构造函数调用时,将使用标准 C localtime
函数用当前日期和时间初始化对象。这意味着这只能在1970-2038年工作,如 http://en.wikipedia.org/wiki/Time_t 中所述。这应该始终生成一个有效日期。这只填充到最近的秒。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO;
printf("%s\n",TSO.c_str());
return 0;
};
RJMF_TimeStamp(unsigned int hdth, unsigned int sec, unsigned int minutes, unsigned int hours, unsigned int mday, unsigned int month, unsigned int year);
当你想初始化对象到特定日期时,使用此构造函数。以下值应作为参数传递
字段 | 允许值 | 注释 |
---|---|---|
hdth |
0-99 | |
sec |
0-59 | |
minutes |
0-59 | |
hours |
0-23 | 24小时制 |
mday |
1-31 | 月份中的天数 |
month |
1-12 | |
year |
0-9999 | 更高的年份可能仍然有效 |
调用此函数后,你应该使用 valid
函数来检查输入的日期是否有效。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO(55, 31, 31, 20, 30, 11, 2007);
if (TSO.valid()) {
printf("%s\n",TSO.c_str());
} else {
printf("This date is not valid\n");
};
return 0;
};
RJMF_TimeStamp(char *pTime, char*pFormat = NULL);
此构造函数根据字符串初始化对象。它只能使用以下硬编码格式字符串
格式字符串 | 示例 |
---|---|
"DD-MON-YYYY | 30-NOV-2007 |
"DD-MON-YY" | 30-NOV-07 |
"DD/MM/YYYY" | 30/11/2007 |
"DD/MM/YY" | 30/11/07 |
"DD-MON-YYYY hh:mm:ss.ss" | 30-NOV-2007 20:31:31.55 |
"DD-MON-YY hh:mm:ss.ss" | 30-NOV-07 20:31:31.55 |
"DD/MM/YYYY hh:mm:ss.ss" | 30/11/2007 20:31:31.55 |
"DD/MM/YY hh:mm:ss.ss" | 30/11/07 20:31:31.55 |
"DD-MON-YYYY hh:mm:ss" | 30-NOV-2007 20:31:31 |
"DD-MON-YY hh:mm:ss" | 30-NOV-07 20:31:31 |
"DD/MM/YYYY hh:mm:ss" | 30/11/2007 20:31:31 |
"DD/MM/YY hh:mm:ss" | 30/11/07 20:31:31 |
"YYYY-MM-DD" | 2007-11-30 |
"YYYY-MM-DD HH:MM" | 2007-11-30 20:31 |
"YYYY-MM-DD HH:MM:SS" | 2007-11-30 20:31:31 |
"YYYY-MM-DD HH:MM:SS.SSS" | 2007-11-30 20:31:31.550 |
"YYYY-MM-DDTHH:MM" | 2007-11-30T:20:31 |
"YYYY-MM-DDTHH:MM:SS" | 2007-11-30T20:31:31 |
"YYYY-MM-DDTHH:MM:SS.SSS" | 2007-11-30T20:31:31.550 |
"HH:MM" | 20:31 |
"HH:MM:SS" | 20:31:31 |
"HH:MM:SS.SSS" | 20:31:31.550 |
注意:我包含了来自 http://www.sqlite.org/cvstrac/wiki?p=DateAndTimeFunctions 的格式字符串。格式字符串区分大小写。两位数年份假定在1990-2069年范围内。
调用此函数后,你应该使用 valid
函数来检查输入的日期是否有效。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-NOV-2007 20:31:31.55",
"DD-MON-YYYY hh:mm:ss.ss");
if (TSO.valid()) {
printf("%s\n",TSO.c_str());
} else {
printf("This date is not valid\n");
};
return 0;
};
RJMF_TimeStamp& operator= (const RJMF_TimeStamp& o);
这是赋值运算符。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-NOV-2007 20:31:31.55",
"DD-MON-YYYY hh:mm:ss.ss");
RJMF_TimeStamp TS1;
TS1 = TSO;
printf("%s\n",TS1.c_str());
return 0;
};
void AddYear(int num);
此函数在当前日期上增加一年。可以使用负数年份。在大多数情况下,月份和月份中的日期不会改变。然而,在少数情况下,这是不可能的。如果日期是2月29日,函数会检查它所在的年份是否是闰年。如果是闰年,它会正常进行;但是,如果不是闰年,它会将日期设置为3月1日。这导致了一个不寻常的情况,即加一年然后再减一年会导致不同的日期。此情况在示例中显示。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("29-FEB-2000","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddYear(1);
printf("+1 - %s\n",TSO.c_str());
TSO.AddYear(1);
printf("-1 - %s - Unusal as it is not where we started\n",TSO.c_str());
RJMF_TimeStamp TS1("29-FEB-2000","DD-MON-YYYY");
printf("\nStart - %s\n",TS1.c_str());
TS1.AddYear(4);
printf("+4 - %s\n",TS1.c_str());
TS1.AddYear(4);
printf("-4 - %s - still where we started because we added 4 years\n",TS1.c_str());
return 0;
};
void AddMonth(int num);
此函数在当前日期上增加一个月。这通常很简单,只需增加月份编号,但并非总是如此,因为有些月份的日期比其他月份多。如果月份中的日期在新月份中无效,则使用新月份的最后一天。这在示例中显示。要减去月份,只需为此函数传递一个负值。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddMonth(2);
printf("+2 - %s\n",TSO.c_str());
TSO.AddMonth(-2);
printf("-2 - %s - Unusal as it is not where we started\n",TSO.c_str());
return 0;
};
void AddDay(int num);
此函数在当前持有的日期上增加天数。要减去天数,只需传递一个负值。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddDay(365);
printf("365 days later - %s\n",TSO.c_str());
TSO.AddDay(-365);
printf("back to start - %s\n",TSO.c_str());
return 0;
};
void AddHour(int num);
此函数在当前持有的日期上增加小时数。要减去小时数,只需传递一个负值。可以给它传递大于24的小时数。此函数在必要时使用 AddDay
函数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddHour(48);
printf("%s\n",TSO.c_str());
TSO.AddHour(-48);
printf("back to start - %s\n",TSO.c_str());
return 0;
};
void AddMinute(int num);
此函数在当前持有的日期上增加分钟数。要减去分钟数,只需传递一个负值。可以给它传递大于59的分钟数。此函数在必要时使用 AddHour
函数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddMinute(121);
printf("%s\n",TSO.c_str());
TSO.AddMinute(-121);
printf("back to start - %s\n",TSO.c_str());
return 0;
};
void AddSecond(int num);
此函数在当前持有的日期上增加秒数。要减去秒数,只需传递一个负值。可以给它传递大于59的秒数。此函数在必要时使用 AddMinute
函数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddSecond(95);
printf("%s\n",TSO.c_str());
TSO.AddSecond(-95);
printf("back to start - %s\n",TSO.c_str());
return 0;
};
void AddHdthsecond(int num);
此函数在当前持有的日期上增加百分之一秒数。要减去百分之一秒数,只需传递一个负值。可以给它传递大于99的百分之一秒数。此函数在必要时使用 AddSecond
函数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp TSO("30-DEC-1999","DD-MON-YYYY");
printf("Start - %s\n",TSO.c_str());
TSO.AddHdthsecond(295);
printf("%s\n",TSO.c_str());
TSO.AddHdthsecond(-295);
printf("back to start - %s\n",TSO.c_str());
return 0;
};
float DiffYear(RJMF_TimeStamp* pO);
此函数返回调用日期与其传入日期之间的年数。返回的整数部分是年数。你可以使用 int(ans)
来仅获取整数部分,就像在示例中一样。小数部分代表年份的小数部分。我主要将其包含在内是为了排序目的(它使我能够对所有14岁的人进行排序,以便下一个满15岁的人排在列表顶部)。在小数部分,一天根据是否为闰年,相当于1/365或1/366。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dO;
float ans = dO.DiffYear(&dMe);
printf("I was %f years old when this program ran, "
"making me %d years old.\n",ans,int(ans));
return 0;
};
unsigned int DiffMonth(RJMF_TimeStamp* pO);
此函数返回调用日期与其传入日期之间的月数。它的工作方式与 DiffYear
和 DiffDay
函数不同,因为它运行一个循环并逐月计数。这使得它能够处理每个月不同的天数以及闰年等。有时需要将月数拆分为年和月,这可以使用 int(ans/12)
和 (ans % 12)
来完成,如示例所示。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dO;
unsigned ans = dO.DiffMonth(&dMe);
printf("I have been alive for %u months (%d years and %d months)\n",
ans, int(ans/12), ans % 12);
return 0;
};
unsigned int DiffDay(RJMF_TimeStamp* pO);
此函数返回调用日期与其传入日期之间的天数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dO;
unsigned ans = dO.DiffDay(&dMe);
printf("I have been alive for %u days\n",ans);
return 0;
};
unsigned int DiffSecond(RJMF_TimeStamp* pO);
此函数返回调用日期与其传入日期之间的秒数。包含此函数是因为毫秒数有时过大,无法正确存储答案。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dO;
unsigned int ans = dO.DiffSecond(&dMe);
printf("I have been alive for %u Seconds\n",ans);
return 0;
};
unsigned int DiffHdthSecond(RJMF_TimeStamp* pO);
此函数返回调用日期与其传入日期之间的百分之一秒数。无符号整数值可以存储高达4294967295的数字。这意味着如果日期相差超过400天,你将得到整数溢出,导致值错误。在这些情况下,使用第二个函数,它最多可以处理大约40,000天的差异(约100年)。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dMe2("22-NOV-2000","DD-MON-YYYY");
RJMF_TimeStamp dMe3("22-NOV-2007","DD-MON-YYYY");
RJMF_TimeStamp dO;
unsigned int ans = dO.DiffHdthSecond(&dMe);
printf("%u - Seconds since 1979\n",ans);
ans = dO.DiffHdthSecond(&dMe2);
printf("%u - Hang on, from 2000 it is more\n",ans);
ans = dO.DiffHdthSecond(&dMe3);
printf("%u - This is due to integer role over.");
printf("It's right for 2006, only works for about 400 days\n",ans);
return 0;
};
bool operator== (const RJMF_TimeStamp& o) const;
比较运算符比较两个对象,如果它们完全相等则返回 true
,否则返回 false
。此比较精确到毫秒。使用比较运算符时,始终要注意时间。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dNow;
if (dMe==dNow) {
//note will probally never work
//as dNow has the current time in it as well!
printf("I am being born right now\n");
} else {
printf("I am not being born right now\n");
};
RJMF_TimeStamp dBDayThisYear(0,0,0,0,22,11,dNow.GetYear());
RJMF_TimeStamp dNowDateOnly(0,0,0,0,dNow.GetDay(),
dNow.GetMonth(),dNow.GetYear());
if (dBDayThisYear==dNowDateOnly) {
printf("It's my birthday\n");
} else {
printf("It's not my birthday\n");
};
if (dMe==dMe) {
printf("Just checking...\n");
} else {
printf("Something is wrong\n");
};
return 0;
};
bool operator!= (const RJMF_TimeStamp& o) const;
如果类精确地保存日期和时间(精确到毫秒),则此运算符返回 false
,否则返回 true
。使用比较运算符时,始终要注意时间。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dNow;
if (dMe!=dNow) {
//note will probally never work as dNow
// has the current time in it as well!
printf("I am not being born right now\n");
} else {
printf("I am being born right now\n");
};
RJMF_TimeStamp dBDayThisYear(0,0,0,0,22,11,dNow.GetYear());
RJMF_TimeStamp dNowDateOnly(0,0,0,0,dNow.GetDay(),
dNow.GetMonth(),dNow.GetYear());
if (dBDayThisYear!=dNowDateOnly) {
printf("It's not my birthday\n");
} else {
printf("It's my birthday\n");
};
if (dMe!=dMe) {
printf("Something is wrong\n");
} else {
printf("Just checking...\n");
};
return 0;
};
bool operator< (const RJMF_TimeStamp& rhs ) const;
如果左侧时间戳早于右侧时间戳,则此运算符返回 true
。使用比较运算符时,始终要注意时间。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dNow;
if (dNow<dMe) {
printf("I don't exist yet so this code can't have been written\n");
} else {
printf("I exist - phew that's a relief");
};
return 0;
};
bool operator<= (const RJMF_TimeStamp& rhs ) const;
小于或等于运算符将在左侧值早于右侧值时返回 true
;相等时返回 true
,否则返回 false
。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dMe2("22-NOV-1979 13:34","DD-MON-YYYY hh:mm");
if (dMe<=dMe2) {
printf("Shows you need to check times as well as dates.\n");
printf("%s<=%s\n",dMe.c_str(),dMe2.c_str());
} else {
};
if (dMe<=dMe) {
printf("Sanity check passed\n");
} else {
printf("Something is wrong\n");
};
return 0;
};
bool operator> (const RJMF_TimeStamp& rhs ) const;
如果左侧时间戳晚于右侧时间戳,则此运算符返回 true
。使用比较运算符时,始终要注意时间。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dNow;
if (dNow>dMe) {
printf("It is after my birthday\n");
} else {
printf("It is before the time I am being born (or it is the time I am being born)\n");
};
return 0;
};
bool operator>= (const RJMF_TimeStamp& rhs ) const;
大于或等于运算符将在两个参数相等时返回 true
,左侧参数大于右侧参数时返回 false
,否则返回 true
。使用比较运算符时,始终要注意时间。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dMe("22-NOV-1979","DD-MON-YYYY");
RJMF_TimeStamp dNow;
if (dNow>=dMe) {
printf("%s>=%s\n",dNow.c_str(),dMe.c_str());
} else {
printf("Huh - have u been playing with the dates on your computer?\n");
};
return 0;
};
bool valid();
此函数用于确定类是否已正确安装。如果类设置为无效日期,则返回 false
。这对于检查用户输入很有用。注意:strftime
函数(以及因此的 c_str
函数)在对无效日期调用时将返回字符串 *INVALID*。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dSomeDate(0,0,0,0,31,31,2007);
if (dSomeDate.valid()) {
printf("This is a valid date %s\n",dSomeDate.c_str());
} else {
printf("This date is not valid %s\n",dSomeDate.c_str());
};
return 0;
};
unsigned int GetYear();
GetYear
函数以无符号整数形式返回日期的年份部分。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current year is %u\n",dNow.GetYear());
return 0;
};
unsigned int GetMonth();
GetMonth
函数以无符号整数形式返回日期的月份部分。有关如何输出此数据的文本表示,请参阅 strftime
函数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current year is %u\n",dNow.GetYear());
printf("The current month is %u\n",dNow.GetMonth());
return 0;
};
unsigned int GetDay();
GetDay
函数以无符号整数形式返回月份中的天数(1-31)。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current year is %u\n",dNow.GetYear());
printf("The current month is %u\n",dNow.GetMonth());
printf("The current day of month is %u\n",dNow.GetDay());
return 0;
};
unsigned int GetDOW();
GetDOW
函数以无符号整数形式返回星期几。有关如何输出此数据的文本表示,请参阅 strftime
函数。
日 | 返回值 |
---|---|
Sunday | 0 |
Monday | 1 |
星期二 | 2 |
星期三 | 3 |
星期四 | 4 |
Friday | 5 |
Saturday | 6 |
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current year is %u\n",dNow.GetYear());
printf("The current month is %u\n",dNow.GetMonth());
printf("The current day of month is %u\n",dNow.GetDay());
printf("The current day of week is %u\n",dNow.GetDOW());
return 0;
};
unsigned int GetDOY();
GetDOY
函数以无符号整数形式返回一年中的第几天(1-366)。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current year is %u\n",dNow.GetYear());
printf("The current month is %u\n",dNow.GetMonth());
printf("The current day of month is %u\n",dNow.GetDay());
printf("The current day of week is %u\n",dNow.GetDOW());
printf("The current day of year is %u\n",dNow.GetDOY());
return 0;
};
unsigned int GetHour();
GetHour
函数以无符号整数形式返回时间的时部分。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current hour is %u\n",dNow.GetHour());
return 0;
};
unsigned int GetMinute();
GetMinute
函数以无符号整数形式返回时间的分钟部分。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current hour is %u\n",dNow.GetHour());
printf("The current minute is %u\n",dNow.GetMinute());
return 0;
};
unsigned int GetSecond();
GetSecond
函数以无符号整数形式返回时间的秒部分。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current hour is %u\n",dNow.GetHour());
printf("The current minute is %u\n",dNow.GetMinute());
printf("The current Second is %u\n",dNow.GetSecond());
return 0;
};
unsigned int GetHdthsecond();
GetHdthsecond
函数以无符号整数形式返回时间的百分之一秒部分。默认构造函数不会填充时间的毫秒部分。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("The current hour is %u\n",dNow.GetHour());
printf("The current minute is %u\n",dNow.GetMinute());
printf("The current Second is %u\n",dNow.GetSecond());
printf("The Hdthsecond is %u\n",dNow.GetHdthsecond());
printf("Note: The default constructor dosn't ");
printf("populate down to the nearest hdthsecond\n");
return 0;
};
unsigned int GetHdthsecondsRAW();
我创建此函数主要是为了测试,但将其保留下来,因为它可能很有用。它返回自年初以来经过的毫秒数。(12月31日午夜和1月1日午夜之间)。这最多为 100 * 60 * 60 * 24 * 366 = 31622400000,这刚好在 unsigned int 的限制之内。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
printf("There have been %u hdthseconds since the start of the year.\n",
dNow.GetHdthsecondsRAW());
return 0;
};
void strftime(char* pOutput, const char* pFormat);
此函数以格式化字符串的形式返回当前日期和时间。我试图遵循 http://uk3.php.net/strftime 中设置的格式字符串,但我也添加了自己的格式字符串以包含毫秒。有效的格式字符串如下所示
字符串 | 含义 | 示例 |
---|---|---|
%a | 短星期 | 周五 |
%A | 长星期 | Friday |
%b | 短月份 | 八月 |
%B | 长月份 | 八月 |
%d | 月份中的天数 | 03 |
%H | 小时(24小时制) | 14 |
%I | 小时(12小时制) | 02 |
%j | 一年中的第几天 | 215 |
%m | 月份(数字) | 08 |
%M | 分钟 | 43 |
%S | 第二种 | 13 |
%t | 选项卡 | \t |
%w | 星期几(十进制),星期日为 0 | 5 |
%y | 短年份 | 07 |
%Y | 长年份 | 2007 |
%% | 百分比 | % |
%! | 百分之一秒 | 22.11 |
%£ | 仅百分之一秒 | 11 |
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
char buf[255];
dNow.strftime(buf, "%a %A %b %B %c %d %H %I %j %m %M %S %U %W %w %x %X %y %Y %% %! %£");
printf("Today:%s\n",buf);
return 0;
};
bool IsLeapYear();
此函数返回 true
如果当前年份是闰年,否则返回 false
。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
RJMF_TimeStamp dNow;
if (dNow.IsLeapYear()) {
printf("%d is a leap year\n",dNow.GetYear());
} else {
printf("%d is not a leap year\n",dNow.GetYear());
};
return 0;
};
static bool IsLeapYear(unsigned int Year);
此函数将返回 true
如果传入的年份是闰年,否则返回 false
。它是一个静态函数,不使用对象中加载的当前日期和时间,因此可以按需使用。一种应用是计算两个日期之间的闰年数。
#include <iostream>
#include <math.h>
#include "RJMFTime.h"
int main() {
unsigned int num_leap_years = 0;
for (int c=0;c<3000;c++) {
if (RJMF_TimeStamp::IsLeapYear(c)) num_leap_years++;
};
printf("There are %u leap years in the first 3000 years\n",num_leap_years);
return 0;
};
查找和修正错误
与任何非简单的大型代码一样,总有存在 bug 的可能性。我之所以不想开发自己的时间戳类,部分原因是因为像 time_t
和 CTime
这样的类被许多程序员使用,并且大部分 bug 已经被定位并修复。不幸的是,我不得不自己制作一个,并且我在我的程序中使用了这个类,尽管我担心可能仍然存在 bug。
为了测试这个类,我创建了 *TimeTest.cpp*。(TimeTest 包含在下载文件中。)这个程序运行了许多测试,并确保该类给出了预期的输出。每当我更改该类时,我都会检查以确保 TimeTest 继续工作,这让我有信心没有破坏其他任何东西。你可以编译并运行 TimeTest 来确保该类在你的系统上正常工作。
如果有人希望在自己的程序中使用此类别,他们可以这样做。无需付费,您也不需要给我任何信用,甚至不需要告诉我您正在这样做。如果您发现代码中的 bug,我希望您遵循下面概述的流程。这将使我能够修复 bug 并与他人分享修复方案。
- 确定类给出错误输出的具体情况。
- 在 *TimeTest.cpp* 中创建一个函数,该函数将导致 TimeTest 因你发现的错误而失败,但在错误修复后会通过。
- 将该函数和对错误的解释通过电子邮件发送给我。如果你能提出修复建议,那将会有所帮助。
如果这是一个真正的问题,我将通过将你的测试纳入 TimeTest 并修改该类来修复该问题。这样做将增加此类的价值。
算法改进
没有什么是完美的,我使用的算法可能通过了我创建的测试,但它们可能不是实现所需结果的最佳方式。拥有完整的测试套件的另一个好处是,当我更改某项功能的工作方式时,我可以立即对新的工作方式有信心。(只要它通过了测试!)
如果有人对特定函数的工作方式有任何评论,并能提出更好的方法来完成相同的事情,那将非常受欢迎。同样,这将改进我所有使用该类的程序!我在 TimeTest 中加入了一些基本的基准测试。作为改进算法速度的一部分,我可以修改 TimeTest,使其也对有问题的函数进行压力测试,并使用基准测试结果来比较不同算法的效率。
我希望它能做到 x
这个类可以通过添加额外功能来改进。我欢迎任何关于还有什么有用的想法。
历史
- 文章创建于2007年8月6日至8月10日之间。
- 2007年8月11日 - 进行了两个主要更改。第一个是,我更改了源文件,以便 TimeTest 符合 Visual Studio 6.0 标准。(我使用 DJGPP 编写了它,并且需要进行一些小的更改才能使其在 Visual Studio 中正常工作。)第二个更改是由于我犯了一个基本的术语错误,将百分之一秒称为毫秒。我现在已经仔细检查了源文件和文章,用百分之一秒替换了毫秒。这并不是代码更改,只是我用了错误的术语。