Move date to tessesframework

This commit is contained in:
2025-05-10 19:54:03 -05:00
parent cabe5ba8cd
commit a684c9ba45
16 changed files with 404 additions and 20675 deletions

View File

@ -124,7 +124,7 @@ src/runtime_methods/ogc.cpp
src/runtime_methods/path.cpp
src/runtime_methods/env.cpp
src/runtime_methods/process.cpp
src/runtime_methods/time.cpp
src/types/datetime.cpp
src/types/ittr.cpp
src/types/closure.cpp
src/types/dictionary.cpp

View File

@ -1348,11 +1348,21 @@ class Parser {
class MethodInvoker {
};
class TDateTime {
Tesses::Framework::Date::DateTime* dt;
public:
TDateTime();
TDateTime(Tesses::Framework::Date::DateTime t);
TDateTime(const TDateTime& dt);
Tesses::Framework::Date::DateTime& GetDate();
~TDateTime();
};
/**
* @brief A script object
*
*/
using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,TVMVersion>;
using TObject = std::variant<int64_t,double,char,bool,std::string,std::regex,Tesses::Framework::Filesystem::VFSPath,std::nullptr_t,Undefined,MethodInvoker,THeapObjectHolder,TVMVersion,TDateTime>;
class TRootEnvironment;
class GC;
class GC {
@ -1500,7 +1510,6 @@ class GC {
};
using TDItem = std::pair<std::string, TObject>;
class TDictionary : public THeapObject
{
public:
@ -1609,7 +1618,6 @@ class GC {
bool canRegisterPath;
bool canRegisterOGC;
bool canRegisterEnv;
bool canRegisterTime;
bool sqlite3Scoped;
bool locked;
};
@ -1660,7 +1668,6 @@ class GC {
static void RegisterOGC(GC* gc, TRootEnvironment* env);
static void RegisterEnv(GC* gc, TRootEnvironment* env);
static void RegisterProcess(GC* gc, TRootEnvironment* env);
static void RegisterTime(GC* gc, TRootEnvironment* env);
};
@ -1863,8 +1870,8 @@ class GC {
Tesses::Framework::Filesystem::VFSPath ReadLink(Tesses::Framework::Filesystem::VFSPath path);
std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path);
Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path);
void GetDate(Tesses::Framework::Filesystem::VFSPath path, time_t& lastWrite, time_t& lastAccess);
void SetDate(Tesses::Framework::Filesystem::VFSPath path, time_t lastWrite, time_t lastAccess);
void GetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime& lastWrite, Tesses::Framework::Date::DateTime& lastAccess);
void SetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime lastWrite, Tesses::Framework::Date::DateTime lastAccess);
~TObjectVFS();
};

View File

@ -1,34 +0,0 @@
#ifndef CHRONO_IO_H
#define CHRONO_IO_H
// The MIT License (MIT)
//
// Copyright (c) 2016, 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Our apologies. When the previous paragraph was written, lowercase had not yet
// been invented (that would involve another several millennia of evolution).
// We did not mean to shout.
// This functionality has moved to "date.h"
#include "date.h"
#endif // CHRONO_IO_H

File diff suppressed because it is too large Load Diff

View File

@ -1,50 +0,0 @@
//
// ios.h
// DateTimeLib
//
// The MIT License (MIT)
//
// Copyright (c) 2016 Alexander Kormanovsky
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef ios_hpp
#define ios_hpp
#if __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# include <string>
namespace date
{
namespace iOSUtils
{
std::string get_tzdata_path();
std::string get_current_timezone();
} // namespace iOSUtils
} // namespace date
# endif // TARGET_OS_IPHONE
#else // !__APPLE__
# define TARGET_OS_IPHONE 0
#endif // !__APPLE__
#endif // ios_hpp

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,952 +0,0 @@
#ifndef PTZ_H
#define PTZ_H
// The MIT License (MIT)
//
// Copyright (c) 2017 Howard Hinnant
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// This header allows Posix-style time zones as specified for TZ here:
// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03
//
// Posix::time_zone can be constructed with a posix-style string and then used in
// a zoned_time like so:
//
// zoned_time<system_clock::duration, Posix::time_zone> zt{"EST5EDT,M3.2.0,M11.1.0",
// system_clock::now()};
// or:
//
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// zoned_time<system_clock::duration, Posix::time_zone> zt{tz, system_clock::now()};
//
// In C++17 CTAD simplifies this to:
//
// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"};
// zoned_time zt{tz, system_clock::now()};
//
// Extension to the Posix rules to allow a constant daylight saving offset:
//
// If the rule set is missing (everything starting with ','), then
// there must be exactly one abbreviation (std or daylight) with
// length 3 or greater, and that will be used as the constant offset. If
// there are two, the std abbreviation is silently set to "", and the
// result is constant daylight saving. If there are zero abbreviations
// with no rule set, an exception is thrown.
//
// Example:
// "EST5" yields a constant offset of -5h with 0h save and "EST abbreviation.
// "5EDT" yields a constant offset of -4h with 1h save and "EDT" abbreviation.
// "EST5EDT" and "5EDT4" are both equal to "5EDT".
//
// Note, Posix-style time zones are not recommended for all of the reasons described here:
// https://stackoverflow.com/tags/timezone/info
//
// They are provided here as a non-trivial custom time zone example, and if you really
// have to have Posix time zones, you're welcome to use this one.
#include "date/tz.h"
#include <algorithm>
#include <cctype>
#include <ostream>
#include <string>
namespace Posix
{
namespace detail
{
#if HAS_STRING_VIEW
using string_t = std::string_view;
#else // !HAS_STRING_VIEW
using string_t = std::string;
#endif // !HAS_STRING_VIEW
class rule;
void throw_invalid(const string_t& s, unsigned i, const string_t& message);
unsigned read_date(const string_t& s, unsigned i, rule& r);
unsigned read_name(const string_t& s, unsigned i, std::string& name);
unsigned read_signed_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t);
unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message = string_t{});
class rule
{
enum {off, J, M, N};
date::month m_;
date::weekday wd_;
unsigned short n_ : 14;
unsigned short mode_ : 2;
std::chrono::duration<std::int32_t> time_ = std::chrono::hours{2};
public:
rule() : mode_(off) {}
bool ok() const {return mode_ != off;}
date::local_seconds operator()(date::year y) const;
std::string to_string() const;
friend std::ostream& operator<<(std::ostream& os, const rule& r);
friend unsigned read_date(const string_t& s, unsigned i, rule& r);
friend bool operator==(const rule& x, const rule& y);
};
inline
bool
operator==(const rule& x, const rule& y)
{
if (x.mode_ != y.mode_)
return false;
switch (x.mode_)
{
case rule::J:
case rule::N:
return x.n_ == y.n_;
case rule::M:
return x.m_ == y.m_ && x.n_ == y.n_ && x.wd_ == y.wd_;
default:
return true;
}
}
inline
bool
operator!=(const rule& x, const rule& y)
{
return !(x == y);
}
inline
date::local_seconds
rule::operator()(date::year y) const
{
using date::local_days;
using date::January;
using date::days;
using date::last;
using sec = std::chrono::seconds;
date::local_seconds t;
switch (mode_)
{
case J:
t = local_days{y/January/0} + days{n_ + (y.is_leap() && n_ > 59)} + sec{time_};
break;
case M:
t = (n_ == 5 ? local_days{y/m_/wd_[last]} : local_days{y/m_/wd_[n_]}) + sec{time_};
break;
case N:
t = local_days{y/January/1} + days{n_} + sec{time_};
break;
default:
assert(!"rule called with bad mode");
}
return t;
}
inline
std::string
rule::to_string() const
{
using namespace std::chrono;
auto print_offset = [](seconds off)
{
std::string nm;
if (off != hours{2})
{
date::hh_mm_ss<seconds> offset{off};
nm = '/';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
}
return nm;
};
std::string nm;
switch (mode_)
{
case rule::J:
nm = 'J';
nm += std::to_string(n_);
break;
case rule::M:
nm = 'M';
nm += std::to_string(static_cast<unsigned>(m_));
nm += '.';
nm += std::to_string(n_);
nm += '.';
nm += std::to_string(wd_.c_encoding());
break;
case rule::N:
nm = std::to_string(n_);
break;
default:
break;
}
nm += print_offset(time_);
return nm;
}
inline
std::ostream&
operator<<(std::ostream& os, const rule& r)
{
switch (r.mode_)
{
case rule::J:
os << 'J' << r.n_ << date::format(" %T", r.time_);
break;
case rule::M:
if (r.n_ == 5)
os << r.m_/r.wd_[date::last];
else
os << r.m_/r.wd_[r.n_];
os << date::format(" %T", r.time_);
break;
case rule::N:
os << r.n_ << date::format(" %T", r.time_);
break;
default:
break;
}
return os;
}
} // namespace detail
class time_zone
{
std::string std_abbrev_;
std::string dst_abbrev_ = {};
std::chrono::seconds offset_;
std::chrono::seconds save_ = std::chrono::hours{1};
detail::rule start_rule_;
detail::rule end_rule_;
public:
explicit time_zone(const detail::string_t& name);
template <class Duration>
date::sys_info get_info(date::sys_time<Duration> st) const;
template <class Duration>
date::local_info get_info(date::local_time<Duration> tp) const;
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_sys(date::local_time<Duration> tp) const;
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_sys(date::local_time<Duration> tp, date::choose z) const;
template <class Duration>
date::local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
to_local(date::sys_time<Duration> tp) const;
friend std::ostream& operator<<(std::ostream& os, const time_zone& z);
const time_zone* operator->() const {return this;}
std::string name() const;
friend bool operator==(const time_zone& x, const time_zone& y);
private:
date::sys_seconds get_start(date::year y) const;
date::sys_seconds get_prev_start(date::year y) const;
date::sys_seconds get_next_start(date::year y) const;
date::sys_seconds get_end(date::year y) const;
date::sys_seconds get_prev_end(date::year y) const;
date::sys_seconds get_next_end(date::year y) const;
date::sys_info contant_offset() const;
};
inline
date::sys_seconds
time_zone::get_start(date::year y) const
{
return date::sys_seconds{(start_rule_(y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_prev_start(date::year y) const
{
return date::sys_seconds{(start_rule_(--y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_next_start(date::year y) const
{
return date::sys_seconds{(start_rule_(++y) - offset_).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_end(date::year y) const
{
return date::sys_seconds{(end_rule_(y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_prev_end(date::year y) const
{
return date::sys_seconds{(end_rule_(--y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_seconds
time_zone::get_next_end(date::year y) const
{
return date::sys_seconds{(end_rule_(++y) - (offset_ + save_)).time_since_epoch()};
}
inline
date::sys_info
time_zone::contant_offset() const
{
using date::year;
using date::sys_info;
using date::sys_days;
using date::January;
using date::December;
using date::last;
using date::days;
using std::chrono::minutes;
sys_info r;
r.begin = sys_days{year::min()/January/1};
r.end = sys_days{year::max()/December/last} + days{1} - std::chrono::seconds{1};
if (std_abbrev_.size() > 0)
{
r.abbrev = std_abbrev_;
r.offset = offset_;
r.save = {};
}
else
{
r.abbrev = dst_abbrev_;
r.offset = offset_ + save_;
r.save = date::ceil<minutes>(save_);
}
return r;
}
inline
time_zone::time_zone(const detail::string_t& s)
{
using detail::read_name;
using detail::read_signed_time;
using detail::throw_invalid;
auto i = read_name(s, 0, std_abbrev_);
auto std_name_i = i;
auto abbrev_name_i = i;
i = read_signed_time(s, i, offset_);
offset_ = -offset_;
if (i != s.size())
{
i = read_name(s, i, dst_abbrev_);
abbrev_name_i = i;
if (i != s.size())
{
if (s[i] != ',')
{
i = read_signed_time(s, i, save_);
save_ = -save_ - offset_;
}
if (i != s.size())
{
if (s[i] != ',')
throw_invalid(s, i, "Expecting end of string or ',' to start rule");
++i;
i = read_date(s, i, start_rule_);
if (i == s.size() || s[i] != ',')
throw_invalid(s, i, "Expecting ',' and then the ending rule");
++i;
i = read_date(s, i, end_rule_);
if (i != s.size())
throw_invalid(s, i, "Found unexpected trailing characters");
}
}
}
if (start_rule_.ok())
{
if (std_abbrev_.size() < 3)
throw_invalid(s, std_name_i, "Zone with rules must have a std"
" abbreviation of length 3 or greater");
if (dst_abbrev_.size() < 3)
throw_invalid(s, abbrev_name_i, "Zone with rules must have a daylight"
" abbreviation of length 3 or greater");
}
else
{
if (dst_abbrev_.size() >= 3)
{
std_abbrev_.clear();
}
else if (std_abbrev_.size() < 3)
{
throw_invalid(s, std_name_i, "Zone must have at least one abbreviation"
" of length 3 or greater");
}
else
{
dst_abbrev_.clear();
save_ = {};
}
}
}
template <class Duration>
date::sys_info
time_zone::get_info(date::sys_time<Duration> st) const
{
using date::sys_info;
using date::year_month_day;
using date::sys_days;
using date::floor;
using date::ceil;
using date::days;
using date::year;
using date::January;
using date::December;
using date::last;
using std::chrono::minutes;
sys_info r{};
r.offset = offset_;
if (start_rule_.ok())
{
auto y = year_month_day{floor<days>(st)}.year();
if (st >= get_next_start(y))
++y;
else if (st < get_prev_end(y))
--y;
auto start = get_start(y);
auto end = get_end(y);
if (start <= end) // (northern hemisphere)
{
if (start <= st && st < end)
{
r.begin = start;
r.end = end;
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
else if (st < start)
{
r.begin = get_prev_end(y);
r.end = start;
r.abbrev = std_abbrev_;
}
else // st >= end
{
r.begin = end;
r.end = get_next_start(y);
r.abbrev = std_abbrev_;
}
}
else // end < start (southern hemisphere)
{
if (end <= st && st < start)
{
r.begin = end;
r.end = start;
r.abbrev = std_abbrev_;
}
else if (st < end)
{
r.begin = get_prev_start(y);
r.end = end;
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
else // st >= start
{
r.begin = start;
r.end = get_next_end(y);
r.offset += save_;
r.save = ceil<minutes>(save_);
r.abbrev = dst_abbrev_;
}
}
}
else
r = contant_offset();
using seconds = std::chrono::seconds;
assert(r.begin <= floor<seconds>(st) && floor<seconds>(st) <= r.end);
return r;
}
template <class Duration>
date::local_info
time_zone::get_info(date::local_time<Duration> tp) const
{
using date::local_info;
using date::year_month_day;
using date::days;
using date::sys_days;
using date::sys_seconds;
using date::year;
using date::ceil;
using date::January;
using date::December;
using date::last;
using std::chrono::seconds;
using std::chrono::minutes;
local_info r{};
using date::floor;
if (start_rule_.ok())
{
auto y = year_month_day{floor<days>(tp)}.year();
auto start = get_start(y);
auto end = get_end(y);
auto utcs = sys_seconds{floor<seconds>(tp - offset_).time_since_epoch()};
auto utcd = sys_seconds{floor<seconds>(tp - (offset_ + save_)).time_since_epoch()};
auto northern = start <= end;
if ((utcs < start) != (utcd < start))
{
if (northern)
r.first.begin = get_prev_end(y);
else
r.first.begin = end;
r.first.end = start;
r.first.offset = offset_;
r.first.abbrev = std_abbrev_;
r.second.begin = start;
if (northern)
r.second.end = end;
else
r.second.end = get_next_end(y);
r.second.abbrev = dst_abbrev_;
r.second.offset = offset_ + save_;
r.second.save = ceil<minutes>(save_);
r.result = save_ > seconds{0} ? local_info::nonexistent
: local_info::ambiguous;
}
else if ((utcs < end) != (utcd < end))
{
if (northern)
r.first.begin = start;
else
r.first.begin = get_prev_start(y);
r.first.end = end;
r.first.offset = offset_ + save_;
r.first.save = ceil<minutes>(save_);
r.first.abbrev = dst_abbrev_;
r.second.begin = end;
if (northern)
r.second.end = get_next_start(y);
else
r.second.end = start;
r.second.abbrev = std_abbrev_;
r.second.offset = offset_;
r.result = save_ > seconds{0} ? local_info::ambiguous
: local_info::nonexistent;
}
else
r.first = get_info(utcs);
}
else
r.first = contant_offset();
return r;
}
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp) const
{
using date::local_info;
using date::sys_time;
using date::ambiguous_local_time;
using date::nonexistent_local_time;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
throw nonexistent_local_time(tp, i);
else if (i.result == local_info::ambiguous)
throw ambiguous_local_time(tp, i);
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
}
template <class Duration>
date::sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_sys(date::local_time<Duration> tp, date::choose z) const
{
using date::local_info;
using date::sys_time;
using date::choose;
auto i = get_info(tp);
if (i.result == local_info::nonexistent)
{
return i.first.end;
}
else if (i.result == local_info::ambiguous)
{
if (z == choose::latest)
return sys_time<Duration>{tp.time_since_epoch()} - i.second.offset;
}
return sys_time<Duration>{tp.time_since_epoch()} - i.first.offset;
}
template <class Duration>
date::local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
time_zone::to_local(date::sys_time<Duration> tp) const
{
using date::local_time;
using std::chrono::seconds;
using LT = local_time<typename std::common_type<Duration, seconds>::type>;
auto i = get_info(tp);
return LT{(tp + i.offset).time_since_epoch()};
}
inline
std::ostream&
operator<<(std::ostream& os, const time_zone& z)
{
using date::operator<<;
os << '{';
os << z.std_abbrev_ << ", " << z.dst_abbrev_ << date::format(", %T, ", z.offset_)
<< date::format("%T, [", z.save_) << z.start_rule_ << ", " << z.end_rule_ << ")}";
return os;
}
inline
std::string
time_zone::name() const
{
using namespace date;
using namespace std::chrono;
auto print_abbrev = [](std::string const& nm)
{
if (std::any_of(nm.begin(), nm.end(),
[](char c)
{
return !std::isalpha(c);
}))
{
return '<' + nm + '>';
}
return nm;
};
auto print_offset = [](seconds off)
{
std::string nm;
date::hh_mm_ss<seconds> offset{-off};
if (offset.is_negative())
nm += '-';
nm += std::to_string(offset.hours().count());
if (offset.minutes() != minutes{0} || offset.seconds() != seconds{0})
{
nm += ':';
if (offset.minutes() < minutes{10})
nm += '0';
nm += std::to_string(offset.minutes().count());
if (offset.seconds() != seconds{0})
{
nm += ':';
if (offset.seconds() < seconds{10})
nm += '0';
nm += std::to_string(offset.seconds().count());
}
}
return nm;
};
auto nm = print_abbrev(std_abbrev_);
nm += print_offset(offset_);
if (!dst_abbrev_.empty())
{
nm += print_abbrev(dst_abbrev_);
if (save_ != hours{1})
nm += print_offset(offset_+save_);
if (start_rule_.ok())
{
nm += ',';
nm += start_rule_.to_string();
nm += ',';
nm += end_rule_.to_string();
}
}
return nm;
}
inline
bool
operator==(const time_zone& x, const time_zone& y)
{
return x.std_abbrev_ == y.std_abbrev_ &&
x.dst_abbrev_ == y. dst_abbrev_ &&
x.offset_ == y.offset_ &&
x.save_ == y.save_ &&
x.start_rule_ == y.start_rule_ &&
x.end_rule_ == y.end_rule_;
}
inline
bool
operator!=(const time_zone& x, const time_zone& y)
{
return !(x == y);
}
namespace detail
{
inline
void
throw_invalid(const string_t& s, unsigned i, const string_t& message)
{
throw std::runtime_error(std::string("Invalid time_zone initializer.\n") +
std::string(message) + ":\n" +
std::string(s) + '\n' +
"\x1b[1;32m" +
std::string(i, '~') + '^' +
std::string(i < s.size() ? s.size()-i-1 : 0, '~') +
"\x1b[0m");
}
inline
unsigned
read_date(const string_t& s, unsigned i, rule& r)
{
using date::month;
using date::weekday;
if (i == s.size())
throw_invalid(s, i, "Expected rule but found end of string");
if (s[i] == 'J')
{
++i;
unsigned n;
i = read_unsigned(s, i, 3, n, "Expected to find the Julian day [1, 365]");
if (!(1 <= n && n <= 365))
throw_invalid(s, i-1, "Expected Julian day to be in the range [1, 365]");
r.mode_ = rule::J;
r.n_ = n;
}
else if (s[i] == 'M')
{
++i;
unsigned m;
i = read_unsigned(s, i, 2, m, "Expected to find month [1, 12]");
if (!(1 <= m && m <= 12))
throw_invalid(s, i-1, "Expected month to be in the range [1, 12]");
if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after month");
++i;
unsigned n;
i = read_unsigned(s, i, 1, n, "Expected to find week number [1, 5]");
if (!(1 <= n && n <= 5))
throw_invalid(s, i-1, "Expected week number to be in the range [1, 5]");
if (i == s.size() || s[i] != '.')
throw_invalid(s, i, "Expected '.' after weekday index");
++i;
unsigned wd;
i = read_unsigned(s, i, 1, wd, "Expected to find day of week [0, 6]");
if (wd > 6)
throw_invalid(s, i-1, "Expected day of week to be in the range [0, 6]");
r.mode_ = rule::M;
r.m_ = month{m};
r.wd_ = weekday{wd};
r.n_ = n;
}
else if (std::isdigit(s[i]))
{
unsigned n;
i = read_unsigned(s, i, 3, n);
if (n > 365)
throw_invalid(s, i-1, "Expected Julian day to be in the range [0, 365]");
r.mode_ = rule::N;
r.n_ = n;
}
else
throw_invalid(s, i, "Expected 'J', 'M', or a digit to start rule");
if (i != s.size() && s[i] == '/')
{
++i;
std::chrono::seconds t;
i = read_unsigned_time(s, i, t);
r.time_ = t;
}
return i;
}
inline
unsigned
read_name(const string_t& s, unsigned i, std::string& name)
{
if (i == s.size())
throw_invalid(s, i, "Expected a name but found end of string");
if (s[i] == '<')
{
++i;
while (true)
{
if (i == s.size())
throw_invalid(s, i,
"Expected to find closing '>', but found end of string");
if (s[i] == '>')
break;
name.push_back(s[i]);
++i;
}
++i;
}
else
{
while (i != s.size() && std::isalpha(s[i]))
{
name.push_back(s[i]);
++i;
}
}
return i;
}
inline
unsigned
read_signed_time(const string_t& s, unsigned i,
std::chrono::seconds& t)
{
if (i == s.size())
throw_invalid(s, i, "Expected to read signed time, but found end of string");
bool negative = false;
if (s[i] == '-')
{
negative = true;
++i;
}
else if (s[i] == '+')
++i;
i = read_unsigned_time(s, i, t);
if (negative)
t = -t;
return i;
}
inline
unsigned
read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t)
{
using std::chrono::seconds;
using std::chrono::minutes;
using std::chrono::hours;
if (i == s.size())
throw_invalid(s, i, "Expected to read unsigned time, but found end of string");
unsigned x;
i = read_unsigned(s, i, 2, x, "Expected to find hours [0, 24]");
if (x > 24)
throw_invalid(s, i-1, "Expected hours to be in the range [0, 24]");
t = hours{x};
if (i != s.size() && s[i] == ':')
{
++i;
i = read_unsigned(s, i, 2, x, "Expected to find minutes [0, 59]");
if (x > 59)
throw_invalid(s, i-1, "Expected minutes to be in the range [0, 59]");
t += minutes{x};
if (i != s.size() && s[i] == ':')
{
++i;
i = read_unsigned(s, i, 2, x, "Expected to find seconds [0, 59]");
if (x > 59)
throw_invalid(s, i-1, "Expected seconds to be in the range [0, 59]");
t += seconds{x};
}
}
return i;
}
inline
unsigned
read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u,
const string_t& message)
{
if (i == s.size() || !std::isdigit(s[i]))
throw_invalid(s, i, message);
u = static_cast<unsigned>(s[i] - '0');
unsigned count = 1;
for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count)
u = u * 10 + static_cast<unsigned>(s[i] - '0');
return i;
}
} // namespace detail
} // namespace Posix
namespace date
{
template <>
struct zoned_traits<Posix::time_zone>
{
#if HAS_STRING_VIEW
static
Posix::time_zone
locate_zone(std::string_view name)
{
return Posix::time_zone{name};
}
#else // !HAS_STRING_VIEW
static
Posix::time_zone
locate_zone(const std::string& name)
{
return Posix::time_zone{name};
}
static
Posix::time_zone
locate_zone(const char* name)
{
return Posix::time_zone{name};
}
#endif // !HAS_STRING_VIEW
};
} // namespace date
#endif // PTZ_H

File diff suppressed because it is too large Load Diff

View File

@ -83,9 +83,19 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"AddValue","Add item",{"key","value"},[dict0](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
std::string key;
std::string value;
if(GetArgument(args2,0,key) && GetArgument(args2,1,value))
int64_t i64;
double d64;
TDateTime da;
if(GetArgument(args2,0,key) )
{
dict0->AddValue(key,value);
if(GetArgument(args2,1,value))
dict0->AddValue(key,value);
else if(GetArgument(args2,1,i64))
dict0->AddValue(key,i64);
else if(GetArgument(args2,1,d64))
dict0->AddValue(key, d64);
else if(GetArgument(args2,1,da))
dict0->AddValue(key, da.GetDate());
}
return nullptr;
});
@ -93,9 +103,19 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"SetValue","Set item",{"key","value"},[dict0](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
std::string key;
std::string value;
if(GetArgument(args2,0,key) && GetArgument(args2,1,value))
int64_t i64;
double d64;
TDateTime da;
if(GetArgument(args2,0,key) )
{
dict0->SetValue(key,value);
if(GetArgument(args2,1,value))
dict0->SetValue(key,value);
else if(GetArgument(args2,1,i64))
dict0->SetValue(key,i64);
else if(GetArgument(args2,1,d64))
dict0->SetValue(key, d64);
else if(GetArgument(args2,1,da))
dict0->SetValue(key, da.GetDate());
}
return nullptr;
});
@ -140,6 +160,15 @@ namespace Tesses::CrossLang
}
return nullptr;
});
dict->DeclareFunction(gc,"TryGetFirstDate","Try Get first date",{"key"},[dict0](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
std::string key;
Tesses::Framework::Date::DateTime value;
if(GetArgument(args2,0,key) && dict0->TryGetFirstDate(key,value))
{
return value;
}
return nullptr;
});
dict->DeclareFunction(gc, "ToList","To List",{}, [dict0](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
TList* ls = TList::Create(ls2);
@ -205,6 +234,16 @@ namespace Tesses::CrossLang
dict->DeclareFunction(gc,"ReadString","Read string from request",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return ctx->ReadString();
});
dict->DeclareFunction(gc, "ReadJson","Read json from request",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
return Json_Decode(ls2,ctx->ReadString());
});
dict->DeclareFunction(gc,"SendJson","Send object as json",{"object"},[ctx](Tesses::CrossLang::GCList& ls2, std::vector<TObject> args2)->TObject{
if(args2.size() > 0)
{
ctx->WithMimeType("application/json").SendText(Json_Encode(args2[0]));
}
return nullptr;
});
dict->DeclareFunction(gc,"SendText","Send response text",{"text"},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string text;
@ -218,6 +257,12 @@ namespace Tesses::CrossLang
ctx->WithMimeType(text);
return dict;
});
dict->DeclareFunction(gc,"WithLastModified","Set last modified date",{"date"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
TDateTime da;
if(GetArgument(args2,0,da))
ctx->WithLastModified(da.GetDate());
return dict;
});
dict->DeclareFunction(gc,"WithContentDisposition","Set content disposition",{"filename","inline"},[ctx,dict](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
std::string filename;
bool isInline;
@ -491,6 +536,21 @@ namespace Tesses::CrossLang
}
return nullptr;
}
static TObject Net_Http_ListenOnUnusedPort(GCList& ls, std::vector<TObject> args)
{
if(args.size() > 0)
{
TObjectHttpServer httpServer(ls.GetGC(),args[0]);
uint16_t port=0;
HttpServer server(port,httpServer, false);
std::cout << "Port: " << server.GetPort() << std::endl;
server.StartAccepting();
Tesses::Framework::TF_RunEventLoop();
}
return nullptr;
}
static TObject Net_Http_MimeType(GCList& ls, std::vector<TObject> args)
{
Tesses::Framework::Filesystem::VFSPath p;
@ -818,6 +878,7 @@ namespace Tesses::CrossLang
});
http->DeclareFunction(gc, "MakeRequest", "Create an http request", {"url","$extra"}, Net_Http_MakeRequest);
http->DeclareFunction(gc, "ListenSimpleWithLoop", "Listen (creates application loop)", {"server","port"},Net_Http_ListenSimpleWithLoop);
http->DeclareFunction(gc, "ListenOnUnusedPort","Listen on unused localhost port and print Port: theport",{"server"},Net_Http_ListenOnUnusedPort);
//FileServer svr()
http->DeclareFunction(gc, "FileServer","Create a file server",{"path","allowlisting","spa"}, [](GCList& ls, std::vector<TObject> args)->TObject{
@ -842,6 +903,21 @@ namespace Tesses::CrossLang
});
dict->DeclareFunction(gc, "NetworkStream","Create a network stream",{"ipv6","datagram"},Net_NetworkStream);
smtp->DeclareFunction(gc, "Send","Send email via smtp server",{"messageStruct"},Net_Smtp_Send);
dict->DeclareFunction(gc, "getIPAddresses","Get the ip addresses of this machine",{"$ipv6"},[](GCList& ls, std::vector<TObject> args)->TObject{
TList* a = TList::Create(ls);
bool ipv6=false;
GetArgument(args,0,ipv6);
ls.GetGC()->BarrierBegin();
for(auto item : Tesses::Framework::Streams::NetworkStream::GetIPs(ipv6))
{
a->Add(TDictionary::Create(ls,{
TDItem("Interface", item.first),
TDItem("Address", item.second)
}));
}
ls.GetGC()->BarrierEnd();;
return a;
});
gc->BarrierBegin();
dict->SetValue("Http", http);
dict->SetValue("Smtp", smtp);

View File

@ -2,10 +2,28 @@
#if defined(CROSSLANG_ENABLE_SHARED)
#if defined(_WIN32)
#include <windows.h>
#include <time.h>
#undef min
#undef max
#else
#include <dlfcn.h>
#include <unistd.h>
#endif
#else
#if defined(_WIN32)
#include <windows.h>
#include <time.h>
#undef min
#undef max
#else
#include <unistd.h>
#endif
#endif
namespace Tesses::CrossLang
{
#if defined(CROSSLANG_ENABLE_SHARED)
@ -118,6 +136,13 @@ namespace Tesses::CrossLang
TVFSHeapObject* vfs;
return GetArgumentHeap(args,0,vfs);
}
static TObject TypeIsDateTime(GCList& ls, std::vector<TObject> args)
{
if(args.empty()) return nullptr;
TDateTime* dt;
return GetArgumentHeap(args,0,dt);
}
static TObject New_SubdirFilesystem(GCList& ls, std::vector<TObject> args)
{
TVFSHeapObject* vfsho;
@ -172,6 +197,38 @@ namespace Tesses::CrossLang
}
return nullptr;
}
static TObject New_DateTime(GCList& ls, std::vector<TObject> args)
{
int64_t year;
if(GetArgument(args,0,year))
{
if(args.size()==1)
{
Tesses::Framework::Date::DateTime dt(year);
return dt;
}
else
{
int64_t month=1;
int64_t day=1;
int64_t hour=0;
int64_t minute=0;
int64_t second=0;
bool isLocal=true;
GetArgument(args,1,month);
GetArgument(args,2,day);
GetArgument(args,3,hour);
GetArgument(args,4,minute);
GetArgument(args,5,second);
GetArgument(args,6,isLocal);
Tesses::Framework::Date::DateTime dt((int)year,(int)month,(int)day,(int)hour,(int)minute,(int)second,isLocal);
return dt;
}
}
return nullptr;
}
static TObject TypeOf(GCList& ls, std::vector<TObject> args)
{
@ -187,6 +244,7 @@ namespace Tesses::CrossLang
if(std::holds_alternative<std::string>(args[0])) return "String";
if(std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(args[0])) return "Path";
if(std::holds_alternative<TDateTime>(args[0])) return "DateTime";
if(std::holds_alternative<THeapObjectHolder>(args[0]))
{
auto obj = std::get<THeapObjectHolder>(args[0]).obj;
@ -207,6 +265,7 @@ namespace Tesses::CrossLang
auto rootEnv = dynamic_cast<TRootEnvironment*>(obj);
auto subEnv = dynamic_cast<TSubEnvironment*>(obj);
auto env = dynamic_cast<TEnvironment*>(obj);
if(rootEnv != nullptr) return "RootEnvironment";
if(subEnv != nullptr) return "SubEnvironment";
@ -390,13 +449,70 @@ namespace Tesses::CrossLang
return Undefined();
}
static TObject DateTime_Sleep(GCList& ls, std::vector<TObject> args)
{
int64_t msec;
if(GetArgument(args,0,msec))
{
#if defined(_WIN32)
Sleep((int)msec);
#else
usleep(1000*msec);
#endif
}
return nullptr;
}
static TObject DateTime_getNow(GCList& ls, std::vector<TObject> args)
{
return Tesses::Framework::Date::DateTime::Now();
}
static TObject DateTime_getNowUTC(GCList& ls, std::vector<TObject> args)
{
return Tesses::Framework::Date::DateTime::NowUTC();
}
static TObject DateTime_getNowEpoch(GCList& ls, std::vector<TObject> args)
{
return (int64_t)time(NULL);
}
static TObject DateTime_TryParseHttpDate(GCList& ls, std::vector<TObject> args)
{
std::string d;
Tesses::Framework::Date::DateTime dt;
if(GetArgument(args,0,d) && Tesses::Framework::Date::DateTime::TryParseHttpDate(d,dt))
{
return dt;
}
return nullptr;
}
void TStd::RegisterRoot(GC* gc, TRootEnvironment* env)
{
GCList ls(gc);
env->permissions.canRegisterRoot=true;
TDictionary* date = TDictionary::Create(ls);
date->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},DateTime_Sleep);
date->DeclareFunction(gc, "getNow", "Get the current time",{},DateTime_getNow);
date->DeclareFunction(gc, "getNowUTC","Get the current time in UTC",{},DateTime_getNowUTC);
date->DeclareFunction(gc, "getNowEpoch","Get the time_t time now",{},DateTime_getNowEpoch);
date->DeclareFunction(gc, "TryParseHttpDate","Parse the http date",{},DateTime_TryParseHttpDate);
gc->BarrierBegin();
date->SetValue("Zone", Tesses::Framework::Date::GetTimeZone());
date->SetValue("SupportsDaylightSavings",Tesses::Framework::Date::TimeZoneSupportDST());
env->DeclareVariable("DateTime", date);
gc->BarrierEnd();
TDictionary* newTypes = TDictionary::Create(ls);
newTypes->DeclareFunction(gc, "DateTime","Create a DateTime object, if only one arg is provided year is epoch, isLocal defaults to true unless epoch",{"year","$month","$day","$hour","$minute","$second","$isLocal"},New_DateTime);
newTypes->DeclareFunction(gc, "MountableFilesystem","Create a mountable filesystem",{"root"}, New_MountableFilesystem);
newTypes->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, New_SubdirFilesystem);
newTypes->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, New_MemoryStream);
@ -444,6 +560,7 @@ namespace Tesses::CrossLang
env->DeclareFunction(gc, "TypeIsList","Get whether object is a list or dynamic list",{"object"},TypeIsList);
env->DeclareFunction(gc, "TypeIsStream","Get whether object is a stream",{"object"},TypeIsStream);
env->DeclareFunction(gc, "TypeIsVFS","Get whether object is a virtual filesystem",{"object"},TypeIsVFS);
env->DeclareFunction(gc, "TypeIsDateTime","Get whether object is a DateTime",{"object"},TypeIsDateTime);
newTypes->DeclareFunction(gc, "Regex", "Create regex object",{"regex"},[](GCList& ls,std::vector<TObject> args)->TObject {
@ -569,7 +686,6 @@ namespace Tesses::CrossLang
RegisterCrypto(gc,env);
RegisterOGC(gc, env);
RegisterProcess(gc,env);
RegisterTime(gc, env);
gc->RegisterEverything(env);

View File

@ -1,248 +0,0 @@
#include "CrossLang.hpp"
#if defined(CROSSLANG_ENABLE_TIME)
#if defined(_WIN32)
#include <windows.h>
#include <time.h>
#undef min
#undef max
#else
#include <unistd.h>
#endif
#include "../HowardHinnant_date/date.h"
#endif
namespace Tesses::CrossLang
{
#if defined(CROSSLANG_ENABLE_TIME)
static int64_t ToLocalTime(int64_t local)
{
#if defined(__SWITCH__) || defined(_WIN32)
local -= _timezone;
if(_daylight)
#else
local -= timezone;
if(daylight)
#endif
{
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(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)
{
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
if(hms.hours().count() >= 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)
{
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
if(hms.hours().count() <=1) isDST=true;
}
}
}
if(isDST) local += 3600;
}
return local;
}
static TObject Time_getNow(GCList& ls, std::vector<TObject> args)
{
time_t t = time(NULL);
return (time_t)t;
}
static TObject Time_Sleep(GCList& ls, std::vector<TObject> args)
{
int64_t msec;
if(GetArgument(args,0,msec))
{
#if defined(_WIN32)
Sleep((int)msec);
#else
usleep(1000*msec);
#endif
}
return nullptr;
}
static TObject Time_LocalTime(GCList& ls, std::vector<TObject> args)
{
//THIS code isn't the best but should work
int64_t local;
if(GetArgument(args,0,local))
{
local = ToLocalTime(local);
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(local/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);
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Hour",hms.hours().count());
dict->SetValue("Minute",hms.minutes().count());
dict->SetValue("Second",hms.seconds().count());
dict->SetValue("Day",(int64_t)(uint32_t)ymd.day());
dict->SetValue("Month",(int64_t)(uint32_t)ymd.month());
dict->SetValue("Year",(int64_t)(int32_t)ymd.year());
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
static TObject Time_LocalUsSlashDate(GCList& ls, std::vector<TObject> args)
{
//THIS code isn't the best but should work
int64_t local;
if(GetArgument(args,0,local))
{
local = ToLocalTime(local);
std::chrono::duration<int64_t> local_epoch_time(local);
date::hh_mm_ss hms(local_epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(local/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);
return std::to_string((uint32_t)ymd.month()) + "/" + std::to_string((uint32_t)ymd.day()) + "/" + std::to_string((int)ymd.year());
}
return "";
}
static TObject Time_UTCUsSlashDate(GCList& ls,std::vector<TObject> args)
{
int64_t gmt;
if(GetArgument(args,0,gmt))
{
std::chrono::duration<int64_t> epoch_time(gmt);
date::hh_mm_ss hms(epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(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);
return std::to_string((uint32_t)ymd.month()) + "/" + std::to_string((uint32_t)ymd.day()) + "/" + std::to_string((int)ymd.year());
}
return "";
}
static TObject Time_GMTTime(GCList& ls, std::vector<TObject> args)
{
int64_t gmt;
if(GetArgument(args,0,gmt))
{
std::chrono::duration<int64_t> epoch_time(gmt);
date::hh_mm_ss hms(epoch_time%86400);
auto epoch = date::sys_days{date::January/1/1970};
epoch += date::days(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);
TDictionary* dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("Hour",hms.hours().count());
dict->SetValue("Minute",hms.minutes().count());
dict->SetValue("Second",hms.seconds().count());
dict->SetValue("Day",(int64_t)(uint32_t)ymd.day());
dict->SetValue("Month",(int64_t)(uint32_t)ymd.month());
dict->SetValue("Year",(int64_t)(int32_t)ymd.year());
ls.GetGC()->BarrierEnd();
return dict;
}
return nullptr;
}
#endif
void TStd::RegisterTime(GC* gc,TRootEnvironment* env)
{
#if defined(CROSSLANG_ENABLE_TIME)
env->permissions.canRegisterTime=true;
GCList ls(gc);
TDictionary* dict = TDictionary::Create(ls);
dict->DeclareFunction(gc, "GetLocalTime", "Get local time from epoch value",{"epoch"},Time_LocalTime);
dict->DeclareFunction(gc, "GetGMTTime","Get the GMT time from epoch value",{"epoch"},Time_GMTTime);
dict->DeclareFunction(gc, "getNow","Get the time right now, returns C's time(NULL) return value",{},Time_getNow);
dict->DeclareFunction(gc, "Sleep","Sleep for a specified amount of milliseconds (multiply seconds by 1000 to get milliseconds)", {"ms"},Time_Sleep);
dict->DeclareFunction(gc, "UTCUsSlashDate","Get a utc date like 8/20/1992 from epoch value",{"epoch"},Time_UTCUsSlashDate);
dict->DeclareFunction(gc, "LocalUsSlashDate","Get a local date like 8/20/1992 from epoch value",{"epoch"},Time_LocalUsSlashDate);
gc->BarrierBegin();
#if defined(__SWITCH__) || defined(_WIN32)
dict->SetValue("Zone", (int64_t)-(_timezone));
dict->SetValue("SupportsDaylightSavings",(int64_t)_daylight);
#else
dict->SetValue("Zone", (int64_t)-(timezone));
dict->SetValue("SupportsDaylightSavings",(int64_t)daylight);
#endif
env->DeclareVariable("Time", dict);
gc->BarrierEnd();
#endif
}
}

23
src/types/datetime.cpp Normal file
View File

@ -0,0 +1,23 @@
#include "CrossLang.hpp"
namespace Tesses::CrossLang {
TDateTime::TDateTime()
{
this->dt=new Tesses::Framework::Date::DateTime();
}
TDateTime::TDateTime(Tesses::Framework::Date::DateTime t)
{
this->dt = new Tesses::Framework::Date::DateTime(t);
}
TDateTime::TDateTime(const TDateTime& dt)
{
this->dt = new Tesses::Framework::Date::DateTime(*dt.dt);
}
Tesses::Framework::Date::DateTime& TDateTime::GetDate()
{
return *this->dt;
}
TDateTime::~TDateTime()
{
delete this->dt;
}
}

View File

@ -556,7 +556,7 @@ namespace Tesses::CrossLang {
}
return Tesses::Framework::Filesystem::VFSPath();
}
void TObjectVFS::GetDate(Tesses::Framework::Filesystem::VFSPath path, time_t& lastWrite, time_t& lastAccess)
void TObjectVFS::GetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime& lastWrite, Tesses::Framework::Date::DateTime& lastAccess)
{
TVFSHeapObject* vfs;
@ -573,17 +573,20 @@ namespace Tesses::CrossLang {
{
this->ls->GetGC()->BarrierBegin();
res = dict->GetValue("LastWrite");
int64_t v;
if(GetObject(res,v)) lastWrite=(time_t)v;
TDateTime d;
if(GetObject(res,d))
lastWrite =d.GetDate();
res = dict->GetValue("LastAccess");
if(GetObject(res,v)) lastAccess=(time_t)v;
if(GetObject(res,d))
lastWrite =d.GetDate();
this->ls->GetGC()->BarrierEnd();
}
}
}
void TObjectVFS::SetDate(Tesses::Framework::Filesystem::VFSPath path, time_t lastWrite, time_t lastAccess)
void TObjectVFS::SetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime lastWrite, Tesses::Framework::Date::DateTime lastAccess)
{
TVFSHeapObject* vfs;
@ -595,7 +598,7 @@ namespace Tesses::CrossLang {
if(GetObjectHeap(this->obj, dict))
{
GCList ls(this->ls->GetGC());
dict->CallMethod(ls, "SetDate",{path,(int64_t)lastWrite,(int64_t)lastAccess});
dict->CallMethod(ls, "SetDate",{path,lastWrite,lastAccess});
}
}

View File

@ -42,6 +42,12 @@ namespace Tesses::CrossLang {
{
return std::get<char>(obj) != 0;
}
else if(std::holds_alternative<TDateTime>(obj))
{
auto& dt = std::get<TDateTime>(obj).GetDate();
return !(dt.Year() == 1970 && dt.Month() == 1 && dt.Day() == 1 && dt.Hour() == 0 && dt.Minute() == 0 && dt.Second() == 0 && !dt.IsLocal());
}
else if(std::holds_alternative<THeapObjectHolder>(obj))
{
auto o = std::get<THeapObjectHolder>(obj).obj;
@ -50,6 +56,8 @@ namespace Tesses::CrossLang {
auto ba = dynamic_cast<TByteArray*>(o);
auto nat = dynamic_cast<TNative*>(o);
auto thrd = dynamic_cast<ThreadHandle*>(o);
auto dt = dynamic_cast<TDateTime*>(o);
if(ls != nullptr)
{
return ls->Count() != 0;
@ -72,7 +80,7 @@ namespace Tesses::CrossLang {
}
return true;
}
return false;
}
@ -130,6 +138,10 @@ namespace Tesses::CrossLang {
{
return std::get<int64_t>(left) == std::get<char>(right);
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
return std::get<TDateTime>(left).GetDate().ToEpoch() == std::get<TDateTime>(right).GetDate().ToEpoch();
}
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
{
auto lver= std::get<TVMVersion>(left);
@ -692,6 +704,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator!",{}));
return false;
}
else
{
cse.back()->Push(gc, !ToBool(left));
@ -796,12 +809,17 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc, std::get<std::string>(left) < std::get<std::string>(right));
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() < std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -875,12 +893,17 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc, std::get<std::string>(left) > std::get<std::string>(right));
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() > std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -953,12 +976,17 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc, std::get<std::string>(left) <= std::get<std::string>(right));
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() <= std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -971,6 +999,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator<=",{right}));
return false;
}
else
{
cse.back()->Push(gc,Undefined());
@ -1032,12 +1061,17 @@ namespace Tesses::CrossLang {
{
cse.back()->Push(gc, std::get<std::string>(left) >= std::get<std::string>(right));
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() >= std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -1050,6 +1084,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator>=",{right}));
return false;
}
else
{
cse.back()->Push(gc,Undefined());
@ -1128,6 +1163,10 @@ namespace Tesses::CrossLang {
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r == 0);
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() == std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -1135,6 +1174,8 @@ namespace Tesses::CrossLang {
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
auto native = dynamic_cast<TNative*>(obj);
if(dict != nullptr)
{
gc->BarrierBegin();
@ -1154,6 +1195,7 @@ namespace Tesses::CrossLang {
return false;
}
}
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
cse.back()->Push(gc, native->GetDestroyed());
return false;
@ -1260,6 +1302,10 @@ namespace Tesses::CrossLang {
auto r = lver.CompareTo(rver);
cse.back()->Push(gc, r != 0);
}
else if(std::holds_alternative<TDateTime>(left) && std::holds_alternative<TDateTime>(right))
{
cse.back()->Push(gc, std::get<TDateTime>(left).GetDate().ToEpoch() != std::get<TDateTime>(right).GetDate().ToEpoch());
}
else if(std::holds_alternative<THeapObjectHolder>(left))
{
auto obj = std::get<THeapObjectHolder>(left).obj;
@ -1286,6 +1332,7 @@ namespace Tesses::CrossLang {
return false;
}
}
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
cse.back()->Push(gc, !native->GetDestroyed());
return false;
@ -2369,14 +2416,7 @@ namespace Tesses::CrossLang {
std::string _str={};
if(GetArgument(args,0,oldStr) && GetArgument(args,1,newStr))
{
bool first=true;
for(auto txt : Tesses::Framework::Http::HttpUtils::SplitString(str,oldStr))
{
if(!first) _str.append(newStr);
first=false;
_str.append(txt);
}
_str = Tesses::Framework::Http::HttpUtils::Replace(str, oldStr,newStr);
}
@ -2449,6 +2489,48 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, Undefined());
return false;
}
else if(std::holds_alternative<TDateTime>(instance))
{
auto& date = std::get<TDateTime>(instance).GetDate();
if(key == "ToString")
{
std::string fmt;
if(GetArgument(args,0,fmt))
{
cse.back()->Push(gc, date.ToString(fmt));
}
else
{
cse.back()->Push(gc, date.ToString());
}
return false;
}
if(key == "ToHttpDate")
{
cse.back()->Push(gc, date.ToHttpDate());
return false;
}
if(key == "ToEpoch")
{
cse.back()->Push(gc, date.ToEpoch());
return false;
}
if(key == "ToLocal")
{
cse.back()->Push(gc, date.ToLocal());
return false;
}
if(key == "ToUTC")
{
cse.back()->Push(gc, date.ToUTC());
return false;
}
cse.back()->Push(gc, nullptr);
return false;
}
else if(std::holds_alternative<THeapObjectHolder>(instance))
{
auto obj = std::get<THeapObjectHolder>(instance).obj;
@ -2465,6 +2547,7 @@ namespace Tesses::CrossLang {
auto callable = dynamic_cast<TCallable*>(obj);
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
auto svr = dynamic_cast<TServerHeapObject*>(obj);
if(callstackEntry != nullptr)
@ -2721,13 +2804,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc,nullptr);
return false;
}
if(key == "RegisterTime")
{
if((myEnv->permissions.canRegisterEverything || myEnv->permissions.canRegisterTime) && !rootEnv->permissions.locked)
TStd::RegisterTime(gc, rootEnv);
cse.back()->Push(gc,nullptr);
return false;
}
if(key == "SetSqliteRoot")
{
Tesses::Framework::Filesystem::VFSPath p;
@ -2974,11 +3051,11 @@ namespace Tesses::CrossLang {
if(key == "SetDate")
{
Tesses::Framework::Filesystem::VFSPath path;
int64_t lastWrite;
int64_t lastAccess;
TDateTime lastWrite;
TDateTime lastAccess;
if(GetArgumentAsPath(args,0,path) && GetArgument(args,1,lastWrite) && GetArgument(args,2,lastAccess))
{
vfs->vfs->SetDate(path,(time_t)lastWrite,(time_t)lastAccess);
vfs->vfs->SetDate(path,lastWrite.GetDate(), lastAccess.GetDate());
}
cse.back()->Push(gc, nullptr);
return false;
@ -2988,13 +3065,15 @@ namespace Tesses::CrossLang {
Tesses::Framework::Filesystem::VFSPath path;
if(GetArgumentAsPath(args,0,path))
{
time_t lastWrite;
time_t lastAccess;
Tesses::Framework::Date::DateTime lastWrite;
Tesses::Framework::Date::DateTime lastAccess;
vfs->vfs->GetDate(path,lastWrite,lastAccess);
auto dict = TDictionary::Create(ls);
ls.GetGC()->BarrierBegin();
dict->SetValue("LastWrite", (int64_t)lastWrite);
dict->SetValue("LastAccess", (int64_t)lastAccess);
dict->SetValue("LastWrite", TDateTime(lastWrite));
dict->SetValue("LastAccess", TDateTime(lastAccess));
ls.GetGC()->BarrierEnd();
cse.back()->Push(gc, dict);
@ -3244,6 +3323,7 @@ namespace Tesses::CrossLang {
{
auto memStrm = dynamic_cast<Tesses::Framework::Streams::MemoryStream*>(strm->stream);
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
auto mystrm = dynamic_cast<TObjectStream*>(strm->stream);
if(mystrm != nullptr)
@ -3271,6 +3351,11 @@ namespace Tesses::CrossLang {
}
if(netStrm != nullptr)
{
if(key == "GetPort")
{
cse.back()->Push(gc, netStrm->GetPort());
return false;
}
if(key == "Bind")
{
std::string ip;
@ -3522,6 +3607,7 @@ namespace Tesses::CrossLang {
cse.back()->Push(gc, nullptr);
return false;
}
else if(bArray != nullptr)
{
if(key == "Count" || key == "Length")
@ -4098,6 +4184,53 @@ namespace Tesses::CrossLang {
stk->Push(gc, Undefined());
return false;
}
if(std::holds_alternative<TDateTime>(instance))
{
auto& date = std::get<TDateTime>(instance).GetDate();
if(key == "IsLocal")
{
stk->Push(gc, date.IsLocal());
return false;
}
if(key == "Year")
{
stk->Push(gc, (int64_t)date.Year());
return false;
}
if(key == "Month")
{
stk->Push(gc, (int64_t)date.Month());
return false;
}
if(key == "Day")
{
stk->Push(gc, (int64_t)date.Day());
return false;
}
if(key == "Hour")
{
stk->Push(gc, (int64_t)date.Hour());
return false;
}
if(key == "Minute")
{
stk->Push(gc, (int64_t)date.Minute());
return false;
}
if(key == "Second")
{
stk->Push(gc, (int64_t)date.Second());
return false;
}
if(key == "DayOfWeek")
{
stk->Push(gc, (int64_t)date.DayOfWeek());
return false;
}
stk->Push(gc, Undefined());
return false;
}
if(std::holds_alternative<THeapObjectHolder>(instance))
{
auto obj = std::get<THeapObjectHolder>(instance).obj;
@ -5791,13 +5924,17 @@ namespace Tesses::CrossLang {
{
return std::get<bool>(o) ? "true" : "false";
}
if(std::holds_alternative<TDateTime>(o))
{
return std::get<TDateTime>(o).GetDate().ToString();
}
if(std::holds_alternative<THeapObjectHolder>(o))
{
auto obj = std::get<THeapObjectHolder>(o).obj;
auto dict = dynamic_cast<TDictionary*>(obj);
auto list = dynamic_cast<TList*>(obj);
auto bArray = dynamic_cast<TByteArray*>(obj);
if(dict != nullptr)
{
GCList ls(gc);