diff --git a/.clwb/.blaze/modules/.workspace.iml b/.clwb/.blaze/modules/.workspace.iml index 74dcfe7..0d91316 100644 --- a/.clwb/.blaze/modules/.workspace.iml +++ b/.clwb/.blaze/modules/.workspace.iml @@ -9,6 +9,11 @@ + + + + + diff --git a/BUILD.bazel b/BUILD.bazel index f7ef562..81a7ad4 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -10,31 +10,34 @@ cc_library( srcs = [], hdrs = [], copts = ["-I./src"], + linkopts = [ + "-pthread", + "-ldl", + ], deps = [ - "//src/logger:logger", - "//src/logger:Logging", - "//src/Base64:base64", - "//src/BmpTool:BmpTool", - "//src/C_VECTOR:c_vector", - "//src/CGI:CGI", - "//src/ConfigTool:ConfigTool", - "//src/fastjson:fastjson", - "//src/JSON:CJsonObject", - "//src/json11:json11", - "//src/littlefs:littlefs", - # "//src/kHttpd:kHttpd", - "//src/nlohmann:nlohmann_json", - "//src/Pipe:Pipe", - "//src/easyloggingpp:easyloggingpp", - "//src/SHA1:SHA1", - # "//src/socket:socket", - "//src/thread_pool:thread_pool", - "//src/xml:tinyxml2", - "//src/UTF8Url:UTF8Url", - # "//src/http:http", - "//src/net_tool:net_tool", - "//src/yaml-cpp:yaml-cpp", - ], - linkopts = ["-pthread","-ldl"], + "//src/logger", + "//src/logger:Logging", + "//src/Base64:base64", + "//src/BmpTool", + "//src/C_VECTOR:c_vector", + "//src/CGI", + "//src/ConfigTool", + "//src/fastjson", + "//src/JSON:CJsonObject", + "//src/json11", + "//src/littlefs", + # "//src/kHttpd:kHttpd", + "//src/nlohmann:nlohmann_json", + "//src/Pipe", + "//src/easyloggingpp", + "//src/SHA1", + "//src/date", + # "//src/socket:socket", + "//src/thread_pool", + "//src/xml:tinyxml2", + "//src/UTF8Url", + # "//src/http:http", + "//src/net_tool", + "//src/yaml-cpp", + ], ) - diff --git a/Example/BUILD.bazel b/Example/BUILD.bazel index c360171..3b3fe19 100644 --- a/Example/BUILD.bazel +++ b/Example/BUILD.bazel @@ -10,3 +10,13 @@ cc_binary( "//:Tools", ], ) + +cc_binary( + name = "testDate", + srcs = ["testDate.cpp"], + copts = [ + ], + deps = [ + "//:Tools", + ], +) diff --git a/Example/testDate.cpp b/Example/testDate.cpp new file mode 100644 index 0000000..1cd0cc8 --- /dev/null +++ b/Example/testDate.cpp @@ -0,0 +1,32 @@ +// +// Created by caesar kekxv on 2024/6/14. +// +#include +#include +#include + +int main(int argc, const char *argv[]) { + const auto date1 = clangTools::date::parse(1718372061); + std::cout << __LINE__ << ":" << date1->format() << std::endl; + const auto date2 = clangTools::date::parseMicroseconds(1718372061000); + std::cout << __LINE__ << ":" << date2->format() << std::endl; + const auto date3 = clangTools::date::parse(2024, 06 - 1, 14); + std::cout << __LINE__ << ":" << date3->format() << std::endl; + const auto date4 = clangTools::date::parse(2024, 06 - 1, 32, 8, 59); + std::cout << " " << date4->format("yyyy-MM-dd HH:mm:ss"); + std::cout << "\t" << "yyyy-MM-dd HH:mm:ss" << std::endl; + std::cout << " " << *date4; + std::cout << "\t" << "yyyy-MM-dd HH:mm:ss" << std::endl; + std::cout << " " << date4->format("yyyy+1-MM-1-dd HH:mm:ss"); + std::cout << "\t" << "yyyy+1-MM-1-dd HH:mm:ss" << std::endl; + std::cout << " " << date4->format("yyyy--06-dd HH:mm:ss"); + std::cout << "\t" << "yyyy--06-dd HH:mm:ss" << std::endl; + std::cout << " " << date4->clone("yyyy-1-MM+1-dd HH:mm:ss")->format("yyyy-MM-dd HH:mm:ss"); + std::cout << "\t" << "yyyy-1-MM+1-dd HH:mm:ss" << "_" << "yyyy-MM-dd HH:mm:ss" << std::endl; + std::cout << " " << date4->format("yyyy--07--02 HH:mm:ss"); + std::cout << "\t" << "yyyy--07--02 HH:mm:ss" << std::endl; + std::cout << "\t" << date1 << std::endl; + std::cout << "\t" << date2 << std::endl; + std::cout << "\t" << (date1 == date2) << std::endl; + return 0; +} diff --git a/src/date/BUILD.bazel b/src/date/BUILD.bazel new file mode 100644 index 0000000..0ad97ed --- /dev/null +++ b/src/date/BUILD.bazel @@ -0,0 +1,11 @@ +cc_library( + name = "date", + srcs = [ + "date.cpp", + ], + hdrs = [ + "date.hpp", + ], + includes = ["."], + visibility = ["//visibility:public"], +) diff --git a/src/date/date.cpp b/src/date/date.cpp new file mode 100644 index 0000000..b36bf94 --- /dev/null +++ b/src/date/date.cpp @@ -0,0 +1,216 @@ +// +// Created by caesar kekxv on 2024/6/14. +// + +#include "date.hpp" + +#include +#include +#include +#include +using namespace clangTools; + +std::shared_ptr date::now() { + return std::make_shared(); +} + +std::shared_ptr date::parse(const int year, const int monthIndex, const int day, const int hours, const int minutes, const int seconds, const int milliseconds) { + struct tm time{}; + time.tm_year = year - 1900; + time.tm_mon = monthIndex; + time.tm_mday = day; + time.tm_hour = hours; + time.tm_min = minutes; + time.tm_sec = seconds; + calc_tm(&time); + auto date_ = parse(std::mktime(&time)); + date_->m_time_point = date_->m_time_point + std::chrono::milliseconds(milliseconds); + return date_; +} + +date::~date() = default; + +/** + * 重置时间点 + */ +void date::reset() { + m_time_point = system_clk::now(); +} + +/** + * 解析时间 + * @param src 时间 + * @param format_string 时间格式 + * @return 是否解析成功 + */ +std::shared_ptr date::parse(const std::string &src, const char *format_string) { + std::stringstream ss{src}; + std::tm dt{}; + ss >> std::get_time(&dt, replace_format(format_string).c_str()); + const time_t c_time_t = std::mktime(&dt); + return parse(c_time_t); +} + +/** + * 解析时间戳,只支持秒 + * @param time_ 时间戳 + * @return 是否解析成功 + */ +std::shared_ptr date::parse(const std::time_t &time_) { + auto date_ = now(); + date_->m_time_point = system_clk::from_time_t(time_); + return date_; +} + +/** + * 解析时间戳,只支持毫秒 + * @param time_ 时间戳 + * @return 是否解析成功 + */ +std::shared_ptr date::parseMicroseconds(const std::time_t &time_) { + return parse(time_ / 1000); +} + +std::shared_ptr date::clone(const char *format_string) const { + const auto t = format(format_string); + auto format_string_ = std::regex_replace(format_string, std::regex{"--"}, "||"); + format_string_ = std::regex_replace(format_string_, std::regex{"[+-]\\d+"}, ""); + format_string_ = std::regex_replace(format_string_, std::regex{"||"}, "-"); + return parse(t, format_string_.c_str()); +} + +/** + * 时间 + * @param format_string 解析格式 + * @return 格式化的时间 + */ +std::string date::format(const char *format_string) const { + auto format_string_ = replace_format(format_string); + format_string_ = std::regex_replace(format_string_, std::regex{"--"}, "||"); + const std::regex reg("([YyMdHlmS])([-+]\\d+)"); + std::smatch m; + auto pos = format_string_.cbegin(); + const std::time_t c_time_t = system_clk::to_time_t(m_time_point); + const auto t_ = std::localtime(&c_time_t); + struct tm t{}; + memcpy(&t, t_, sizeof(struct tm)); + for (const auto end = format_string_.cend(); std::regex_search(pos, end, m, reg); pos = m.suffix().first) { + const int offset = static_cast(strtol(m.str(2).c_str(), nullptr, 10)); + switch (m.str(1)[0]) { + case 'Y': + case 'y': + t.tm_year += offset; + break; + case 'm': + t.tm_mon += offset; + break; + case 'd': + t.tm_mday += offset; + break; + case 'l': + case 'H': + t.tm_hour += offset; + break; + case 'M': + t.tm_min += offset; + break; + case 'S': + t.tm_sec += offset; + break; + default: + break; + } + } + calc_tm(&t); + format_string_ = std::regex_replace(format_string_, std::regex{"[+-]\\d+"}, ""); + format_string_ = std::regex_replace(format_string_, std::regex{"||"}, "-"); + char mbstr[100]{}; + const size_t size = std::strftime(mbstr, sizeof(mbstr), format_string_.c_str(), &t); + std::string result{}; + if (size) { + result.insert(result.end(), mbstr, mbstr + size); + } + return result; +} + +std::string date::to_string(const char *format_string) const { + return format(format_string); +} + +int date::calc_max_day(const int year, const int mon) { + int max_day = 31; + switch (mon + 1) { + case 2: + if (year % 100 == 0) { + max_day = year % 400 == 0 ? 29 : 28; + } else { + max_day = year % 4 == 0 ? 29 : 28; + } + break; + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + max_day = 31; + break; + case 4: + case 6: + case 9: + case 11: + default: + max_day = 30; + break; + } + return max_day; +} + +void date::calc_tm(struct tm *tm_) { + if (tm_->tm_sec < 0) { tm_->tm_sec = 0; } else if (tm_->tm_sec >= 60) { + tm_->tm_sec = tm_->tm_sec - 60; + tm_->tm_min = tm_->tm_min + 1; + } + if (tm_->tm_min < 0) { tm_->tm_min = 0; } else if (tm_->tm_min >= 60) { + tm_->tm_min = tm_->tm_min - 60; + tm_->tm_hour = tm_->tm_hour + 1; + } + if (tm_->tm_hour < 0) { tm_->tm_hour = 0; } else if (tm_->tm_hour >= 24) { + tm_->tm_hour = tm_->tm_hour - 24; + tm_->tm_mday = tm_->tm_mday + 1; + } + do { + const auto max_day = calc_max_day(tm_->tm_year + 1900, tm_->tm_mon); + if (tm_->tm_mday < 1) { tm_->tm_mday = 1; } else if (tm_->tm_mday > max_day) { + tm_->tm_mday = tm_->tm_mday - max_day; + tm_->tm_mon = tm_->tm_mon + 1; + } + if (tm_->tm_mon < 0) { tm_->tm_mon = 0; } else if (tm_->tm_mon >= 12) { + tm_->tm_mon = tm_->tm_mon - 12; + tm_->tm_year = tm_->tm_year + 1; + const auto max_day_now = calc_max_day(tm_->tm_year, tm_->tm_mon); + if (max_day_now != max_day)continue; + } + break; + } while (true); +} + +std::string date::replace_format(const char *format_string) { + auto s = std::regex_replace(format_string, std::regex{"([dHSaAwWzZ])+"}, "%$1"); + if (std::regex_search(s, std::regex{"y{3,}", std::regex::icase})) { + s = std::regex_replace(s, std::regex{"[Yy]+"}, "%Y"); + } else { + s = std::regex_replace(s, std::regex{"[Yy]+"}, "%y"); + } + // 过度变量字符 + s = std::regex_replace(s, std::regex{"m+"}, "、、"); + s = std::regex_replace(s, std::regex{"M+"}, "%m"); + s = std::regex_replace(s, std::regex{"、、"}, "%M"); + s = std::regex_replace(s, std::regex{"h+"}, "%l"); + s = std::regex_replace(s, std::regex{"s+"}, "%S"); + return s; +} + +date::date(): m_time_point(system_clk::now()) { +} diff --git a/src/date/date.hpp b/src/date/date.hpp new file mode 100644 index 0000000..9cd2bdd --- /dev/null +++ b/src/date/date.hpp @@ -0,0 +1,154 @@ +// +// Created by caesar kekxv on 2024/6/14. +// + +#ifndef CLANGTOOLS_DATE_HPP +#define CLANGTOOLS_DATE_HPP +#include +#include +#include + +namespace clangTools { + class date { + // 重命名system_clock名称空间 + using system_clk = std::chrono::system_clock; + // 重命名time_point类型 + using _time_point = std::chrono::time_point; + + public: + static std::shared_ptr now(); + + /** + * 创建时间对象 + * @param year 年 + * @param monthIndex 月:0-11 + * @param day 天 + * @param hours 小时 + * @param minutes 分钟 + * @param seconds 秒 + * @param milliseconds 毫秒 + * @return 时间 + */ + static std::shared_ptr parse(int year, int monthIndex, int day = 1, int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0); + + /** + * 解析时间 + * @param src 时间 + * @param format_string 时间格式 + * @return 是否解析成功 + */ + static std::shared_ptr parse(const std::string &src, const char *format_string = "yyyy-MM-dd HH:mm:ss"); + + /** + * 解析时间戳,只支持秒 + * @param time_ 时间戳 + * @return 是否解析成功 + */ + static std::shared_ptr parse(const std::time_t &time_); + + /** + * 解析时间戳,只支持毫秒 + * @param time_ 时间戳 + * @return 是否解析成功 + */ + static std::shared_ptr parseMicroseconds(const std::time_t &time_); + + ~date(); + + explicit date(); + + /** + * 重置时间点 + */ + void reset(); + + + /** + * 时间 + * @param format_string 解析格式 + * @return 格式化的时间 + */ + std::string format(const char *format_string = "yyyy-MM-dd HH:mm:ss") const; + + /** + * 转字符串 + * @param format_string 格式 + * @return 字符串 + */ + std::string to_string(const char *format_string = "yyyy-MM-dd HH:mm:ss") const; + + /** + * 克隆一个对象 + * @param format_string 格式,支持 "yyyy+1-MM-1-dd HH:mm:ss" 如果是 "yyyy-01-01 HH:mm:ss",需要改为 "yyyy--01--01 HH:mm:ss",否则解析错误 + * @return 新的对象 + */ + std::shared_ptr clone(const char *format_string = "yyyy-MM-dd HH:mm:ss") const; + + public: + date &operator=(const date &date_) = default; + + date &operator=(const std::shared_ptr &date_) { + m_time_point = date_->m_time_point; + return (*this); + } + + friend std::ostream &operator<<(std::ostream &output, const date &date_) { + output << date_.to_string(); + return output; + } + + friend std::ostream &operator<<(std::ostream &output, const std::shared_ptr &date_) { + output << date_->to_string(); + return output; + } + + friend std::istream &operator>>(std::istream &input, date &date_) { + std::string str; + input >> str; + date_ = date::parse(str); + return input; + } + + friend bool operator>(const date &d1, const date &d2) { return d1.m_time_point > d2.m_time_point; } + friend bool operator>(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 > *d2; } + friend bool operator>(const date &d1, const std::shared_ptr &d2) { return d1 > *d2; } + friend bool operator>(const std::shared_ptr &d1, const date &d2) { return *d1 > d2; } + + friend bool operator>=(const date &d1, const date &d2) { return d1.m_time_point >= d2.m_time_point; } + friend bool operator>=(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 >= *d2; } + friend bool operator>=(const date &d1, const std::shared_ptr &d2) { return d1 >= *d2; } + friend bool operator>=(const std::shared_ptr &d1, const date &d2) { return *d1 >= d2; } + + friend bool operator<(const date &d1, const date &d2) { return d1.m_time_point < d2.m_time_point; } + friend bool operator<(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 < *d2; } + friend bool operator<(const date &d1, const std::shared_ptr &d2) { return d1 < *d2; } + friend bool operator<(const std::shared_ptr &d1, const date &d2) { return *d1 < d2; } + + friend bool operator<=(const date &d1, const date &d2) { return d1.m_time_point <= d2.m_time_point; } + friend bool operator<=(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 <= *d2; } + friend bool operator<=(const date &d1, const std::shared_ptr &d2) { return d1 <= *d2; } + friend bool operator<=(const std::shared_ptr &d1, const date &d2) { return *d1 <= d2; } + + friend bool operator==(const date &d1, const date &d2) { return d1.m_time_point == d2.m_time_point; } + friend bool operator==(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 == *d2; } + friend bool operator==(const date &d1, const std::shared_ptr &d2) { return d1 == *d2; } + friend bool operator==(const std::shared_ptr &d1, const date &d2) { return *d1 == d2; } + + friend bool operator!=(const date &d1, const date &d2) { return d1.m_time_point != d2.m_time_point; } + friend bool operator!=(const std::shared_ptr &d1, const std::shared_ptr &d2) { return *d1 != *d2; } + friend bool operator!=(const date &d1, const std::shared_ptr &d2) { return d1 != *d2; } + friend bool operator!=(const std::shared_ptr &d1, const date &d2) { return *d1 != d2; } + + private: + static int calc_max_day(int year, int mon); + + static void calc_tm(struct tm *tm_); + + static std::string replace_format(const char *format_string = "yyyy-MM-dd HH:mm:ss"); + + private: + _time_point m_time_point; + }; +} + +#endif //CLANGTOOLS_DATE_HPP