505 lines
11 KiB
C++
505 lines
11 KiB
C++
#include "DateTime.h"
|
|
#include <chrono>
|
|
#include <format>
|
|
#include <stdexcept>
|
|
|
|
void DateTime::UpdateDT()
|
|
{
|
|
namespace ch = std::chrono;
|
|
auto tp = ch::system_clock::from_time_t(storage);
|
|
|
|
try
|
|
{
|
|
// C++20 时区感知:将系统时间转换为本地时间
|
|
auto local_tp = ch::current_zone()->to_local(tp);
|
|
auto dp = ch::floor<ch::days>(local_tp);
|
|
|
|
ch::year_month_day ymd { dp };
|
|
ch::hh_mm_ss hms { local_tp - dp };
|
|
|
|
sep_time.year = static_cast<int>(ymd.year());
|
|
sep_time.month = static_cast<unsigned>(ymd.month());
|
|
sep_time.day = static_cast<unsigned>(ymd.day());
|
|
sep_time.hour = hms.hours().count();
|
|
sep_time.minute = hms.minutes().count();
|
|
sep_time.second = static_cast<int>(hms.seconds().count());
|
|
}
|
|
catch (...)
|
|
{
|
|
// 备用方案:如果系统未配置或不支持本地时区数据库,平滑降级到传统安全实现
|
|
std::tm ptm {};
|
|
#ifdef _WIN32
|
|
localtime_s(&ptm, &storage);
|
|
#else
|
|
localtime_r(&storage, &ptm);
|
|
#endif
|
|
sep_time.year = ptm.tm_year + 1900;
|
|
sep_time.month = ptm.tm_mon + 1;
|
|
sep_time.day = ptm.tm_mday;
|
|
sep_time.hour = ptm.tm_hour;
|
|
sep_time.minute = ptm.tm_min;
|
|
sep_time.second = ptm.tm_sec;
|
|
}
|
|
}
|
|
|
|
time_t DateTime::FormatConvert(int year, int month, int day, int hour, int minute, int second)
|
|
{
|
|
namespace ch = std::chrono;
|
|
try
|
|
{
|
|
ch::year_month_day ymd { ch::year{year}, ch::month{static_cast<unsigned>(month)}, ch::day{static_cast<unsigned>(day)} };
|
|
if (!ymd.ok())
|
|
return 0;
|
|
|
|
auto local_tp = ch::local_days { ymd } + ch::hours { hour } + ch::minutes { minute } + ch::seconds { second };
|
|
// 将本地时间根据当前系统时区转换为系统标准时间(UTC)
|
|
return ch::system_clock::to_time_t(ch::current_zone()->to_sys(local_tp));
|
|
}
|
|
catch (...)
|
|
{
|
|
std::tm stm {};
|
|
stm.tm_year = year - 1900;
|
|
stm.tm_mon = month - 1;
|
|
stm.tm_mday = day;
|
|
stm.tm_hour = hour;
|
|
stm.tm_min = minute;
|
|
stm.tm_sec = second;
|
|
stm.tm_isdst = -1;
|
|
return ::mktime(&stm);
|
|
}
|
|
}
|
|
|
|
time_t DateTime::SpanedSeconds(Span sp)
|
|
{
|
|
namespace ch = std::chrono;
|
|
auto total = ch::days { sp.days } + ch::hours { sp.hours } + ch::minutes { sp.minutes } + ch::seconds { sp.seconds };
|
|
return ch::duration_cast<ch::seconds>(total).count();
|
|
}
|
|
|
|
DateTime::Span DateTime::ToSpan(time_t tim)
|
|
{
|
|
// 修复了原代码中天数数额赋给秒、余数计算混乱的 Bug
|
|
namespace ch = std::chrono;
|
|
ch::seconds total_secs { tim };
|
|
|
|
auto d = ch::duration_cast<ch::days>(total_secs);
|
|
total_secs -= d;
|
|
|
|
auto h = ch::duration_cast<ch::hours>(total_secs);
|
|
total_secs -= h;
|
|
|
|
auto m = ch::duration_cast<ch::minutes>(total_secs);
|
|
total_secs -= m;
|
|
|
|
Span sp;
|
|
sp.days = static_cast<int>(d.count());
|
|
sp.hours = static_cast<int>(h.count());
|
|
sp.minutes = static_cast<int>(m.count());
|
|
sp.seconds = static_cast<int>(total_secs.count());
|
|
return sp;
|
|
}
|
|
|
|
DateTime::DateTime()
|
|
{
|
|
storage = ::time(nullptr);
|
|
UpdateDT();
|
|
}
|
|
|
|
DateTime::DateTime(time_t t)
|
|
{
|
|
storage = t;
|
|
UpdateDT();
|
|
}
|
|
|
|
DateTime::DateTime(const tm& stm)
|
|
{
|
|
storage = ::mktime(const_cast<tm*>(&stm));
|
|
UpdateDT();
|
|
}
|
|
|
|
DateTime::DateTime(const Full& ftm)
|
|
{
|
|
storage = FormatConvert(ftm.year, ftm.month, ftm.day, ftm.hour, ftm.minute, ftm.second);
|
|
UpdateDT();
|
|
}
|
|
|
|
DateTime::DateTime(int year, int month, int day, int hour, int minute, int second)
|
|
{
|
|
storage = FormatConvert(year, month, day, hour, minute, second);
|
|
UpdateDT();
|
|
}
|
|
|
|
DateTime::DateTime(const DateTime& obj)
|
|
{
|
|
storage = obj.storage;
|
|
sep_time = obj.sep_time;
|
|
}
|
|
|
|
DateTime DateTime::Now()
|
|
{
|
|
return DateTime(::time(nullptr));
|
|
}
|
|
|
|
time_t DateTime::GetTimeStamp() const
|
|
{
|
|
return storage;
|
|
}
|
|
|
|
int DateTime::GetYear() const
|
|
{
|
|
return sep_time.year;
|
|
}
|
|
|
|
int DateTime::GetMonth() const
|
|
{
|
|
return sep_time.month;
|
|
}
|
|
|
|
int DateTime::GetDay() const
|
|
{
|
|
return sep_time.day;
|
|
}
|
|
|
|
int DateTime::GetHour() const
|
|
{
|
|
return sep_time.hour;
|
|
}
|
|
|
|
int DateTime::GetMinute() const
|
|
{
|
|
return sep_time.minute;
|
|
}
|
|
|
|
int DateTime::GetSecond() const
|
|
{
|
|
return sep_time.second;
|
|
}
|
|
|
|
DateTime::Full DateTime::GetFullDateTime() const
|
|
{
|
|
return sep_time;
|
|
}
|
|
|
|
std::string DateTime::Format(std::string fmt_str)
|
|
{
|
|
namespace ch = std::chrono;
|
|
try
|
|
{
|
|
// 1. 获取系统标准时间点
|
|
auto tp = ch::system_clock::from_time_t(storage);
|
|
|
|
// 2. 转换为本地时间点
|
|
auto local_tp = ch::current_zone()->to_local(tp);
|
|
|
|
// 3. 截断到秒级精度(防止打印出纳秒/微秒的小数点),并获取 C++20 支持格式化的强类型
|
|
auto local_secs = ch::floor<ch::seconds>(local_tp);
|
|
|
|
// 4. 组装 C++20 chrono 格式化字符串并执行
|
|
std::string chrono_fmt = "{:" + fmt_str + "}";
|
|
return std::vformat(chrono_fmt, std::make_format_args(local_secs));
|
|
}
|
|
catch (...)
|
|
{
|
|
// 如果 C++20 运行时时区数据库不可用,或者 fmt_str 包含不兼容的传统旧语法,平滑降级
|
|
size_t size = (fmt_str.size() * 2) + 10;
|
|
auto recv = std::make_unique<char[]>(size);
|
|
std::tm suctm = static_cast<std::tm>(*this);
|
|
size_t ret = ::strftime(recv.get(), size, fmt_str.c_str(), &suctm);
|
|
while (ret == 0)
|
|
{
|
|
size *= 2;
|
|
recv = std::make_unique<char[]>(size);
|
|
ret = ::strftime(recv.get(), size, fmt_str.c_str(), &suctm);
|
|
}
|
|
return std::string(recv.get());
|
|
}
|
|
}
|
|
|
|
bool DateTime::IsAM()
|
|
{
|
|
return (sep_time.hour < 12);
|
|
} // 修正逻辑:通常12点后为PM
|
|
|
|
bool DateTime::IsPM()
|
|
{
|
|
return (sep_time.hour >= 12);
|
|
}
|
|
|
|
bool DateTime::TimePassed()
|
|
{
|
|
return (storage < ::time(nullptr));
|
|
} // 修正逻辑:过去的时间应该小于现在
|
|
|
|
DateTime::operator tm()
|
|
{
|
|
std::tm stm {};
|
|
stm.tm_year = sep_time.year - 1900;
|
|
stm.tm_mon = sep_time.month - 1;
|
|
stm.tm_mday = sep_time.day;
|
|
stm.tm_hour = sep_time.hour;
|
|
stm.tm_min = sep_time.minute;
|
|
stm.tm_sec = sep_time.second;
|
|
stm.tm_isdst = -1;
|
|
return stm;
|
|
}
|
|
|
|
DateTime::operator Full()
|
|
{
|
|
return sep_time;
|
|
}
|
|
|
|
DateTime::operator time_t()
|
|
{
|
|
return storage;
|
|
}
|
|
|
|
DateTime::operator std::string()
|
|
{
|
|
return Format("%Y-%m-%dT%H:%M:%S+08:00");
|
|
}
|
|
|
|
// ================== 运算符重载实现 ==================
|
|
DateTime::Span DateTime::operator-(const tm& stm)
|
|
{
|
|
return ToSpan(storage - ::mktime(const_cast<tm*>(&stm)));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator-(const Span& ts)
|
|
{
|
|
return ToSpan(storage - SpanedSeconds(ts));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator-(const Full& sdt)
|
|
{
|
|
return ToSpan(storage - FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator-(const time_t& t)
|
|
{
|
|
return ToSpan(storage - t);
|
|
}
|
|
|
|
DateTime::Span DateTime::operator-(const DateTime& dt)
|
|
{
|
|
return ToSpan(storage - dt.storage);
|
|
}
|
|
|
|
DateTime::Span DateTime::operator+(const tm& stm)
|
|
{
|
|
return ToSpan(storage + ::mktime(const_cast<tm*>(&stm)));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator+(const Span& ts)
|
|
{
|
|
return ToSpan(storage + SpanedSeconds(ts));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator+(const Full& sdt)
|
|
{
|
|
return ToSpan(storage + FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second));
|
|
}
|
|
|
|
DateTime::Span DateTime::operator+(const time_t& t)
|
|
{
|
|
return ToSpan(storage + t);
|
|
}
|
|
|
|
DateTime::Span DateTime::operator+(const DateTime& dt)
|
|
{
|
|
return ToSpan(storage + dt.storage);
|
|
}
|
|
|
|
DateTime DateTime::operator=(const tm& stm)
|
|
{
|
|
storage = ::mktime(const_cast<tm*>(&stm)); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator=(const Full& sdt)
|
|
{
|
|
storage = FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator=(const time_t& t)
|
|
{
|
|
storage = t; UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator=(const DateTime& dt)
|
|
{
|
|
storage = dt.storage; UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator+=(const tm& stm)
|
|
{
|
|
storage += ::mktime(const_cast<tm*>(&stm)); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator+=(const Span& ts)
|
|
{
|
|
storage += SpanedSeconds(ts); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator+=(const Full& sdt)
|
|
{
|
|
storage += FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator+=(const time_t& t)
|
|
{
|
|
storage += t; UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator+=(const DateTime& dt)
|
|
{
|
|
storage += dt.storage; UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator-=(const tm& stm)
|
|
{
|
|
storage -= ::mktime(const_cast<tm*>(&stm)); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator-=(const Span& ts)
|
|
{
|
|
storage -= SpanedSeconds(ts); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator-=(const Full& sdt)
|
|
{
|
|
storage -= FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second); UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator-=(const time_t& t)
|
|
{
|
|
storage -= t; UpdateDT(); return *this;
|
|
}
|
|
|
|
DateTime DateTime::operator-=(const DateTime& dt)
|
|
{
|
|
storage -= dt.storage; UpdateDT(); return *this;
|
|
}
|
|
|
|
bool DateTime::operator==(const tm& stm)
|
|
{
|
|
return storage == ::mktime(const_cast<tm*>(&stm));
|
|
}
|
|
|
|
bool DateTime::operator==(const Full& sdt)
|
|
{
|
|
return storage == FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second);
|
|
}
|
|
|
|
bool DateTime::operator==(const time_t& t)
|
|
{
|
|
return storage == t;
|
|
}
|
|
|
|
bool DateTime::operator==(const DateTime& dt)
|
|
{
|
|
return storage == dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator!=(const tm& stm)
|
|
{
|
|
return !(*this == stm);
|
|
}
|
|
|
|
bool DateTime::operator!=(const Full& sdt)
|
|
{
|
|
return !(*this == sdt);
|
|
}
|
|
|
|
bool DateTime::operator!=(const time_t& t)
|
|
{
|
|
return storage != t;
|
|
}
|
|
|
|
bool DateTime::operator!=(const DateTime& dt)
|
|
{
|
|
return storage != dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator>(const tm& stm)
|
|
{
|
|
return storage > ::mktime(const_cast<tm*>(&stm));
|
|
}
|
|
|
|
bool DateTime::operator>(const Full& sdt)
|
|
{
|
|
return storage > FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second);
|
|
}
|
|
|
|
bool DateTime::operator>(const time_t& t)
|
|
{
|
|
return storage > t;
|
|
}
|
|
|
|
bool DateTime::operator>(const DateTime& dt)
|
|
{
|
|
return storage > dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator>=(const tm& stm)
|
|
{
|
|
return storage >= ::mktime(const_cast<tm*>(&stm));
|
|
}
|
|
|
|
bool DateTime::operator>=(const Full& sdt)
|
|
{
|
|
return storage >= FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second);
|
|
}
|
|
|
|
bool DateTime::operator>=(const time_t& t)
|
|
{
|
|
return storage >= t;
|
|
}
|
|
|
|
bool DateTime::operator>=(const DateTime& dt)
|
|
{
|
|
return storage >= dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator<(const tm& stm)
|
|
{
|
|
return storage < ::mktime(const_cast<tm*>(&stm));
|
|
}
|
|
|
|
bool DateTime::operator<(const Full& sdt)
|
|
{
|
|
return storage < FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second);
|
|
}
|
|
|
|
bool DateTime::operator<(const time_t& t)
|
|
{
|
|
return storage < t;
|
|
}
|
|
|
|
bool DateTime::operator<(const DateTime& dt)
|
|
{
|
|
return storage < dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator<(const DateTime& dt) const
|
|
{
|
|
return storage < dt.storage;
|
|
}
|
|
|
|
bool DateTime::operator<=(const tm& stm)
|
|
{
|
|
return storage <= ::mktime(const_cast<tm*>(&stm));
|
|
}
|
|
|
|
bool DateTime::operator<=(const Full& sdt)
|
|
{
|
|
return storage <= FormatConvert(sdt.year, sdt.month, sdt.day, sdt.hour, sdt.minute, sdt.second);
|
|
}
|
|
|
|
bool DateTime::operator<=(const time_t& t)
|
|
{
|
|
return storage <= t;
|
|
}
|
|
|
|
bool DateTime::operator<=(const DateTime& dt)
|
|
{
|
|
return storage <= dt.storage;
|
|
} |