1. 关键类简介
- wxDateTime :时间点(时刻/Moment)
- wxTimeSpan : 绝对时间长度(以毫秒表达的两个时间点之间的长度)
- wxDateSpan : 日历时间跨度(用以表达日历上两个时间点之间的跨度,比如多少周,多少月,多少年)
关键点:2025 年 2 月 1 日 0 点 0 分 0 秒 和 2025 年 1 月 31 日 23 点 59 分 59 秒,使用 wxTimeSpan表达,二者相差一秒,使用 wxDateSpan 表达,二者相差一天,也相差一月。
2. 视频1-数字时钟、常用方法
2.1 wxDateTime 构造
- wxDateTime(); // 默认构造 :得到一个非法时间
- wxDateTime(time_t t); // 从C的时间戳转换
- wxDateTime(tm tm); // 从C的时间结构tm转换
- wxDateTime(h, m, s, ms); // 指定时分秒毫秒(类型 wxDateTime_t),日期为当天
- wxDateTime(wxDateTime_t day, Month month, int year, h=0, m=0, s=0, ms=0);
2.2 wxDateTime 设置
- Now(); // 静态方法,取得当前日期时间;
- Today(); // 静态方法 取得当前日期(时间为 0点0分0秒)
- Set()、Set( time_t )、Set( tm )、Set(h, m, s, ms)、Set(day, month, year, h,m,s,ms); // 对应5个构造函数
- SetYear(int year)、SetMonth(Month month)、SetDay(wxDateTime_t day)
SetHour(h)、SetMinute(m)、SetSecond(s)、SetMillisecond(ms); // 设置各日期时间组成部分 - SetToCurrent() // 设置为当前时间,相当于 Now() 的非静态版本;
- ResetTime(); // 日期不变,时间归零(午夜零点零分零秒零毫秒)
2.3 wxDateTime 查询
- 转回 C 的时间数据:GetTm() -> tm;GetTicks() -> time_t;
- 取各组成部分:GetYear()、GetMonth()、GetDay()、GetHour()、GetMinute()、GetSecond()、GetMilisecond()、GetDateOnly();
- 自动计算:GetWeekDay() -> WeekDay;GetDayOfYear() -> wxDateTime_t;GetWeekOfMonth(WeekFlags flag = Monday_First);GetWeekOfYear(WeekFlags flag = Monday_First)
2.4 wxDateTime 嵌套类型定义
- 月份枚举:wxDateTime::Month : Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec, Inv_Month; 枚举值从 0 开始;
- 星期枚举:wxDateTime::WeekDay : Sun, Mon, Tue, Wed, Thu, Fri, Sat, Inv_WeekDay;枚举值从0开始,且周日为每周第一天;
- 星期标志枚举:wxDateTime::WeekFlags : 和周相关的计算时,用于指定每周的开始日为周一或周日,其值有 Default_First(美国默认周日开始、其他默认周一开始),Monday_First、Sunday_First;
2.5 wxDateTime 到 字符串
- wxString Format (wxChar* const* fmt);
- wxString FormatDate() ; // Format("%x");
- wxString FormatTime(); // Format("%X");
- wxString FormatISODate(); //YYYY-MM-DD
- wxString FormatISOTime(); //HH:MM:SS
说明 :
- 需要转换为指定的格式日期、时间字符串时,所需要的格式化指示串(fmt) 说明,见:C/C++ strftime 函数;
- FormatDate() 相当于 Format("%x"),将得到类似 MM/DD/YY 的日期串;
- FormatTime() 相当于 Format("%X"),将得到类似 HH:MM:SS 的时间串;
- FormatISODate() 得到类似 YYYY-MM-DD 格式日期串,此格式符合 ISO-8601;
- FormatISOTime() 得到 HH:MM:SS 格式时间串,此格式符合 ISO-8601;
- 可自行组装出 YYYY-MM-DDTHH:MM:SS格式的,符合 ISO-8601 的日期时间串;
2.6 解析字符串至 wxDateTime
- wxChar const* ParseFormat(wxChar const* s, const wxChar *format = wxDefaultDateTimeFormat, const wxDateTime& dateDef = wxDefaultDateTime); // 使用指定的格式,尝试解析字符串 s 的内容以获取日期时间值,解析失败的值,从 dateDef 中获取;解析失败返回空指针,否则返回解析结束于源串 s 的指针偏移;
- wxChar const* ParseDateTime(wxChar const *datetime); 尽最多可能尝试,解析 datetime 串中的日期与时间信息;
- wxChar const* ParseDate(wxChar const* date); 尽最多可能尝试,解析 date 串中的日期信息;
- wxChar const* ParseTime(wxChar const* time); 尽最多可能尝试,解析 time 串中的时间信息;
重要:尽量在业务需求与设计上,限定仅需对符合 ISO 标准的字符串做转换。
3. 视频2-日期计算(含人生时光计算功能)
3.1 wxDateTime 判断、比较
- bool IsValid() // 判断当前日期时间数据是否合法;
- 相等判断:dt1 == dt2 ,或 dt1.IsEqualTo(dt2);
- 大于判断:dt1 > dt2,或 dt1.IsLaterThan(dt2);
- 小于判断:dt1 < dt2,或 dt1.IsEarlierThan(dt2);
- 期间判断:dt >= dt1 && dt <= dt2,或 dt.IsBetween(dt1, dt2);
- 严格期间判断:dt > dt1 && dt < dt2, 或 dt.IsStrictlyBetween(dt1, dt2);
注:以上两个期间判断参数,需满足 dt1 小于或等于 dt2。
- 闰年判断:wxDateTime::IsLeayYear(year = Inv_Year);
IsLeayYear
是一个静态方法,需要一个入参(年份),但是,该入参默认值(一个非法年份)。唯一入参又有默认值,将千万该静态方法非常容易被误用为:
// IsLeayYear 的错误用法示例:
wxDateTime now = wxDateTime::Now();
if ( now.IsLeapYear() ) // 错误,永远无法返回 true
{
wxMessageBox(L"今年是闰年"!);
}
- 工作日判断:IsWorkDay();
除时区、日历法(wxDateTime 有限支持从 Julian Day Number 转换)外,wxTimeDate 还可设置国别(国家、地区),并于国家(或地区)基础上,提供 IsWorkDay()
这样的方法——显然不可信。
3.2 时间点相减
wxDateTime - wxDateTime
固定得到一个 wxTimeSpan。 内含两个时间点之间存在多少毫秒(可正可负),并且,基于毫秒数(类型为 wxLongLong,类似 C++11 后的 long long),可折算为多少秒(同样为 wxLongLong)、多少分钟、小时、天(24小时)、周(7天);但不能换算为多少个月(因为月的天数不固定)。
3.3 时间点 ± 时间长度
时间点(wxDateTime)可以加减一个时间绝对长度(wxTimeSpan),或者加减一个日历时间长度(wxDateSpan)。
时间点加上或减去一个 wxTimeSpan,本质是在原时间点的基础上,加上或减去指定的毫秒数,从而得到另一个时间点。即,无论 wxTimeSpan 是多长,参加计算时,都是准确的毫秒数。
时间点加上或减去一个 wxDateSpan,能参加计算的偏移量,从一天开始,到一周、一月、一年。比如,假设时间点是 2月1日,加上一个月的偏移,将得到 3月1日——尽管,从2月1日开始往后到 3月1日,并不足30天。再有,假设当前时间点是 7月31日,减去1月,将自动得到6月30日(6月没有31日)。
wxDateSpan 可以指定组合的长度,比如,以下代码用来计算今天再过“一个月又十三天”后,是几月几日:
wxDateSpan ds;
ds.SetMonths(1).SetDays(13);
wxDateTime dt = wxDateTime::Today() + ds; // 今天+1月又13天
4. 关键代码
// 数字时钟
void HelloDateTimeDialog::OnTimer1Trigger(wxTimerEvent& event)
{
wxDateTime now = wxDateTime::Now();
wxString lable = now.Format(L"%Y/%m/%d %H:%M:%S");
this->TextTime->SetLabel(lable);
this->Layout();
}
// 时光计算
void HelloDateTimeDialog::OnButtonLifeClick(wxCommandEvent& event)
{
wxDateTime now = wxDateTime::Now();
wxDateTime birthday = wxDateTime(1, wxDateTime::Jun, 2004); // 生日:2004/6/1
// 判断一下 “是否出生了”……
if (now.IsEarlierThan(birthday))
{
wxMessageBox(L"还没出生?", L"有问题吧!");
return;
}
int life;
if (life = wxGetNumberFromUser(L"请基于自身的生活与健康状态和\n内心意愿……"
, L"输入预估寿命长度(年):"
, L"生命预估"
, 79 // 使用我国人均寿命作为默认值
, now.GetYear() - birthday.GetYear() + 1 // 最小(当前岁数)
, 150 // 最大: 150
, this); life == -1)
{
return;
}
// 告别日子
wxDateTime farewellDay = birthday + wxDateSpan().SetYears(life);
wxTimeSpan daysPass = now - birthday; // 已经度过的时光
wxTimeSpan daysFuture = farewellDay - now; // 未来时光
wxString msg;
msg << L"你生出于:" << birthday.Format(L"%Y年-%m月-%d日");
msg << L"\n自我评估寿命:" << life << L" 年";
msg << L"\n回首往昔,人生已度过匆匆的 " << daysPass.GetDays()
<< L" 天,计 " << daysPass.GetHours() << L" 小时";
msg << L"\n展望未来,人生还有 " << daysFuture.GetDays() << L" 个日日夜夜需要面对";
auto percen = static_cast<double>(daysPass.GetHours())
/ (daysPass.GetHours() + daysFuture.GetHours()) * 100;
msg << L"\n你的人生进度是:" << percen << L"%,请珍惜生命中的每一段快乐时光!";
wxMessageBox(msg, L"人生时光");
}