从.NET Framework之中摘要的 DateTime(日期时间)移植到 C/C++(Linux)

本文深入解析了DateTime类的内部实现,包括日期和时间的构造、属性访问、日期操作、比较和格式化等方法。同时,提供了如何获取当前时间和UTC时间,以及如何解析和格式化日期时间字符串的实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DateTime.h 

#pragma once

#include <string>

#ifndef NULL
#define NULL 0
#endif

//
/*
 * 时间计量单位为:千万分之一秒,即一个周期100纳秒时。
 */
enum DayOfWeek
{
    DayOfWeek_Sunday,
    DayOfWeek_Monday,
    DayOfWeek_Tuesday,
    DayOfWeek_Wednesday,
    DayOfWeek_Thursday,
    DayOfWeek_Friday,
    DayOfWeek_Saturday
};

struct DateTime
{
private:
    long long               m_ticks;

public:
    DateTime()
    {
        m_ticks = 0;
    }
    DateTime(long long ticks)
    {
        m_ticks = ticks;
    };
    DateTime(int year, int month, int day = 0, int hour = 0, int minutes = 0, int seconds = 0, int millisecond = 0)
    {
        this->m_ticks = 0;
        DateTime& dateTime = *this;
        dateTime = dateTime.AddYears(year - 1);
        dateTime = dateTime.AddMonths(month - 1);
        dateTime = dateTime.AddDays(day - 1);
        dateTime = dateTime.AddHours(hour);
        dateTime = dateTime.AddMinutes(minutes);
        dateTime = dateTime.AddSeconds(seconds);
        dateTime = dateTime.AddMilliseconds(millisecond);
    }

public:
    inline long long        Ticks() {
        return m_ticks & 0x3FFFFFFFFFFFFFFF;
    }
    inline int              Millisecond() {
        return (int)(Ticks() / 10000 % 1000);
    }
    inline int              Second() {
        return (int)(Ticks() / 10000000 % 60);
    }
    inline int              Minute() {
        return (int)(Ticks() / 600000000 % 60);
    }
    inline int              Hour() {
        return (int)(Ticks() / 36000000000LL % 24);
    }
    inline int              Microseconds()
    {
        return (int)(Ticks() / 10LL % 1000);
    }

private:
    static int*             DaysToMonth366()
    {
        static int buf[] = {
            0,
            31,
            60,
            91,
            121,
            152,
            182,
            213,
            244,
            274,
            305,
            335,
            366
        };
        return buf;
    }
    static int*             DaysToMonth365()
    {
        static int buf[] = {
            0,
            31,
            59,
            90,
            120,
            151,
            181,
            212,
            243,
            273,
            304,
            334,
            365
        };
        return buf;
    }
    inline int              GetDatePart(int part)
    {
        long long internalTicks = Ticks();
        int num = (int)(internalTicks / 864000000000LL);
        int num2 = num / 146097;
        num -= num2 * 146097;
        int num3 = num / 36524;
        if (num3 == 4)
        {
            num3 = 3;
        }
        num -= num3 * 36524;
        int num4 = num / 1461;
        num -= num4 * 1461;
        int num5 = num / 365;
        if (num5 == 4)
        {
            num5 = 3;
        }
        if (part == 0)
        {
            return num2 * 400 + num3 * 100 + num4 * 4 + num5 + 1;
        }
        num -= num5 * 365;
        if (part == 1)
        {
            return num + 1;
        }
        int* array = (num5 == 3 && (num4 != 24 || num3 == 3)) ? DaysToMonth366() : DaysToMonth365();
        int i = 0;
        for (i = num >> 6; num >= array[i]; i++)
        {
        }
        if (part == 2)
        {
            return i;
        }
        return num - array[i - 1] + 1;
    }

public:
    inline int              Day() {
        return GetDatePart(3);
    }
    inline int              DayOfYear() {
        return GetDatePart(1);
    }
    inline DayOfWeek        DayOfWeeks() {
        return (DayOfWeek)((Ticks() / 864000000000LL + 1) % 7);
    }
    inline int              Month() {
        return GetDatePart(2);
    }
    inline int              Year() {
        return GetDatePart(0);
    }

public:
    inline DateTime         Date()
    {
        long long internalTicks = Ticks();
        return DateTime((unsigned long long)(internalTicks - internalTicks % 864000000000LL));
    }
    DateTime                ToUtc();
    DateTime                ToLocal();

public:
    inline static int       Compare(DateTime t1, DateTime t2)
    {
        long long internalTicks = t1.Ticks();
        long long internalTicks2 = t2.Ticks();
        if (internalTicks > internalTicks2)
        {
            return 1;
        }
        if (internalTicks < internalTicks2)
        {
            return -1;
        }
        return 0;
    }
    inline int              CompareTo(DateTime value)
    {
        return Compare(*this, value);
    }
    inline bool             Equals(DateTime value)
    {
        return Ticks() == value.Ticks();
    }
    inline static bool      Equals(DateTime t1, DateTime t2)
    {
        return t1.Ticks() == t2.Ticks();
    }

public:
    inline static bool      IsLeapYear(int year)
    {
        if (year < 1 || year > 9999)
        {
            return false;
        }
        if (year % 4 == 0)
        {
            if (year % 100 == 0)
            {
                return year % 400 == 0;
            }
            return true;
        }
        return false;
    }
    inline static int       DaysInMonth(int year, int month)
    {
        if (month < 1 || month > 12)
        {
            return -1;
        }
        int* array = IsLeapYear(year) ? DaysToMonth366() : DaysToMonth365();
        return array[month] - array[month - 1];
    }

public:
    inline DateTime         AddTicks(long long value) {
        long internalTicks = Ticks();
        if (value > 3155378975999999999LL - internalTicks)
        {
            value = 3155378975999999999LL - internalTicks;
        }
        if (value < -internalTicks)
        {
            value = -internalTicks;
        }
        return DateTime((unsigned long long)(internalTicks + value));
    }
    inline DateTime         Add(long double value, int scale) {
        long long num = (long long)(value * (long double)scale + ((value >= 0.0) ? 0.5 : (-0.5)));
        if (num <= -315537897600000LL)
        {
            num = -315537897600000LL;
        }
        if (num >= 315537897600000LL)
        {
            num = 315537897600000LL;
        }
        return AddTicks(num * 10000);
    }
    inline DateTime         AddDays(long double value) {
        return Add(value, 86400000);
    }
    inline DateTime         AddHours(long double value)
    {
        return Add(value, 3600000);
    }
    inline DateTime         AddSeconds(long double value)
    {
        return Add(value, 1000);
    }
    inline DateTime         AddMinutes(long double value)
    {
        return Add(value, 60000);
    }
    inline DateTime         AddMilliseconds(long double value)
    {
        return Add(value, 1);
    }

private:
    inline long             DateToTicks(int year, int month, int day)
    {
        if (year >= 1 && year <= 9999 && month >= 1 && month <= 12)
        {
            int* array = IsLeapYear(year) ? DaysToMonth366() : DaysToMonth365();
            if (day >= 1 && day <= array[month] - array[month - 1])
            {
                int num = year - 1;
                int num2 = num * 365 + num / 4 - num / 100 + num / 400 + array[month - 1] + day - 1;
                return num2 * 864000000000LL;
            }
        }
        return 0;
    }
    inline void             GetDatePart(int& year, int& month, int& day)
    {
        long long internalTicks = Ticks();
        int num = (int)(internalTicks / 864000000000LL);
        int num2 = num / 146097;
        num -= num2 * 146097;
        int num3 = num / 36524;
        if (num3 == 4)
        {
            num3 = 3;
        }
        num -= num3 * 36524;
        int num4 = num / 1461;
        num -= num4 * 1461;
        int num5 = num / 365;
        if (num5 == 4)
        {
            num5 = 3;
        }
        year = num2 * 400 + num3 * 100 + num4 * 4 + num5 + 1;
        num -= num5 * 365;
        int* array = (num5 == 3 && (num4 != 24 || num3 == 3)) ? DaysToMonth366() : DaysToMonth365();
        int i = 0;
        for (i = (num >> 5) + 1; num >= array[i]; i++)
        {
        }
        month = i;
        day = num - array[i - 1] + 1;
    }

public:
    inline DateTime         AddMonths(int months)
    {
        if (months < -120000 || months > 120000)
        {
            return *this;
        }
        int year;
        int month;
        int day;
        GetDatePart(year, month, day);
        int num = month - 1 + months;
        if (num >= 0)
        {
            month = num % 12 + 1;
            year += num / 12;
        }
        else
        {
            month = 12 + (num + 1) % 12;
            year += (num - 11) / 12;
        }
        if (year < 1 || year > 9999)
        {
            return *this;
        }
        int num2 = DaysInMonth(year, month);
        if (day > num2)
        {
            day = num2;
        }
        return DateTime((unsigned long long)((DateToTicks(year, month, day) + Ticks() % 864000000000LL)));
    }
    inline DateTime         Subtract(DateTime value)
    {
        return DateTime(Ticks() - value.Ticks());
    }
    inline DateTime         AddYears(int year)
    {
        if (year < -10000 || year > 10000)
        {
            return *this;
        }
        return AddMonths(year * 12);
    }

public:
    inline long double           TotalDays()
    {
        return (long double)Ticks() * 1.1574074074074074E-12;
    }
    inline long double           TotalHours()
    {
        return (long double)Ticks() * 2.7777777777777777E-11;
    }
    inline long double           TotalMilliseconds()
    {
        long double num = (long double)Ticks() * 0.0001;
        if (num > 922337203685477.0)
        {
            return 922337203685477.0;
        }
        if (num < -922337203685477.0)
        {
            return -922337203685477.0;
        }
        return num;
    }
    inline long double           TotalMinutes()
    {
        return (long double)Ticks() * 1.6666666666666667E-09;
    }
    inline long double           TotalSeconds()
    {
        return (long double)Ticks() * 1E-07;
    }

public:
    static DateTime         Now();
    static DateTime         UtcNow();
    static int              GetGMTOffset(bool abs = false);
    inline static DateTime  MinValue()
    {
        return DateTime(0);
    }
    inline static DateTime  MaxValue()
    {
        return DateTime(3155378975999999999LL);
    }

public:
    inline static bool          TryParse(const char* s, DateTime& dateTime)
    {
        return TryParse(s, -1, dateTime);
    }
    static bool                 TryParse(const char* s, int len, DateTime& dateTime);
    inline static bool          TryParse(const std::string& s, DateTime& dateTime)
    {
        std::string& sx = const_cast<std::string&>(s);
        return TryParse(sx.c_str(), sx.length(), dateTime);
    }
    inline static DateTime      Parse(const char* s)
    {
        return Parse(s, -1);
    }
    inline static DateTime      Parse(const char* s, int len)
    {
        DateTime dateTime;
        TryParse(s, len, dateTime);
        return dateTime;
    }
    inline static DateTime      Parse(const std::string& s)
    {
        DateTime dateTime;
        TryParse(s, dateTime);
        return dateTime;
    }

public:
    inline std::string          ToString(const std::string& s)
    {
        std::string& sx = const_cast<std::string&>(s);
        return ToString(sx.data(), sx.length());
    }
    inline std::string          ToString(const char* format)
    {
        return ToString(format, -1);
    }
    std::string                 ToString(const char* format, int len);

public:
    inline bool             operator==(const DateTime& right)
    {
        return Ticks() == const_cast<DateTime&>(right).Ticks();
    }
    inline bool             operator!=(const DateTime& right)
    {
        return Ticks() != const_cast<DateTime&>(right).Ticks();
    }
    inline bool             operator>(const DateTime& right)
    {
        return Ticks() > const_cast<DateTime&>(right).Ticks();
    }
    inline bool             operator<(const DateTime& right)
    {
        return Ticks() < const_cast<DateTime&>(right).Ticks();
    }
    inline bool             operator>=(const DateTime& right)
    {
        return Ticks() >= const_cast<DateTime&>(right).Ticks();
    }
    inline bool             operator<=(const DateTime& right)
    {
        return Ticks() <= const_cast<DateTime&>(right).Ticks();
    }
    inline DateTime         operator+(const DateTime& right)
    {
        long long ticks = const_cast<DateTime&>(right).Ticks();
        return this->AddTicks(ticks);
    }
    inline DateTime         operator-(const DateTime& right)
    {
        return this->Subtract(right);
    }
};

DateTime.cpp

#include "DateTime.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <math.h>
#include <string>
#include <string.h>

DateTime DateTime::ToUtc()
{
    return this->AddSeconds(-GetGMTOffset());
}

DateTime DateTime::ToLocal()
{
    return this->AddSeconds(GetGMTOffset());
}

static double DateTimeTicksRound(double number, unsigned int bits = 0)
{
    long long integerPart = number;
    number -= integerPart;
    for (unsigned int i = 0; i < bits; ++i)
        number *= 10;
    number = (long long)(number + 0.5);
    for (unsigned int i = 0; i < bits; ++i)
        number /= 10;
    return integerPart + number;
}

DateTime DateTime::Now()
{
    int gmtoff = GetGMTOffset();

    DateTime dateTime = UtcNow();
    if (0 != gmtoff)
    {
        dateTime = dateTime.AddSeconds(gmtoff);
    }

    return dateTime;
}

DateTime DateTime::UtcNow()
{
    struct timespec ts = { 0, 0 };

    clock_gettime(CLOCK_REALTIME, &ts);

    long long sec = (long long)ts.tv_sec;
    long long nsec = (long long)ts.tv_nsec;
    long long nsec_100 = DateTimeTicksRound((double)nsec / 100);

    DateTime dateTime = DateTime(1970, 1, 1, 0, 0, 0);

    long long ticks = sec * 10000000;
    ticks += nsec_100;
    ticks += dateTime.Ticks();

    return DateTime(ticks);
}

int DateTime::GetGMTOffset(bool abs)
{
    static int gmtoff = 0;
    static char geted = 0;
    if (abs || 0 == geted)
    {
        time_t rawtime;
        struct tm* ptm;

        time(&rawtime);

        ptm = gmtime(&rawtime);
        gmtoff = ptm->tm_gmtoff;

        if (0 == gmtoff) // 获取当前时区与中心时区之间(TimeZoneInfo)的时差;例:中国GMT/CST(东八区+ UTC-8)
        {
            ptm = localtime(&rawtime);
            gmtoff = ptm->tm_gmtoff;
        }

        geted = 1;
    }

    return gmtoff;
}

bool DateTime::TryParse(const char* s, int len, DateTime& out)
{
    out = MinValue();
    if (s == NULL && len != 0)
    {
        return false;
    }
    if (s != NULL && len == 0)
    {
        return false;
    }
    if (len < 0)
    {
        len = (int)strlen(s);
    }
    if (len <= 0)
    {
        return false;
    }
    static const int max_segments_length = 7;
    std::string segments[max_segments_length + 1];

    const char* p = s;
    unsigned int length = 0;
    while (p < (s + len) && *p != '\x0')
    {
        char ch = *p;
        if (ch >= '0' && ch <= '9')
        {
            char buf[2] = { ch, '\x0' };
            segments[length] += buf;
        }
        else
        {
            if (!segments[length].empty())
            {
                length++;
                if (length >= max_segments_length)
                {
                    break;
                }
                segments[length].empty();
            }
        }
        p++;
    }

    struct
    {
        int y;
        int M;
        int d;
        int H;
        int m;
        int s;
        int f;
    } tm;

    if (0 == length)
    {
        return false;
    }
    else
    {
        int* t = (int*)&tm;
        for (unsigned int i = 1; i <= max_segments_length; i++)
        {
            if (i > (length + 1))
            {
                t[i - 1] = 0;
            }
            else
            {
                std::string& sx = segments[i - 1];
                if (sx.empty())
                {
                    t[i - 1] = 0;
                }
                else
                {
                    t[i - 1] = atoi(sx.c_str());
                }
            }
        }
        out = DateTime(tm.y, tm.M, tm.d, tm.H, tm.m, tm.s, tm.f);
    }
    return length > 0;
}

std::string DateTime::ToString(const char* format, int len)
{
    if (format == NULL && len != 0)
    {
        return "";
    }
    if (format != NULL && len == 0)
    {
        return "";
    }
    if (len < 0)
    {
        len = (int)strlen(format);
    }
    if (len <= 0)
    {
        return "";
    }

#define DATETIME_FORMAT_PROPERTY_TOSTRING(k, v) \
{ \
        { \
            int n = 0; \
            while ( (p + n) < e && p[n] == *(#k) ) n++; \
            if ( n > 0 ) \
            { \
                char buf[ 255 ]; \
                char fmt[ 50 ]; \
                fmt[ 0 ] = '%'; \
                fmt[ 1 ] = '0'; \
                sprintf( fmt + 2, "%dlld", n ); \
                sprintf( buf, fmt, (long long int)v ); \
                s += buf; \
                p += n; \
            } \
        } \
    DATETIME_FORMAT_DIVIDER_TOSTRING(); \
}

#define DATETIME_FORMAT_DIVIDER_TOSTRING() \
    { \
            const char* fb = "yMdHmsfu"; \
            char buf[ 50 ]; \
            int n = 0; \
            while ( ( p + n ) < e && n < (int)(sizeof(buf) - 1)) { \
                char ch = p[ n ]; \
                if ( ch == '\x0' ) break; \
                bool fx = false; \
                for ( int i = 0; i < 8; i++ ) { \
                    if ( ch == fb[ i ] ) { \
                        fx = true; \
                        break; \
                    } \
                } \
                if ( fx ) break; else buf[n++] = ch; \
            } \
            buf[ n ] = '\x0'; \
            if ( buf[ 0 ] != '\x0' ) { \
                s += buf; \
                p += n; \
            } \
    }

    std::string s = "";

    const char* p = format;
    const char* e = p + len;
    while (p < e && *p != '\x0')
    {
        DATETIME_FORMAT_PROPERTY_TOSTRING(y, Year());
        DATETIME_FORMAT_PROPERTY_TOSTRING(M, Month());
        DATETIME_FORMAT_PROPERTY_TOSTRING(d, Day());
        DATETIME_FORMAT_PROPERTY_TOSTRING(H, Hour());
        DATETIME_FORMAT_PROPERTY_TOSTRING(m, Minute());
        DATETIME_FORMAT_PROPERTY_TOSTRING(s, Second());
        DATETIME_FORMAT_PROPERTY_TOSTRING(f, Millisecond());
        DATETIME_FORMAT_PROPERTY_TOSTRING(u, Microseconds());

        p++;
    }

#undef DATETIME_FORMAT_DIVIDER_TOSTRING
#undef DATETIME_FORMAT_PROPERTY_TOSTRING

    return s;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值