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;
}