Angelscript/add_on/datetime/datetime.cpp

271 lines
12 KiB
C++

#include "datetime.h"
#include "../autowrapper/aswrappedcall.h"
#include <string.h>
#include <assert.h>
#include <new>
using namespace std;
using namespace std::chrono;
BEGIN_AS_NAMESPACE
// TODO: Allow setting the timezone to use
static tm time_point_to_tm(const std::chrono::time_point<std::chrono::system_clock> &tp)
{
time_t t = system_clock::to_time_t(tp);
tm local;
// Use the universal timezone
#ifdef _MSC_VER
gmtime_s(&local, &t);
#else
local = *gmtime(&t);
#endif
return local;
}
// Returns true if successful. Doesn't modify tp if not successful
static bool tm_to_time_point(const tm &_tm, std::chrono::time_point<std::chrono::system_clock> &tp)
{
tm localTm = _tm;
// Do not rely on timezone, as it is not portable
// ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc
// ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
localTm.tm_isdst = -1; // Always use current settings, so mktime doesn't modify the time for daylight savings
time_t t = mktime(&localTm);
if (t == -1)
return false;
// Adjust the time_t since epoch with the difference of the local timezone to the universal timezone
t += (mktime(localtime(&t)) - mktime(gmtime(&t)));
// Verify if the members were modified, indicating an out-of-range value in input
if (localTm.tm_year != _tm.tm_year ||
localTm.tm_mon != _tm.tm_mon ||
localTm.tm_mday != _tm.tm_mday ||
localTm.tm_hour != _tm.tm_hour ||
localTm.tm_min != _tm.tm_min ||
localTm.tm_sec != _tm.tm_sec)
return false;
tp = system_clock::from_time_t(t);
return true;
}
CDateTime::CDateTime() : tp(std::chrono::system_clock::now())
{
}
CDateTime::CDateTime(const CDateTime &o) : tp(o.tp)
{
}
CDateTime &CDateTime::operator=(const CDateTime &o)
{
tp = o.tp;
return *this;
}
asUINT CDateTime::getYear() const
{
tm local = time_point_to_tm(tp);
return local.tm_year + 1900;
}
asUINT CDateTime::getMonth() const
{
tm local = time_point_to_tm(tp);
return local.tm_mon + 1;
}
asUINT CDateTime::getDay() const
{
tm local = time_point_to_tm(tp);
return local.tm_mday;
}
asUINT CDateTime::getHour() const
{
tm local = time_point_to_tm(tp);
return local.tm_hour;
}
asUINT CDateTime::getMinute() const
{
tm local = time_point_to_tm(tp);
return local.tm_min;
}
asUINT CDateTime::getSecond() const
{
tm local = time_point_to_tm(tp);
return local.tm_sec;
}
bool CDateTime::setDate(asUINT year, asUINT month, asUINT day)
{
tm local = time_point_to_tm(tp);
local.tm_year = int(year) - 1900;
local.tm_mon = month - 1;
local.tm_mday = day;
return tm_to_time_point(local, tp);
}
bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second)
{
tm local = time_point_to_tm(tp);
local.tm_hour = hour;
local.tm_min = minute;
local.tm_sec = second;
return tm_to_time_point(local, tp);
}
CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second)
{
tp = std::chrono::system_clock::now();
setDate(year, month, day);
setTime(hour, minute, second);
}
asINT64 CDateTime::operator-(const CDateTime &dt) const
{
return (tp - dt.tp).count() / std::chrono::system_clock::period::den * std::chrono::system_clock::period::num;
}
CDateTime CDateTime::operator+(asINT64 seconds) const
{
CDateTime dt(*this);
dt.tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num);
return dt;
}
CDateTime &CDateTime::operator+=(asINT64 seconds)
{
tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num);
return *this;
}
CDateTime operator+(asINT64 seconds, const CDateTime &other)
{
return other + seconds;
}
CDateTime CDateTime::operator-(asINT64 seconds) const
{
return *this + -seconds;
}
CDateTime &CDateTime::operator-=(asINT64 seconds)
{
return *this += -seconds;
}
CDateTime operator-(asINT64 seconds, const CDateTime &other)
{
return other + -seconds;
}
bool CDateTime::operator==(const CDateTime &other) const
{
return tp == other.tp;
}
bool CDateTime::operator<(const CDateTime &other) const
{
return tp < other.tp;
}
static int opCmp(const CDateTime &a, const CDateTime &b)
{
if (a < b) return -1;
if (a == b) return 0;
return 1;
}
static void Construct(CDateTime *mem)
{
new(mem) CDateTime();
}
static void ConstructCopy(CDateTime *mem, const CDateTime &o)
{
new(mem) CDateTime(o);
}
static void ConstructSet(CDateTime *mem, asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second)
{
new(mem) CDateTime(year, month, day, hour, minute, second);
}
static void ConstructSet_Generic(asIScriptGeneric *gen)
{
CDateTime *date = (CDateTime*)gen->GetObject();
asUINT year = *(asUINT*)gen->GetAddressOfArg(0);
asUINT month = *(asUINT*)gen->GetAddressOfArg(1);
asUINT day = *(asUINT*)gen->GetAddressOfArg(2);
asUINT hour = *(asUINT*)gen->GetAddressOfArg(3);
asUINT minute = *(asUINT*)gen->GetAddressOfArg(4);
asUINT second = *(asUINT*)gen->GetAddressOfArg(5);
ConstructSet(date, year, month, day, hour, minute, second);
}
void RegisterScriptDateTime(asIScriptEngine *engine)
{
int r = engine->RegisterObjectType("datetime", sizeof(CDateTime), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits<CDateTime>()); assert(r >= 0);
if(strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")==0)
{
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", asFUNCTION(ConstructCopy), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet), asCALL_CDECL_OBJFIRST); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", asMETHOD(CDateTime, operator=), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", asMETHOD(CDateTime, getYear), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", asMETHOD(CDateTime, getMonth), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", asMETHOD(CDateTime, getDay), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", asMETHOD(CDateTime, getHour), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", asMETHOD(CDateTime, getMinute), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", asMETHOD(CDateTime, getSecond), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", asMETHOD(CDateTime, setDate), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", asMETHOD(CDateTime, setTime), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", asMETHODPR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", asMETHOD(CDateTime, operator+), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", asFUNCTIONPR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", asMETHOD(CDateTime, operator+=), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", asMETHODPR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", asFUNCTIONPR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", asMETHOD(CDateTime, operator-=), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", asMETHODPR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_THISCALL); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", asFUNCTION(opCmp), asCALL_CDECL_OBJFIRST); assert(r >= 0);
}
else
{
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_LAST(Construct), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", WRAP_OBJ_FIRST(ConstructCopy), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet_Generic), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", WRAP_MFN(CDateTime, operator=), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", WRAP_MFN(CDateTime, getYear), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", WRAP_MFN(CDateTime, getMonth), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", WRAP_MFN(CDateTime, getDay), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", WRAP_MFN(CDateTime, getHour), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", WRAP_MFN(CDateTime, getMinute), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", WRAP_MFN(CDateTime, getSecond), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", WRAP_MFN(CDateTime, setDate), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", WRAP_MFN(CDateTime, setTime), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", WRAP_MFN(CDateTime, operator+), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", WRAP_MFN(CDateTime, operator+=), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", WRAP_MFN_PR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", WRAP_MFN(CDateTime, operator-=), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_GENERIC); assert(r >= 0);
r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", WRAP_OBJ_FIRST(opCmp), asCALL_GENERIC); assert(r >= 0);
}
}
END_AS_NAMESPACE