C++ 时间处理-日期时间类

1. 关键词

C++ 时间处理 日期时间类 跨平台

2. 问题

为什么C++就没有一个方便好用的表示日期时间的类?

同样是高级语言,Java中有Date,C#中有DateTime,Python中有datetime,为什么C++就没有一个方便好用的表示日期时间的类?我觉得这是C++ STL的遗憾,在这个点上做的是挺失败的。C++11之前,处理日期时间一般都会用C语言函数,如:localtime, gmtime, mktime, gettimeofday, put_time等。C++11之后,引入了chrono库,做到了时间处理的跨平台化和标准化,时间精度也支持到了纳秒级,但是chrono库的用法非常累赘,一点也不简洁,如:要以毫秒为单位获取当前时间戳,他的实现要写以下这么一长串的代码。

auto now = std::chrono::system_clock::now();
auto timestamp_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
auto ms = static_cast<uint64_t>(timestamp_ms);

那~ 有没有更简洁、漂亮的实现方式呢?

答案是:自己写一个!

3. 设计理念

  • 极简
  • 易用
  • 跨平台

4. 支持的能力

  • 获取当前时间
  • 获取UTC时间
  • 格式化时间
  • 从字符串解析时间
  • 时间差计算
  • 时间精度:毫秒级

5. 代码实现

5.1. datetime.h

#pragma once

#include <cstdint>
#include <string>
#include <iostream>
#include <regex>
#include <vector>
#include <utility>

namespace cutl
{
    /**
     * @brief the string datetime format for parsing and formatting
     *
     */
    enum class datetime_format
    {
        /** YYYY-MM-DD HH:MM:SS.sss */
        datetime_format_a,
        /** YYYY.MM.DD HH:MM:SS */
        datetime_format_b,
        /** YYYY/MM/DD HH:MM:SS */
        datetime_format_c,
        /** YYYYMMDD HH:MM:SS */
        datetime_format_d,
    };

    /**
     * @brief A simple, feature-rich modern C++ date-time class
     *
     */
    class datetime
    {
    public:
        /**
         * @brief Constants value: second, expressed in milliseconds.
         *
         */
        static constexpr int second = 1000;
        /**
         * @brief Constants value: min, expressed in milliseconds.
         *
         */
        static constexpr int min = 60 * second;
        /**
         * @brief Constants value: hour, expressed in milliseconds.
         *
         */
        static constexpr int hour = 60 * min;
        /**
         * @brief Constants value: day, expressed in milliseconds.
         *
         */
        static constexpr int day = 24 * hour;

    public:
        /**
         * @brief Construct a new datetime object
         *
         * @param ms a timestamp in milliseconds for initialize the datetime object
         */
        datetime(uint64_t ms);

        /**
         * @brief Construct a new datetime object
         *
         * @param other other datetime object to copy
         */
        datetime(const datetime &other);

        /**
         * @brief Destroy the datetime object
         *
         */
        ~datetime();

    private:
        datetime();

    public:
        /**
         * @brief Get a datetime object for the current system time
         *
         * @return datetime object for the current system time
         */
        static datetime now();

        /**
         * @brief Constructs a datetime object from a local time string.
         *
         * Only the following time formats are supported:
         * - YYYY-MM-DD HH:MM:SS.sss
         * - YYYY-MM-DD HH:MM:SS
         * - YYYY.MM.DD HH:MM:SS.sss
         * - YYYY.MM.DD HH:MM:SS
         * - YYYY/MM/DD HH:MM:SS.sss
         * - YYYY/MM/DD HH:MM:SS
         * - YYYYMMDD HH:MM:SS.sss
         * - YYYYMMDD HH:MM:SS
         * @param time_text local time string, use the below formats to construct a datetime object.
         * @param isdst the setting of daylight saving time, -1 means system automatically determine, 0 means not in daylight saving time, 1 means in daylight saving time
         * @return datetime object constructed from the local time string
         */
        static datetime get(const std::string &time_text, int isdst = -1);

    public:
        /**
         * @brief Get the timestamp in milliseconds
         *
         * @return the timestamp in milliseconds
         */
        uint64_t timestamp() const;
        /**
         * @brief format the datetime object to a string
         *
         * @param dfmt datetime format, a value of datetime_format enum, default is datetime_format_a
         * @param local whether to use local time, default is true. if true means output in local time, otherwise, output in UTC time.
         * @param show_milliseconds whether to show milliseconds, default is true. if true means show milliseconds, otherwise, not show milliseconds.
         * @return formatted datetime string described by std::string
         */
        std::string format(datetime_format dfmt = datetime_format::datetime_format_a, bool local = true, bool show_milliseconds = true) const;
        // fmt, usages like std::put_time

        /**
         * @brief Format the datetime object to a string with a custom format string
         *
         * @param fmt datetime format string, default is "%Y-%m-%d %H:%M:%S.%f". usages like std::put_time, reference to https://en.cppreference.com/w/cpp/io/manip/put_time
         * @param local whether to use local time, default is true. if true means output in local time, otherwise, output in UTC time.
         * @param show_milliseconds whether to show milliseconds, default is true. if true means show milliseconds, otherwise, not show milliseconds.
         * @return formatted datetime string described by std::string
         */
        std::string format(const std::string &fmt, bool local = true, bool show_milliseconds = true) const;

        /**
         * @brief Get the string of UTC time described by datetime object
         *
         * @return the string of UTC time in format "YYYY-MM-DD HH:MM:SS.sss"
         */
        std::string utctime() const
        {
            return format(datetime_format::datetime_format_a, false);
        }

        /**
         * @brief Define the assignment operator
         *
         * @param other other datetime object to copy
         * @return datetime& the reference of the current datetime object
         */
        datetime &operator=(const datetime &other);

        /**
         * @brief Define the addition operator
         *
         * @param ms milliseconds to add
         * @return datetime object after adding milliseconds
         */
        datetime operator+(uint64_t ms);

        /**
         * @brief Define the subtraction operator
         *
         * @param ms milliseconds to subtract
         * @return datetime object after subtracting milliseconds
         */
        datetime operator-(uint64_t ms);

        /**
         * @brief Define the addition and assignment operator
         *
         * @param ms milliseconds to add
         * @return datetime& the reference of the current datetime object after adding milliseconds
         */
        datetime &operator+=(uint64_t ms);

        /**
         * @brief Define the subtraction and assignment operator
         *
         * @param ms milliseconds to subtract
         * @return datetime& the reference of the current datetime object after subtracting milliseconds
         */
        datetime &operator-=(uint64_t ms);

        /**
         * @brief Define the subtraction operator between two datetime objects
         *
         * @param other datetime object to subtract
         * @return the duration in milliseconds between current and other datetime objects
         */
        int64_t operator-(const datetime &other) const;

    private:
        using time_regex_type = std::pair<std::string, std::regex>;
        using time_regex_vec_type = std::vector<time_regex_type>;
        static std::string supported_time_formats(const time_regex_vec_type &fmtlist);
        static bool verify_time(const struct tm &time);

    private:
        uint64_t timestamp_ms_;
    };

    /**
     * @brief Define the output stream operator for datetime object
     *
     * @param os the std::ostream object
     * @param dt the datetime object to be output
     * @return std::ostream& the reference of the std::ostream object after outputting the datetime object
     */
    std::ostream &operator<<(std::ostream &os, const datetime &dt);

} // namespace

5.2. timecount.cpp

#include "datetime.h"
#include "timeutil.h"
#include "strfmt.h"
#include "inner/logger.h"

namespace cutl
{
    datetime::datetime(const datetime &other)
    {
        timestamp_ms_ = other.timestamp_ms_;
    }

    datetime::datetime()
    {
        timestamp_ms_ = 0;
    }

    datetime::datetime(uint64_t ms) : timestamp_ms_(ms)
    {
    }

    datetime::~datetime()
    {
    }

    datetime datetime::now()
    {
        return datetime(cutl::timestamp(timeunit::ms));
    }

    datetime datetime::get(const std::string &time_text, int isdst)
    {
        std::smatch matchRes;
        bool result = false;
        static time_regex_vec_type fmt_list = {
            // 0/1, 2/3, 4/5, 6/7的顺序不能反,因为不含毫秒数的时间会被优先匹配到
            std::make_pair("YYYY-MM-DD HH:MM:SS.sss", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
            std::make_pair("YYYY-MM-DD HH:MM:SS", std::regex(R"((\d{4})-(\d{2})-(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
            std::make_pair("YYYY.MM.DD HH:MM:SS.sss", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
            std::make_pair("YYYY.MM.DD HH:MM:SS", std::regex(R"((\d{4}).(\d{2}).(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
            std::make_pair("YYYY/MM/DD HH:MM:SS.sss", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
            std::make_pair("YYYY/MM/DD HH:MM:SS", std::regex(R"((\d{4})/(\d{2})/(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
            std::make_pair("YYYYMMDD HH:MM:SS.sss", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}).(\d{3}))")),
            std::make_pair("YYYYMMDD HH:MM:SS", std::regex(R"((\d{4})(\d{2})(\d{2})[ ](\d{2}):(\d{2}):(\d{2}))")),
        };
        for (size_t i = 0; i < fmt_list.size(); i++)
        {
            auto &fmt_text = fmt_list[i].first;
            auto &fmt_pattern = fmt_list[i].second;
            result = std::regex_search(time_text, matchRes, fmt_pattern);
            if (result)
            {
                CUTL_DEBUG("matched regex: " + fmt_text);
                break;
            }
        }

        if (!result || matchRes.size() < 7)
        {
            auto time_fmts = supported_time_formats(fmt_list);
            CUTL_ERROR("Only the following time formats are supported:\n" + time_fmts);
            return datetime();
        }

        CUTL_DEBUG("matchRes size:" + std::to_string(matchRes.size()) + ", res:" + matchRes[0].str());
        // 解析毫秒值
        int ms = 0;
        if (matchRes.size() == 8)
        {
            ms = std::stoi(matchRes[7].str());
        }
        // 解析tm结构的时间
        struct tm time = {};
        if (matchRes.size() >= 7)
        {
            for (size_t i = 1; i < 7; i++)
            {
                time.tm_year = std::stoi(matchRes[1]);
                time.tm_mon = std::stoi(matchRes[2]);
                time.tm_mday = std::stoi(matchRes[3]);
                time.tm_hour = std::stoi(matchRes[4]);
                time.tm_min = std::stoi(matchRes[5]);
                time.tm_sec = std::stoi(matchRes[6]);
                time.tm_isdst = isdst;
            }
        }
        if (!verify_time(time))
        {
            return datetime();
        }

        // 转换为时间戳
        time.tm_year -= 1900;
        time.tm_mon -= 1;
        auto ret = mktime(&time);
        if (ret == -1)
        {
            CUTL_ERROR("mktime() failed");
            return datetime();
        }
        auto s = static_cast<uint64_t>(ret);
        return datetime(s2ms(s) + ms);
    }

    uint64_t datetime::timestamp() const
    {
        return timestamp_ms_;
    }

    std::string get_format_str(datetime_format fmt)
    {
        std::string text;
        switch (fmt)
        {
        case datetime_format::datetime_format_a: // YYYY-MM-DD HH:MM:SS
            text = "%Y-%m-%d %H:%M:%S";
            break;
        case datetime_format::datetime_format_b: // YYYY.MM.DD HH:MM:SS
            text = "%Y.%m.%d %H:%M:%S";
            break;
        case datetime_format::datetime_format_c: // YYYY/MM/DD HH:MM:SS
            text = "%Y/%m/%d %H:%M:%S";
            break;
        case datetime_format::datetime_format_d: // YYYYMMDD HH:MM:SS
            text = "%Y%m%d %H:%M:%S";
            break;
        default:
            break;
        }

        return text;
    }

    std::string datetime::format(datetime_format fmt, bool local, bool show_milliseconds) const
    {
        auto fmtstr = get_format_str(fmt);
        auto s = timestamp_ms_ / 1000;
        auto ms = timestamp_ms_ % 1000;
        auto text = fmt_timestamp(s, local, fmtstr);
        if (show_milliseconds)
        {
            text += "." + fmt_uint(ms, 3);
        }
        return text;
    }

    std::string datetime::format(const std::string &fmt, bool local, bool show_milliseconds) const
    {
        auto s = timestamp_ms_ / 1000;
        auto ms = timestamp_ms_ % 1000;
        auto text = fmt_timestamp(s, local, fmt);
        if (show_milliseconds)
        {
            text += "." + fmt_uint(ms, 3);
        }
        return text;
    }

    datetime &datetime::operator=(const datetime &other)
    {
        if (this == &other)
        {
            return *this;
        }

        timestamp_ms_ = other.timestamp_ms_;
        return *this;
    }

    datetime datetime::operator+(uint64_t ms)
    {
        datetime dt(*this);
        dt.timestamp_ms_ += ms;
        return dt;
    }

    datetime datetime::operator-(uint64_t ms)
    {
        datetime dt(*this);
        dt.timestamp_ms_ -= ms;
        return dt;
    }

    datetime &datetime::operator+=(uint64_t ms)
    {
        timestamp_ms_ += ms;
        return *this;
    }

    datetime &datetime::operator-=(uint64_t ms)
    {
        timestamp_ms_ -= ms;
        return *this;
    }

    int64_t datetime::operator-(const datetime &other) const
    {
        int64_t diff = timestamp_ms_ - other.timestamp_ms_;
        return diff;
    }

    std::string datetime::supported_time_formats(const time_regex_vec_type &fmtlist)
    {
        std::string time_fmts;
        for (size_t i = 0; i < fmtlist.size(); i++)
        {
            time_fmts += fmtlist[i].first + "\n";
        }
        return time_fmts;
    }

    bool datetime::verify_time(const struct tm &time)
    {
        // 校验年
        if (time.tm_year < 1900)
        {
            CUTL_ERROR("the year should be >= 1900");
            return false;
        }
        // 校验月
        if (time.tm_mon < 1 || time.tm_mon > 12)
        {
            CUTL_ERROR("the month should be between 1 and 12");
            return false;
        }
        // 校验日
        std::vector<int> large_month = {1, 3, 5, 7, 8, 10, 12};
        if (std::find(large_month.begin(), large_month.end(), time.tm_mon) != large_month.end() && (time.tm_mday < 1 || time.tm_mday > 31))
        {
            CUTL_ERROR("the day should be between 1 and 31 for " + std::to_string(time.tm_mon) + " month");
            return false;
        }
        std::vector<int> small_month = {4, 6, 9, 11};
        if (std::find(small_month.begin(), small_month.end(), time.tm_mon) != small_month.end() && (time.tm_mday < 1 || time.tm_mday > 30))
        {
            CUTL_ERROR("the day should be between 1 and 30 for " + std::to_string(time.tm_mon) + " month");
            return false;
        }
        if (time.tm_mon == 2)
        {
            auto is_leap_year = [](int year)
            { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); };
            if (is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 29))
            {
                CUTL_ERROR("the day should be between 1 and 29 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));
                return false;
            }
            if (!is_leap_year(time.tm_year) && (time.tm_mday < 1 || time.tm_mday > 28))
            {
                CUTL_ERROR("the day should be between 1 and 28 for " + std::to_string(time.tm_year) + "-" + fmt_uint(time.tm_mon, 2));
                return false;
            }
        }

        // 校验时分秒
        if (time.tm_hour < 0 || time.tm_hour > 23)
        {
            CUTL_ERROR("the hour should be between 0 and 23");
            return false;
        }
        if (time.tm_min < 0 || time.tm_min > 59)
        {
            CUTL_ERROR("the minute should be between 0 and 59");
            return false;
        }
        if (time.tm_sec < 0 || time.tm_sec > 59)
        {
            CUTL_ERROR("the second should be between 0 and 59");
            return false;
        }

        return true;
    }

    std::ostream &operator<<(std::ostream &os, const datetime &dt)
    {
        os << dt.format();
        return os;
    }

} // namespace

6. 测试代码

#pragma once

#include <iostream>
#include "datetime.h"
#include "common.hpp"

void TestDatetimeBasicUsage()
{
    PrintSubTitle("TestDatetimeBasicUsage");

    auto now = cutl::datetime::now();
    std::cout << "current timestamp(ms): " << now.timestamp() << std::endl;
    std::cout << "current time(UTC time): " << now.utctime() << std::endl;
    std::cout << "current time(local time): " << now.format() << std::endl;
    std::cout << "current time(UTC time) format b: " << now.format(cutl::datetime_format::datetime_format_b, false, true) << std::endl;
    std::cout << "current time(UTC time) format b, don't show milliseconds: " << now.format(cutl::datetime_format::datetime_format_b, false, false) << std::endl;
    std::cout << "current time(UTC time) format c: " << now.format(cutl::datetime_format::datetime_format_c, false, true) << std::endl;
    std::cout << "current time(UTC time) format d: " << now.format(cutl::datetime_format::datetime_format_d, false, true) << std::endl;
    std::cout << "current time(UTC time) custom format 1: " << now.format("%c %Z", false, true) << std::endl;
    std::cout << "current time(UTC time) custom format 2: " << now.format("%m/%d/%Y/ %H:%M:%S", false, false) << std::endl;
}

void TestDatetimeOperator()
{
    // 运算符重载
    PrintSubTitle("TestDatetimeOperator");

    std::cout << "one day == " << cutl::datetime::day << "ms" << std::endl;
    std::cout << "one hour == " << cutl::datetime::hour << "ms" << std::endl;
    std::cout << "one minute == " << cutl::datetime::min << "ms" << std::endl;

    auto now = cutl::datetime::now();
    std::cout << "current time: " << now << std::endl;
    auto dt1 = now - cutl::datetime::min;
    std::cout << "before one minute: " << dt1 << std::endl;
    // std::cout << "current time 1: " << now << std::endl;
    auto dt2 = now + cutl::datetime::min;
    std::cout << "after one minute: " << dt2 << std::endl;
    // std::cout << "current time 2: " << now << std::endl;

    now -= (2 * cutl::datetime::hour);
    std::cout << "before two hours: " << now << std::endl;
    now += (4 * cutl::datetime::hour);
    std::cout << "after two hours: " << now << std::endl;

    auto dt3 = cutl::datetime::get("2024-03-01 10:00:00");
    auto dt4 = cutl::datetime::get("2024-03-30 14:18:44");
    auto duration1 = dt4 - dt3;
    std::cout << "the difference between " << dt3 << " and " << dt4 << " is: " << duration1 << "ms, formatted: " << cutl::fmt_timeduration_ms(duration1) << std::endl;
    auto duration2 = dt3 - dt4;
    std::cout << "the difference between " << dt4 << " and " << dt3 << " is: " << duration2 << "ms" << std::endl;
}

void TestDatetimeParseString()
{
    // 字符串解析成时间
    PrintSubTitle("TestDatetimeParseString");
    auto dt0 = cutl::datetime::get(" 2024-03-02 14:18:44 ");
    std::cout << "dt0: " << dt0 << std::endl;
    auto dt1 = cutl::datetime::get(" 2024-03-02 14:18:44.023 ");
    std::cout << "dt1: " << dt1 << std::endl;
    auto dt2 = cutl::datetime::get(" 2024.03.12 14:18:44");
    std::cout << "dt2: " << dt2 << std::endl;
    auto dt3 = cutl::datetime::get(" 2024.03.12 14:18:44.003");
    std::cout << "dt3: " << dt3 << std::endl;
    auto dt4 = cutl::datetime::get("2024/03/22 14:18:44 ");
    std::cout << "dt4: " << dt4 << std::endl;
    auto dt5 = cutl::datetime::get("2024/03/22 14:18:44.200 ");
    std::cout << "dt5: " << dt5 << std::endl;
    auto dt6 = cutl::datetime::get("2024/03/23 09:28:04");
    std::cout << "dt6: " << dt6 << std::endl;
    auto dt7 = cutl::datetime::get("2024/03/23 09:28:04.276");
    std::cout << "dt7: " << dt7 << std::endl;
    // format error
    auto dt8 = cutl::datetime::get(" 2024-0322 14:18:44 ");
    std::cout << "dt8: " << dt8 << std::endl;
    // mounth error
    auto dt9 = cutl::datetime::get(" 2024-13-02 14:18:44 ");
    std::cout << "dt9: " << dt9 << std::endl;
    // leap year error
    auto dt10 = cutl::datetime::get(" 2023-02-29 14:18:44 ");
    std::cout << "dt10: " << dt10 << std::endl;
    // day error
    auto dt11 = cutl::datetime::get(" 2024-03-42 14:18:44 ");
    std::cout << "dt11: " << dt11 << std::endl;

    // year > 2038
    auto dt12 = cutl::datetime::get(" 2044-03-02 14:18:44 ");
    std::cout << "dt12: " << dt12 << std::endl;
    std::cout << "dt12 timestamp: " << dt12.timestamp() << std::endl;
}

void TestDatetime()
{
    PrintTitle("datetime");

    TestDatetimeBasicUsage();
    TestDatetimeOperator();
    TestDatetimeParseString();
}

7. 运行结果

==============================================datetime==============================================
---------------------------------------TestDatetimeBasicUsage---------------------------------------
current timestamp(ms): 1716129275853
current time(UTC time): 2024-05-19 14:34:35.853
current time(local time): 2024-05-19 22:34:35.853
current time(UTC time) format b: 2024.05.19 14:34:35.853
current time(UTC time) format b, don't show milliseconds: 2024.05.19 14:34:35
current time(UTC time) format c: 2024/05/19 14:34:35.853
current time(UTC time) format d: 20240519 14:34:35.853
current time(UTC time) custom format 1: Sun May 19 14:34:35 2024 UTC.853
current time(UTC time) custom format 2: 05/19/2024/ 14:34:35
----------------------------------------TestDatetimeOperator----------------------------------------
one day == 86400000ms
one hour == 3600000ms
one minute == 60000ms
current time: 2024-05-19 22:34:35.854
before one minute: 2024-05-19 22:33:35.854
after one minute: 2024-05-19 22:35:35.854
before two hours: 2024-05-19 20:34:35.854
after two hours: 2024-05-20 00:34:35.854
the difference between 2024-03-01 10:00:00.000 and 2024-03-30 14:18:44.000 is: 2521124000ms, formatted: 29d:04h:18m:44s.000ms
the difference between 2024-03-30 14:18:44.000 and 2024-03-01 10:00:00.000 is: -2521124000ms
--------------------------------------TestDatetimeParseString---------------------------------------
dt0: 2024-03-02 14:18:44.000
dt1: 2024-03-02 14:18:44.023
dt2: 2024-03-12 14:18:44.000
dt3: 2024-03-12 14:18:44.003
dt4: 2024-03-22 14:18:44.000
dt5: 2024-03-22 14:18:44.200
dt6: 2024-03-23 09:28:04.000
dt7: 2024-03-23 09:28:04.276
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:79:get] Only the following time formats are supported:
YYYY-MM-DD HH:MM:SS.sss
YYYY-MM-DD HH:MM:SS
YYYY.MM.DD HH:MM:SS.sss
YYYY.MM.DD HH:MM:SS
YYYY/MM/DD HH:MM:SS.sss
YYYY/MM/DD HH:MM:SS
YYYYMMDD HH:MM:SS.sss
YYYYMMDD HH:MM:SS

dt8: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:241:verify_time] the month should be between 1 and 12
dt9: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.857][E]]0x7ff844a9b100](cutl) [datetime.cpp:268:verify_time] the day should be between 1 and 28 for 2023-02
dt10: 1970-01-01 08:00:00.000
[2024-05-19 22:34:35.858][E]]0x7ff844a9b100](cutl) [datetime.cpp:248:verify_time] the day should be between 1 and 31 for 3 month
dt11: 1970-01-01 08:00:00.000
dt12: 2044-03-02 14:18:44.000
dt12 timestamp: 2340512324000

8. 源码地址

更多详细代码,请查看本人写的C++ 通用工具库: common_util, 本项目已开源,代码简洁,且有详细的文档和Demo。

  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陌尘(MoChen)

爱打赏的人技术成长更开哦~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值