Add date code

This commit is contained in:
2025-05-10 19:52:23 -05:00
parent 1cb9bc93ee
commit 21b0418926
31 changed files with 21614 additions and 78 deletions

720
src/Date/Date.cpp Normal file
View File

@@ -0,0 +1,720 @@
#include "TessesFramework/Date/Date.hpp"
#include "TessesFramework/Http/HttpUtils.hpp"
#include "../HowardHinnant_date/date.h"
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace std::chrono;
using namespace date;
namespace Tesses::Framework::Date
{
int GetTimeZone()
{
#if defined(__SWITCH__) || defined(_WIN32)
return (int)(-_timezone);
#else
return (int)(-timezone);
#endif
}
bool TimeZoneSupportDST()
{
#if defined(__SWITCH__) || defined(_WIN32)
return _daylight == 1;
#else
return daylight == 1;
#endif
}
DateTime::DateTime()
{
}
static int64_t div_floor(int64_t a, int64_t b)
{
int64_t v = a / b;
if(a < 0 && (a % b) != 0) v--;
return v;
}
void DateTime::FromEpochNoConvert(int64_t gmt)
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(div_floor(gmt,86400));
//date::days<int64_t> sys_days_since_epoch = date::days<int64_t>(gmt);
// Convert sys_days to year_month_day
date::year_month_day ymd = date::year_month_day(epoch);
int64_t secs = gmt % 86400;
if(secs < 0) secs += 86400;
second = secs % 60;
secs /= 60;
minute = secs % 60;
secs /= 60;
hour = secs % 24;
day = (int)(uint32_t)ymd.day();
month = (int)(uint32_t)ymd.month();
year = (int32_t)ymd.year();
}
DateTime::DateTime(int64_t epoch)
{
this->isLocal=false;
this->FromEpochNoConvert(epoch);
}
void DateTime::Set(int64_t epoch)
{
this->isLocal=false;
this->FromEpochNoConvert(epoch);
}
void DateTime::Set(int year, int month, int day, int hour, int minute, int seconds, bool isLocal)
{
this->year = year;
this->month = month;
this->day = day;
this->hour = hour;
this->minute = minute;
this->second = seconds;
this->isLocal = isLocal;
}
DateTime::DateTime(int year, int month, int day, int hour, int minute, int seconds, bool isLocal)
{
this->year = year;
this->month = month;
this->day = day;
this->hour = hour;
this->minute = minute;
this->second = seconds;
this->isLocal = isLocal;
}
int DateTime::Year()
{
return this->year;
}
int DateTime::Month()
{
return this->month;
}
int DateTime::Day()
{
return this->day;
}
int DateTime::Hour()
{
return this->hour;
}
int DateTime::Minute()
{
return this->minute;
}
int DateTime::Second()
{
return this->second;
}
bool DateTime::IsLocal()
{
return this->isLocal;
}
int DateTime::DayOfWeek()
{
date::year_month_day ymd(date::year(year),date::month((uint32_t)month),date::day((uint32_t)day));
date::sys_days d = ymd;
date::year_month_weekday ymw(d);
return ymw.weekday().c_encoding() % 7;
}
void DateTime::SetToLocal()
{
if(this->isLocal) return;
auto local = this->ToEpochNoConvert();
local += GetTimeZone();
if(TimeZoneSupportDST())
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(div_floor(local,86400));
bool isDST = false;
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
if(month > 3 && month < 11)
{
isDST=true;
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
auto secondSunday = day - dow;
if(secondSunday < 8) secondSunday+=7;
if(day > secondSunday) isDST=true;
else if(day == secondSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours >= 2) isDST=true;
}
}
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
int32_t firstSunday = (int32_t)day - (int32_t)dow;
if(firstSunday < 1) firstSunday+=7;
if(day < firstSunday) isDST=true;
else if(day == firstSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours <=1) isDST=true;
}
}
}
if(isDST) local += 3600;
}
this->isLocal=true;
this->FromEpochNoConvert(local);
}
DateTime DateTime::ToLocal()
{
DateTime dt = *this;
dt.SetToLocal();
return dt;
}
void DateTime::SetToUTC()
{
if(!this->isLocal) return;
auto local = this->ToEpochNoConvert();
local -= GetTimeZone();
if(TimeZoneSupportDST())
{
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(div_floor(local,86400));
bool isDST = false;
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
if(month > 3 && month < 11)
{
isDST=true;
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
auto secondSunday = day - dow;
if(secondSunday < 8) secondSunday+=7;
if(day > secondSunday) isDST=true;
else if(day == secondSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours >= 2) isDST=true;
}
}
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
int32_t firstSunday = (int32_t)day - (int32_t)dow;
if(firstSunday < 1) firstSunday+=7;
if(day < firstSunday) isDST=true;
else if(day == firstSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours <=1) isDST=true;
}
}
}
if(isDST) local -= 3600;
}
}
this->isLocal=false;
this->FromEpochNoConvert(local);
}
DateTime DateTime::ToUTC()
{
DateTime dt = *this;
dt.SetToUTC();
return dt;
}
int64_t DateTime::ToEpoch()
{
if(this->isLocal)
{
DateTime dt = this->ToUTC();
return dt.ToEpochNoConvert();
}
return this->ToEpochNoConvert();
}
int64_t DateTime::ToEpochNoConvert()
{
date::year y = (date::year)year;
date::month m = (date::month)month;
date::day d = (date::day)day;
date::year_month_day ymd(y,m,d);
std::chrono::duration hr = hours(this->hour) + minutes(this->minute) + seconds(this->second);
sys_days sd = ymd;
auto res = sd - date::sys_days{date::January/1/1970};
return (res.count() * 86400) + hr.count(); //bad
}
DateTime DateTime::NowUTC()
{
DateTime theTime((int64_t)time(NULL));
return theTime;
}
void DateTime::SetToNowUTC()
{
this->Set((int64_t)time(NULL));
}
void DateTime::SetYear(int y)
{
this->year = year;
}
void DateTime::SetMonth(int m)
{
this->month = m;
}
void DateTime::SetDay(int d)
{
this->day = d;
}
void DateTime::SetHour(int h)
{
this->hour = h;
}
void DateTime::SetMinute(int m)
{
this->minute = m;
}
void DateTime::SetSecond(int s)
{
this->second = s;
}
void DateTime::SetLocal(bool local)
{
this->isLocal=local;
}
void DateTime::SetToNow()
{
int64_t local = (int64_t)time(NULL);
local += GetTimeZone();
if(TimeZoneSupportDST())
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(div_floor(local,86400));
bool isDST = false;
date::year_month_day ymd(epoch);
auto month = (uint32_t)ymd.month();
if(month > 3 && month < 11)
{
isDST=true;
}
else if(month == 3)
{
auto day = (uint32_t)ymd.day();
if(day > 14) isDST=true;
else if(day >= 8 && day <= 14)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
auto secondSunday = day - dow;
if(secondSunday < 8) secondSunday+=7;
if(day > secondSunday) isDST=true;
else if(day == secondSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours >= 2) isDST=true;
}
}
}
else if(month == 11)
{
auto day = (uint32_t)ymd.day();
if(day >= 1 && day <= 7)
{
date::year_month_weekday ymw(epoch);
auto dow=ymw.weekday().c_encoding();
int32_t firstSunday = (int32_t)day - (int32_t)dow;
if(firstSunday < 1) firstSunday+=7;
if(day < firstSunday) isDST=true;
else if(day == firstSunday)
{
int64_t secs = local % 86400;
if(secs < 0) secs += 86400;
secs /= 3600;
auto _hours = secs % 24;
if(_hours <=1) isDST=true;
}
}
}
if(isDST) local += 3600;
}
this->isLocal=true;
this->FromEpochNoConvert(local);
}
DateTime DateTime::Now()
{
DateTime dt;
dt.SetToNow();
return dt;
}
const char* weekday_short[] = {
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat"
};
const char* months_short[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
const char* weekday_long[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
};
const char* months_long[] = {
"January",
"Febuary",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
};
bool DateTime::TryParseHttpDate(std::string txt, DateTime& dt)
{
//Mon, 24 Jul 2018 11:00:00 GMT
auto split = Http::HttpUtils::SplitString(txt,", ",2);
if(split.size() != 2) return false;
bool validDay = false;
for(size_t i = 0; i < 7; i++)
{
std::string_view d = weekday_short[i];
if(d == split[0]) validDay=true;
}
if(!validDay) return false;
//DAY MON YEAR HH:MM:SS GMT
split = Http::HttpUtils::SplitString(split[1]," ",5);
if(split.size() != 5) return false;
if(split[4] != "GMT") return false;
int day=0;
int mon=0;
int year=0;
int hour=0;
int minute=0;
int second=0;
try {
day = std::stoi(split[0]);
if(day < 1 && day > 31) return false;
} catch(std::exception& ex) {
return false;
}
for(int i = 0; i < 12; mon++)
{
std::string_view d = months_short[i];
if(d == split[1])
{
mon = i + 1;
break;
}
}
if(mon == 0) return false;
try {
year = std::stoi(split[2]);
} catch(std::exception& ex) {
return false;
}
split = Http::HttpUtils::SplitString(split[3],":",3);
if(split.size() != 3) return false;
try {
hour = std::stoi(split[0]);
minute = std::stoi(split[1]);
second = std::stoi(split[2]);
} catch(std::exception& ex) {
return false;
}
dt.day = day;
dt.month = mon;
dt.year = year;
dt.hour = hour;
dt.minute = minute;
dt.second = second;
return true;
}
std::string DateTime::ToHttpDate()
{
auto utc=this->ToUTC();
std::string weekday=weekday_short[utc.DayOfWeek()];
std::string month = months_short[utc.month-1];
std::stringstream strm(std::ios_base::out);
strm << weekday << ", " << std::setfill('0') << std::setw(2) << utc.day;
strm << " " << month << " " << std::setfill('0') << std::setw(4) << utc.year;
strm << " " << std::setfill('0') << std::setw(2) << utc.hour;
strm << ":" << std::setfill('0') << std::setw(2) << utc.minute;
strm << ":" << std::setfill('0') << std::setw(2) << utc.second;
strm << " GMT";
return strm.str();
}
std::string DateTime::ToString()
{
return ToString("%Y/%m/%d %H:%M:%S");
}
std::string DateTime::ToString(std::string fmt)
{
auto weekday = this->DayOfWeek();
std::string text = "";
for(size_t i = 0; i < fmt.size(); i++)
{
if(fmt[i]=='%')
{
i++;
if(i < fmt.size())
switch(fmt[i])
{
case 'a':
text.append(weekday_short[weekday]);
break;
case 'A':
text.append(weekday_long[weekday]);
break;
case 'S':
text.append(Http::HttpUtils::LeftPad(std::to_string(second),2,'0'));
break;
case 'm':
text.append(Http::HttpUtils::LeftPad(std::to_string(month),2,'0'));
break;
case 'd':
text.append(Http::HttpUtils::LeftPad(std::to_string(day),2,'0'));
break;
case 'e':
text.append(Http::HttpUtils::LeftPad(std::to_string(day),2,' '));
break;
case 'M':
text.append(Http::HttpUtils::LeftPad(std::to_string(minute),2,'0'));
break;
case 'H':
text.append(Http::HttpUtils::LeftPad(std::to_string(hour),2,'0'));
break;
case 'F':
text.append(Http::HttpUtils::LeftPad(std::to_string(year),4,'0'));
text.push_back('-');
text.append(Http::HttpUtils::LeftPad(std::to_string(month),2,'0'));
text.push_back('-');
text.append(Http::HttpUtils::LeftPad(std::to_string(day),2,'0'));
break;
case 'D':
text.append(Http::HttpUtils::LeftPad(std::to_string(month),2,'0'));
text.push_back('/');
text.append(Http::HttpUtils::LeftPad(std::to_string(day),2,'0'));
text.push_back('/');
text.append(Http::HttpUtils::LeftPad(std::to_string(year % 100),2,'0'));
break;
case 'y':
text.append(Http::HttpUtils::LeftPad(std::to_string(year % 100),2,'0'));
break;
case 'r':
{
auto hours = hour % 12;
if(hours == 0) hours=12;
text.append(Http::HttpUtils::LeftPad(std::to_string(hours),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(minute),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(second),2,'0'));
text.append(hour >= 12 ? " PM" : " AM");
}
break;
case 'R':
{
text.append(Http::HttpUtils::LeftPad(std::to_string(hour),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(minute),2,'0'));
}
break;
case 'T':
{
text.append(Http::HttpUtils::LeftPad(std::to_string(hour),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(minute),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(second),2,'0'));
}
break;
case 'u':
{
int dow = weekday + 6;
dow %= 7;
text.append(std::to_string(dow+1));
}
break;
case 'w':
{
text.append(std::to_string(weekday));
}
break;
case 'c':
{
text.append(weekday_short[weekday]);
text.push_back(' ');
text.append(months_short[month]);
text.push_back(' ');
text.append(Http::HttpUtils::LeftPad(std::to_string(day),2,'0'));
text.push_back(' ');
text.append(Http::HttpUtils::LeftPad(std::to_string(hour),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(minute),2,'0'));
text.push_back(':');
text.append(Http::HttpUtils::LeftPad(std::to_string(second),2,'0'));
text.push_back(' ');
text.append(Http::HttpUtils::LeftPad(std::to_string(year),4,'0'));
}
break;
case 'C':
text.append(Http::HttpUtils::LeftPad(std::to_string(year / 100),2,'0'));
break;
case 'Y':
text.append(Http::HttpUtils::LeftPad(std::to_string(year),4,'0'));
break;
case 'p':
text.append(hour >= 12 ? "PM" : "AM");
break;
case 'I':
{
auto hours = hour % 12;
if(hours == 0) hours=12;
text.append(Http::HttpUtils::LeftPad(std::to_string(hours),2,'0'));
}
break;
case 'h':
case 'b':
text.append(months_short[month-1]);
break;
case 'B':
text.append(months_long[month-1]);
break;
case '%':
text.push_back('%');
break;
case 'n':
text.push_back('\n');
break;
case 't':
text.push_back('\t');
break;
}
}
else
{
text.push_back(fmt[i]);
}
}
return text;
}
}