chenluhua1980
2026-01-10 ded981a2ac5dbb456bafce5468d7289bc45e313b
SourceCode/Bond/Servo/ToolUnits.cpp
@@ -3,7 +3,10 @@
#include <chrono>
#include <memory>
#include <sstream>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <sstream>
CToolUnits::CToolUnits()
{
@@ -74,9 +77,17 @@
ULONGLONG CToolUnits::getTimestamp()
{
   // 返回毫秒数的版本
   auto now = std::chrono::system_clock::now();
   auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
   return static_cast<ULONGLONG>(ms.time_since_epoch().count());
}
time_t CToolUnits::getUnixTimestamp()
{
   // 返回秒数的版本
   auto now = std::chrono::system_clock::now();
   return std::chrono::system_clock::to_time_t(now);
}
void CToolUnits::createDir(const char* pszDir)
@@ -328,4 +339,279 @@
   if (nLength > 0) {
      strOut = std::string(pszBuffer, nLength);
   }
}
// FILETIME(UTC) -> time_point
std::chrono::system_clock::time_point CToolUnits::FileTimeToTimePointUTC(const FILETIME& ftUtc) {
   ULARGE_INTEGER ull;
   ull.LowPart = ftUtc.dwLowDateTime;
   ull.HighPart = ftUtc.dwHighDateTime;
   // 1601-01-01 到 1970-01-01 的 100ns tick
   constexpr unsigned long long EPOCH_DIFF_100NS = 116444736000000000ULL;
   unsigned long long t100 = ull.QuadPart - EPOCH_DIFF_100NS; // 1970以来 100ns
   // 避免溢出:100ns -> us
   unsigned long long us = t100 / 10ULL;
   return std::chrono::system_clock::time_point(std::chrono::microseconds(us));
}
// 从 CDateTimeCtrl 取本地时间并转为 UTC time_point
// 返回 false 表示控件是“无值”(DTS_SHOWNONE / GDT_NONE) 或转换失败
bool CToolUnits::GetCtrlTimeUtc(const CDateTimeCtrl& ctrl,
   std::chrono::system_clock::time_point& outUtc)
{
   SYSTEMTIME stLocal{};
   DWORD rc = const_cast<CDateTimeCtrl&>(ctrl).GetTime(&stLocal); // MFC 原型需要非const
   if (rc != GDT_VALID) return false; // GDT_NONE
   SYSTEMTIME stUtc{};
   if (!TzSpecificLocalTimeToSystemTime(nullptr, &stLocal, &stUtc)) return false;
   FILETIME ftUtc{};
   if (!SystemTimeToFileTime(&stUtc, &ftUtc)) return false;
   outUtc = FileTimeToTimePointUTC(ftUtc);
   return true;
}
// 若你的日期控件只显示“日期不显示时间”,想把 From 调整到 00:00:00 / To 调整到 23:59:59.999:
bool CToolUnits::GetCtrlDateRangeUtc_StartOfDay(const CDateTimeCtrl& ctrl,
   std::chrono::system_clock::time_point& outUtc)
{
   SYSTEMTIME st{};
   DWORD rc = const_cast<CDateTimeCtrl&>(ctrl).GetTime(&st);
   if (rc != GDT_VALID) return false;
   st.wHour = 0; st.wMinute = 0; st.wSecond = 0; st.wMilliseconds = 0;
   SYSTEMTIME stUtc{};
   if (!TzSpecificLocalTimeToSystemTime(nullptr, &st, &stUtc)) return false;
   FILETIME ftUtc{}; if (!SystemTimeToFileTime(&stUtc, &ftUtc)) return false;
   outUtc = FileTimeToTimePointUTC(ftUtc);
   return true;
}
bool CToolUnits::GetCtrlDateRangeUtc_EndOfDay(const CDateTimeCtrl& ctrl,
   std::chrono::system_clock::time_point& outUtc)
{
   SYSTEMTIME st{};
   DWORD rc = const_cast<CDateTimeCtrl&>(ctrl).GetTime(&st);
   if (rc != GDT_VALID) return false;
   st.wHour = 23; st.wMinute = 59; st.wSecond = 59; st.wMilliseconds = 999;
   SYSTEMTIME stUtc{};
   if (!TzSpecificLocalTimeToSystemTime(nullptr, &st, &stUtc)) return false;
   FILETIME ftUtc{}; if (!SystemTimeToFileTime(&stUtc, &ftUtc)) return false;
   outUtc = FileTimeToTimePointUTC(ftUtc);
   return true;
}
// ---------- 本地 SYSTEMTIME -> UTC time_point ----------
std::chrono::system_clock::time_point CToolUnits::LocalSTtoUtcTP(const SYSTEMTIME& stLocal) {
   SYSTEMTIME stUtc{};
   if (!TzSpecificLocalTimeToSystemTime(nullptr, &stLocal, &stUtc))
      throw std::runtime_error("TzSpecificLocalTimeToSystemTime failed");
   FILETIME ftUtc{};
   if (!SystemTimeToFileTime(&stUtc, &ftUtc))
      throw std::runtime_error("SystemTimeToFileTime failed");
   return FileTimeToTimePointUTC(ftUtc);
}
// 生成本地 SYSTEMTIME
SYSTEMTIME CToolUnits::MakeLocalST(int y, int m, int d, int hh, int mi, int ss, int ms) {
   SYSTEMTIME st{};
   st.wYear = (WORD)y; st.wMonth = (WORD)m; st.wDay = (WORD)d;
   st.wHour = (WORD)hh; st.wMinute = (WORD)mi; st.wSecond = (WORD)ss; st.wMilliseconds = (WORD)ms;
   return st;
}
// 闰年 / 月天数
bool CToolUnits::IsLeap(int y) {
   return ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0);
}
int CToolUnits::DaysInMonth(int y, int m) {
   static const int d[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
   return (m == 2) ? d[m] + (IsLeap(y) ? 1 : 0) : d[m];
}
// 本地“今天”的年月日
void CToolUnits::GetTodayYMD_Local(int& y, int& m, int& d) {
   SYSTEMTIME now{}; GetLocalTime(&now);
   y = now.wYear; m = now.wMonth; d = now.wDay;
}
// 本地日历上减 n 天(仍是本地 Y/M/D)
void CToolUnits::LocalCalendarMinusDays(int& y, int& m, int& d, int nDays) {
   std::tm t{};
   t.tm_year = y - 1900; t.tm_mon = m - 1; t.tm_mday = d;
   t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0;
   t.tm_mday -= nDays;
   (void)std::mktime(&t); // 按本地时区归一化
   y = t.tm_year + 1900; m = t.tm_mon + 1; d = t.tm_mday;
}
// ====== 核心:计算预设区间的 UTC [from, to] ======
// 语义:
//  - Today     : 本地“今天”00:00:00.000 ~ 今天 23:59:59.999
//  - Last7Days : 本地“6 天前”00:00:00.000 ~ 今天 23:59:59.999(共 7 个自然日,含今天)
//  - ThisMonth : 本地“当月 1 号”00:00:00.000 ~ 本月末 23:59:59.999
//  - ThisYear  : 本地“当年 1/1”00:00:00.000 ~ 当年末 23:59:59.999
std::pair<std::chrono::system_clock::time_point,
   std::chrono::system_clock::time_point>
   CToolUnits::CalcQuickRangeUtc(QuickRange r)
{
   int y, m, d;
   GetTodayYMD_Local(y, m, d);
   SYSTEMTIME stFromLocal{}, stToLocal{};
   switch (r) {
   case QuickRange::Today:
      stFromLocal = MakeLocalST(y, m, d, 0, 0, 0, 0);
      stToLocal = MakeLocalST(y, m, d, 23, 59, 59, 999);
      break;
   case QuickRange::Last7Days: {
      int y2 = y, m2 = m, d2 = d;
      LocalCalendarMinusDays(y2, m2, d2, 6);
      stFromLocal = MakeLocalST(y2, m2, d2, 0, 0, 0, 0);
      stToLocal = MakeLocalST(y, m, d, 23, 59, 59, 999);
      break;
   }
   case QuickRange::ThisMonth: {
      int lastDay = DaysInMonth(y, m);
      stFromLocal = MakeLocalST(y, m, 1, 0, 0, 0, 0);
      stToLocal = MakeLocalST(y, m, lastDay, 23, 59, 59, 999);
      break;
   }
   case QuickRange::ThisYear:
      stFromLocal = MakeLocalST(y, 1, 1, 0, 0, 0, 0);
      stToLocal = MakeLocalST(y, 12, DaysInMonth(y, 12), 23, 59, 59, 999);
      break;
   default:
      throw std::invalid_argument("CalcQuickRangeUtc: unsupported range");
   }
   auto fromUtc = LocalSTtoUtcTP(stFromLocal);
   auto toUtc = LocalSTtoUtcTP(stToLocal);
   return { fromUtc, toUtc };
}
// 小工具:ASCII 不区分大小写包含(中文等非 ASCII 不受影响,但也不需要大小写转换)
bool CToolUnits::containsCI(const std::string& hay, const std::string& needle) {
   if (needle.empty()) return true;
   auto toLower = [](std::string s) { std::transform(s.begin(), s.end(), s.begin(),
      [](unsigned char c) { return (char)std::tolower(c); }); return s; };
   std::string h = toLower(hay), n = toLower(needle);
   return h.find(n) != std::string::npos;
}
// ------- 本地时间 -------
std::string CToolUnits::TimePointToLocalString(const std::optional<TP>& tp,
   const char* fmt/* = "%Y-%m-%d %H:%M:%S"*/)
{
   if (!tp) return {};
   std::time_t t = std::chrono::system_clock::to_time_t(*tp);
   std::tm tm{};
#if defined(_WIN32)
   localtime_s(&tm, &t);
#else
   localtime_r(&t, &tm);
#endif
   char buf[64]{};
   std::strftime(buf, sizeof(buf), fmt, &tm);
   return buf;
}
// ------- UTC 时间 -------
std::string CToolUnits::TimePointToUtcString(const std::optional<TP>& tp,
   const char* fmt/* = "%Y-%m-%d %H:%M:%S"*/)
{
   if (!tp) return {};
   std::time_t t = std::chrono::system_clock::to_time_t(*tp);
   std::tm tm{};
#if defined(_WIN32)
   gmtime_s(&tm, &t);
#else
   gmtime_r(&t, &tm);
#endif
   char buf[64]{};
   std::strftime(buf, sizeof(buf), fmt, &tm);
   return buf;
}
std::string CToolUnits::TimePointToLocalStringMs(const std::optional<TP>& tp)
{
   if (!tp) return {};
   using namespace std::chrono;
   auto ms_since_epoch = duration_cast<milliseconds>(tp->time_since_epoch());
   auto ms = static_cast<int>(ms_since_epoch.count() % 1000);
   std::time_t t = system_clock::to_time_t(*tp);
   std::tm tm{};
#if defined(_WIN32)
   localtime_s(&tm, &t);
#else
   localtime_r(&t, &tm);
#endif
   char date[32]{};
   std::strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &tm);
   char out[40]{};
   std::snprintf(out, sizeof(out), "%s.%03d", date, ms);
   return out;
}
std::string CToolUnits::NowStrSec()
{
   using namespace std::chrono;
   auto now = system_clock::now();
   std::time_t t = system_clock::to_time_t(now);
   std::tm tm{};
#ifdef _WIN32
   localtime_s(&tm, &t);   // 本地时间(Windows 线程安全)
#else
   localtime_r(&t, &tm);   // 本地时间(POSIX 线程安全)
#endif
   std::ostringstream oss;
   oss << std::put_time(&tm, "%Y%m%d%H%M%S"); // 例:2025-09-15 08:23:07
   return oss.str();
}
std::wstring CToolUnits::AnsiToWString(const std::string& str)
{
   if (str.empty()) return std::wstring();
   int len = ::MultiByteToWideChar(CP_ACP, 0,
      str.c_str(), -1,
      nullptr, 0);
   if (len <= 0) return std::wstring();
   std::wstring ws;
   ws.resize(len - 1);
   ::MultiByteToWideChar(CP_ACP, 0,
      str.c_str(), -1,
      &ws[0], len);
   return ws;
}
std::string CToolUnits::WStringToAnsi(const std::wstring& wstr)
{
   if (wstr.empty()) return std::string();
   int len = ::WideCharToMultiByte(CP_ACP, 0,
      wstr.c_str(), -1,
      nullptr, 0,
      nullptr, nullptr);
   if (len <= 0) return std::string();
   std::string str;
   str.resize(len - 1);
   ::WideCharToMultiByte(CP_ACP, 0,
      wstr.c_str(), -1,
      &str[0], len,
      nullptr, nullptr);
   return str;
}