Move date to tessesframework
This commit is contained in:
@ -124,7 +124,7 @@ src/runtime_methods/ogc.cpp
|
|||||||
src/runtime_methods/path.cpp
|
src/runtime_methods/path.cpp
|
||||||
src/runtime_methods/env.cpp
|
src/runtime_methods/env.cpp
|
||||||
src/runtime_methods/process.cpp
|
src/runtime_methods/process.cpp
|
||||||
src/runtime_methods/time.cpp
|
src/types/datetime.cpp
|
||||||
src/types/ittr.cpp
|
src/types/ittr.cpp
|
||||||
src/types/closure.cpp
|
src/types/closure.cpp
|
||||||
src/types/dictionary.cpp
|
src/types/dictionary.cpp
|
||||||
|
|||||||
@ -1348,11 +1348,21 @@ class Parser {
|
|||||||
class MethodInvoker {
|
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
|
* @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 TRootEnvironment;
|
||||||
class GC;
|
class GC;
|
||||||
class GC {
|
class GC {
|
||||||
@ -1500,7 +1510,6 @@ class GC {
|
|||||||
|
|
||||||
};
|
};
|
||||||
using TDItem = std::pair<std::string, TObject>;
|
using TDItem = std::pair<std::string, TObject>;
|
||||||
|
|
||||||
class TDictionary : public THeapObject
|
class TDictionary : public THeapObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -1609,7 +1618,6 @@ class GC {
|
|||||||
bool canRegisterPath;
|
bool canRegisterPath;
|
||||||
bool canRegisterOGC;
|
bool canRegisterOGC;
|
||||||
bool canRegisterEnv;
|
bool canRegisterEnv;
|
||||||
bool canRegisterTime;
|
|
||||||
bool sqlite3Scoped;
|
bool sqlite3Scoped;
|
||||||
bool locked;
|
bool locked;
|
||||||
};
|
};
|
||||||
@ -1660,7 +1668,6 @@ class GC {
|
|||||||
static void RegisterOGC(GC* gc, TRootEnvironment* env);
|
static void RegisterOGC(GC* gc, TRootEnvironment* env);
|
||||||
static void RegisterEnv(GC* gc, TRootEnvironment* env);
|
static void RegisterEnv(GC* gc, TRootEnvironment* env);
|
||||||
static void RegisterProcess(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);
|
Tesses::Framework::Filesystem::VFSPath ReadLink(Tesses::Framework::Filesystem::VFSPath path);
|
||||||
std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path);
|
std::string VFSPathToSystem(Tesses::Framework::Filesystem::VFSPath path);
|
||||||
Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path);
|
Tesses::Framework::Filesystem::VFSPath SystemToVFSPath(std::string path);
|
||||||
void GetDate(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, time_t lastWrite, time_t lastAccess);
|
void SetDate(Tesses::Framework::Filesystem::VFSPath path, Tesses::Framework::Date::DateTime lastWrite, Tesses::Framework::Date::DateTime lastAccess);
|
||||||
~TObjectVFS();
|
~TObjectVFS();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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
@ -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
@ -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
@ -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 {
|
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 key;
|
||||||
std::string value;
|
std::string value;
|
||||||
if(GetArgument(args2,0,key) && GetArgument(args2,1,value))
|
int64_t i64;
|
||||||
|
double d64;
|
||||||
|
TDateTime da;
|
||||||
|
if(GetArgument(args2,0,key) )
|
||||||
{
|
{
|
||||||
|
if(GetArgument(args2,1,value))
|
||||||
dict0->AddValue(key,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;
|
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 {
|
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 key;
|
||||||
std::string value;
|
std::string value;
|
||||||
if(GetArgument(args2,0,key) && GetArgument(args2,1,value))
|
int64_t i64;
|
||||||
|
double d64;
|
||||||
|
TDateTime da;
|
||||||
|
if(GetArgument(args2,0,key) )
|
||||||
{
|
{
|
||||||
|
if(GetArgument(args2,1,value))
|
||||||
dict0->SetValue(key,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;
|
return nullptr;
|
||||||
});
|
});
|
||||||
@ -140,6 +160,15 @@ namespace Tesses::CrossLang
|
|||||||
}
|
}
|
||||||
return nullptr;
|
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 {
|
dict->DeclareFunction(gc, "ToList","To List",{}, [dict0](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject {
|
||||||
TList* ls = TList::Create(ls2);
|
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{
|
dict->DeclareFunction(gc,"ReadString","Read string from request",{},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
|
||||||
return ctx->ReadString();
|
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{
|
dict->DeclareFunction(gc,"SendText","Send response text",{"text"},[ctx](Tesses::CrossLang::GCList &ls2, std::vector<Tesses::CrossLang::TObject> args2)->TObject{
|
||||||
std::string text;
|
std::string text;
|
||||||
@ -218,6 +257,12 @@ namespace Tesses::CrossLang
|
|||||||
ctx->WithMimeType(text);
|
ctx->WithMimeType(text);
|
||||||
return dict;
|
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{
|
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;
|
std::string filename;
|
||||||
bool isInline;
|
bool isInline;
|
||||||
@ -491,6 +536,21 @@ namespace Tesses::CrossLang
|
|||||||
}
|
}
|
||||||
return nullptr;
|
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)
|
static TObject Net_Http_MimeType(GCList& ls, std::vector<TObject> args)
|
||||||
{
|
{
|
||||||
Tesses::Framework::Filesystem::VFSPath p;
|
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, "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, "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()
|
//FileServer svr()
|
||||||
http->DeclareFunction(gc, "FileServer","Create a file server",{"path","allowlisting","spa"}, [](GCList& ls, std::vector<TObject> args)->TObject{
|
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);
|
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);
|
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();
|
gc->BarrierBegin();
|
||||||
dict->SetValue("Http", http);
|
dict->SetValue("Http", http);
|
||||||
dict->SetValue("Smtp", smtp);
|
dict->SetValue("Smtp", smtp);
|
||||||
|
|||||||
@ -2,10 +2,28 @@
|
|||||||
#if defined(CROSSLANG_ENABLE_SHARED)
|
#if defined(CROSSLANG_ENABLE_SHARED)
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
#else
|
#else
|
||||||
#include <dlfcn.h>
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Tesses::CrossLang
|
namespace Tesses::CrossLang
|
||||||
{
|
{
|
||||||
#if defined(CROSSLANG_ENABLE_SHARED)
|
#if defined(CROSSLANG_ENABLE_SHARED)
|
||||||
@ -118,6 +136,13 @@ namespace Tesses::CrossLang
|
|||||||
TVFSHeapObject* vfs;
|
TVFSHeapObject* vfs;
|
||||||
return GetArgumentHeap(args,0,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)
|
static TObject New_SubdirFilesystem(GCList& ls, std::vector<TObject> args)
|
||||||
{
|
{
|
||||||
TVFSHeapObject* vfsho;
|
TVFSHeapObject* vfsho;
|
||||||
@ -172,6 +197,38 @@ namespace Tesses::CrossLang
|
|||||||
}
|
}
|
||||||
return nullptr;
|
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)
|
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<std::string>(args[0])) return "String";
|
||||||
|
|
||||||
if(std::holds_alternative<Tesses::Framework::Filesystem::VFSPath>(args[0])) return "Path";
|
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]))
|
if(std::holds_alternative<THeapObjectHolder>(args[0]))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(args[0]).obj;
|
auto obj = std::get<THeapObjectHolder>(args[0]).obj;
|
||||||
@ -208,6 +266,7 @@ namespace Tesses::CrossLang
|
|||||||
auto subEnv = dynamic_cast<TSubEnvironment*>(obj);
|
auto subEnv = dynamic_cast<TSubEnvironment*>(obj);
|
||||||
auto env = dynamic_cast<TEnvironment*>(obj);
|
auto env = dynamic_cast<TEnvironment*>(obj);
|
||||||
|
|
||||||
|
|
||||||
if(rootEnv != nullptr) return "RootEnvironment";
|
if(rootEnv != nullptr) return "RootEnvironment";
|
||||||
if(subEnv != nullptr) return "SubEnvironment";
|
if(subEnv != nullptr) return "SubEnvironment";
|
||||||
if(env != nullptr) return "Environment";
|
if(env != nullptr) return "Environment";
|
||||||
@ -390,13 +449,70 @@ namespace Tesses::CrossLang
|
|||||||
return Undefined();
|
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)
|
void TStd::RegisterRoot(GC* gc, TRootEnvironment* env)
|
||||||
{
|
{
|
||||||
GCList ls(gc);
|
GCList ls(gc);
|
||||||
|
|
||||||
env->permissions.canRegisterRoot=true;
|
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);
|
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, "MountableFilesystem","Create a mountable filesystem",{"root"}, New_MountableFilesystem);
|
||||||
newTypes->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, New_SubdirFilesystem);
|
newTypes->DeclareFunction(gc, "SubdirFilesystem","Create a subdir filesystem",{"fs","subdir"}, New_SubdirFilesystem);
|
||||||
newTypes->DeclareFunction(gc, "MemoryStream","Create a memory stream",{"writable"}, New_MemoryStream);
|
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, "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, "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, "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 {
|
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);
|
RegisterCrypto(gc,env);
|
||||||
RegisterOGC(gc, env);
|
RegisterOGC(gc, env);
|
||||||
RegisterProcess(gc,env);
|
RegisterProcess(gc,env);
|
||||||
RegisterTime(gc, env);
|
|
||||||
|
|
||||||
gc->RegisterEverything(env);
|
gc->RegisterEverything(env);
|
||||||
|
|
||||||
|
|||||||
@ -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
23
src/types/datetime.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -556,7 +556,7 @@ namespace Tesses::CrossLang {
|
|||||||
}
|
}
|
||||||
return Tesses::Framework::Filesystem::VFSPath();
|
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;
|
TVFSHeapObject* vfs;
|
||||||
@ -573,17 +573,20 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
this->ls->GetGC()->BarrierBegin();
|
this->ls->GetGC()->BarrierBegin();
|
||||||
res = dict->GetValue("LastWrite");
|
res = dict->GetValue("LastWrite");
|
||||||
int64_t v;
|
TDateTime d;
|
||||||
if(GetObject(res,v)) lastWrite=(time_t)v;
|
if(GetObject(res,d))
|
||||||
|
lastWrite =d.GetDate();
|
||||||
|
|
||||||
res = dict->GetValue("LastAccess");
|
res = dict->GetValue("LastAccess");
|
||||||
if(GetObject(res,v)) lastAccess=(time_t)v;
|
|
||||||
|
if(GetObject(res,d))
|
||||||
|
lastWrite =d.GetDate();
|
||||||
|
|
||||||
this->ls->GetGC()->BarrierEnd();
|
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;
|
TVFSHeapObject* vfs;
|
||||||
@ -595,7 +598,7 @@ namespace Tesses::CrossLang {
|
|||||||
if(GetObjectHeap(this->obj, dict))
|
if(GetObjectHeap(this->obj, dict))
|
||||||
{
|
{
|
||||||
GCList ls(this->ls->GetGC());
|
GCList ls(this->ls->GetGC());
|
||||||
dict->CallMethod(ls, "SetDate",{path,(int64_t)lastWrite,(int64_t)lastAccess});
|
dict->CallMethod(ls, "SetDate",{path,lastWrite,lastAccess});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
183
src/vm/vm.cpp
183
src/vm/vm.cpp
@ -42,6 +42,12 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
return std::get<char>(obj) != 0;
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(obj))
|
||||||
{
|
{
|
||||||
auto o = std::get<THeapObjectHolder>(obj).obj;
|
auto o = std::get<THeapObjectHolder>(obj).obj;
|
||||||
@ -50,6 +56,8 @@ namespace Tesses::CrossLang {
|
|||||||
auto ba = dynamic_cast<TByteArray*>(o);
|
auto ba = dynamic_cast<TByteArray*>(o);
|
||||||
auto nat = dynamic_cast<TNative*>(o);
|
auto nat = dynamic_cast<TNative*>(o);
|
||||||
auto thrd = dynamic_cast<ThreadHandle*>(o);
|
auto thrd = dynamic_cast<ThreadHandle*>(o);
|
||||||
|
auto dt = dynamic_cast<TDateTime*>(o);
|
||||||
|
|
||||||
if(ls != nullptr)
|
if(ls != nullptr)
|
||||||
{
|
{
|
||||||
return ls->Count() != 0;
|
return ls->Count() != 0;
|
||||||
@ -130,6 +138,10 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
return std::get<int64_t>(left) == std::get<char>(right);
|
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))
|
else if(std::holds_alternative<TVMVersion>(left) && std::holds_alternative<TVMVersion>(right))
|
||||||
{
|
{
|
||||||
auto lver= std::get<TVMVersion>(left);
|
auto lver= std::get<TVMVersion>(left);
|
||||||
@ -692,6 +704,7 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator!",{}));
|
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator!",{}));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cse.back()->Push(gc, !ToBool(left));
|
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));
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
auto dict = dynamic_cast<TDictionary*>(obj);
|
auto dict = dynamic_cast<TDictionary*>(obj);
|
||||||
|
|
||||||
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
gc->BarrierBegin();
|
gc->BarrierBegin();
|
||||||
@ -875,12 +893,17 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
cse.back()->Push(gc, std::get<std::string>(left) > std::get<std::string>(right));
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
auto dict = dynamic_cast<TDictionary*>(obj);
|
auto dict = dynamic_cast<TDictionary*>(obj);
|
||||||
|
|
||||||
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
gc->BarrierBegin();
|
gc->BarrierBegin();
|
||||||
@ -953,12 +976,17 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
cse.back()->Push(gc, std::get<std::string>(left) <= std::get<std::string>(right));
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
auto dict = dynamic_cast<TDictionary*>(obj);
|
auto dict = dynamic_cast<TDictionary*>(obj);
|
||||||
|
|
||||||
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
gc->BarrierBegin();
|
gc->BarrierBegin();
|
||||||
@ -971,6 +999,7 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator<=",{right}));
|
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator<=",{right}));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cse.back()->Push(gc,Undefined());
|
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));
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
auto dict = dynamic_cast<TDictionary*>(obj);
|
auto dict = dynamic_cast<TDictionary*>(obj);
|
||||||
|
|
||||||
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
gc->BarrierBegin();
|
gc->BarrierBegin();
|
||||||
@ -1050,6 +1084,7 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator>=",{right}));
|
cse.back()->Push(gc,dynDict->CallMethod(ls,"operator>=",{right}));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cse.back()->Push(gc,Undefined());
|
cse.back()->Push(gc,Undefined());
|
||||||
@ -1128,6 +1163,10 @@ namespace Tesses::CrossLang {
|
|||||||
auto r = lver.CompareTo(rver);
|
auto r = lver.CompareTo(rver);
|
||||||
cse.back()->Push(gc, r == 0);
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
@ -1135,6 +1174,8 @@ namespace Tesses::CrossLang {
|
|||||||
|
|
||||||
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
auto dynDict = dynamic_cast<TDynamicDictionary*>(obj);
|
||||||
auto native = dynamic_cast<TNative*>(obj);
|
auto native = dynamic_cast<TNative*>(obj);
|
||||||
|
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
gc->BarrierBegin();
|
gc->BarrierBegin();
|
||||||
@ -1154,6 +1195,7 @@ namespace Tesses::CrossLang {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
|
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
|
||||||
cse.back()->Push(gc, native->GetDestroyed());
|
cse.back()->Push(gc, native->GetDestroyed());
|
||||||
return false;
|
return false;
|
||||||
@ -1260,6 +1302,10 @@ namespace Tesses::CrossLang {
|
|||||||
auto r = lver.CompareTo(rver);
|
auto r = lver.CompareTo(rver);
|
||||||
cse.back()->Push(gc, r != 0);
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(left))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(left).obj;
|
auto obj = std::get<THeapObjectHolder>(left).obj;
|
||||||
@ -1286,6 +1332,7 @@ namespace Tesses::CrossLang {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
|
else if(native != nullptr && std::holds_alternative<std::nullptr_t>(right)){
|
||||||
cse.back()->Push(gc, !native->GetDestroyed());
|
cse.back()->Push(gc, !native->GetDestroyed());
|
||||||
return false;
|
return false;
|
||||||
@ -2369,14 +2416,7 @@ namespace Tesses::CrossLang {
|
|||||||
std::string _str={};
|
std::string _str={};
|
||||||
if(GetArgument(args,0,oldStr) && GetArgument(args,1,newStr))
|
if(GetArgument(args,0,oldStr) && GetArgument(args,1,newStr))
|
||||||
{
|
{
|
||||||
bool first=true;
|
_str = Tesses::Framework::Http::HttpUtils::Replace(str, oldStr,newStr);
|
||||||
|
|
||||||
for(auto txt : Tesses::Framework::Http::HttpUtils::SplitString(str,oldStr))
|
|
||||||
{
|
|
||||||
if(!first) _str.append(newStr);
|
|
||||||
first=false;
|
|
||||||
_str.append(txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2449,6 +2489,48 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc, Undefined());
|
cse.back()->Push(gc, Undefined());
|
||||||
return false;
|
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))
|
else if(std::holds_alternative<THeapObjectHolder>(instance))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(instance).obj;
|
auto obj = std::get<THeapObjectHolder>(instance).obj;
|
||||||
@ -2465,6 +2547,7 @@ namespace Tesses::CrossLang {
|
|||||||
auto callable = dynamic_cast<TCallable*>(obj);
|
auto callable = dynamic_cast<TCallable*>(obj);
|
||||||
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
|
auto callstackEntry = dynamic_cast<CallStackEntry*>(obj);
|
||||||
|
|
||||||
|
|
||||||
auto svr = dynamic_cast<TServerHeapObject*>(obj);
|
auto svr = dynamic_cast<TServerHeapObject*>(obj);
|
||||||
|
|
||||||
if(callstackEntry != nullptr)
|
if(callstackEntry != nullptr)
|
||||||
@ -2721,13 +2804,7 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc,nullptr);
|
cse.back()->Push(gc,nullptr);
|
||||||
return false;
|
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")
|
if(key == "SetSqliteRoot")
|
||||||
{
|
{
|
||||||
Tesses::Framework::Filesystem::VFSPath p;
|
Tesses::Framework::Filesystem::VFSPath p;
|
||||||
@ -2974,11 +3051,11 @@ namespace Tesses::CrossLang {
|
|||||||
if(key == "SetDate")
|
if(key == "SetDate")
|
||||||
{
|
{
|
||||||
Tesses::Framework::Filesystem::VFSPath path;
|
Tesses::Framework::Filesystem::VFSPath path;
|
||||||
int64_t lastWrite;
|
TDateTime lastWrite;
|
||||||
int64_t lastAccess;
|
TDateTime lastAccess;
|
||||||
if(GetArgumentAsPath(args,0,path) && GetArgument(args,1,lastWrite) && GetArgument(args,2,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);
|
cse.back()->Push(gc, nullptr);
|
||||||
return false;
|
return false;
|
||||||
@ -2988,13 +3065,15 @@ namespace Tesses::CrossLang {
|
|||||||
Tesses::Framework::Filesystem::VFSPath path;
|
Tesses::Framework::Filesystem::VFSPath path;
|
||||||
if(GetArgumentAsPath(args,0,path))
|
if(GetArgumentAsPath(args,0,path))
|
||||||
{
|
{
|
||||||
time_t lastWrite;
|
Tesses::Framework::Date::DateTime lastWrite;
|
||||||
time_t lastAccess;
|
Tesses::Framework::Date::DateTime lastAccess;
|
||||||
vfs->vfs->GetDate(path,lastWrite,lastAccess);
|
vfs->vfs->GetDate(path,lastWrite,lastAccess);
|
||||||
|
|
||||||
auto dict = TDictionary::Create(ls);
|
auto dict = TDictionary::Create(ls);
|
||||||
ls.GetGC()->BarrierBegin();
|
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();
|
ls.GetGC()->BarrierEnd();
|
||||||
|
|
||||||
cse.back()->Push(gc, dict);
|
cse.back()->Push(gc, dict);
|
||||||
@ -3244,6 +3323,7 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
auto memStrm = dynamic_cast<Tesses::Framework::Streams::MemoryStream*>(strm->stream);
|
auto memStrm = dynamic_cast<Tesses::Framework::Streams::MemoryStream*>(strm->stream);
|
||||||
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
|
auto netStrm = dynamic_cast<Tesses::Framework::Streams::NetworkStream*>(strm->stream);
|
||||||
|
|
||||||
auto mystrm = dynamic_cast<TObjectStream*>(strm->stream);
|
auto mystrm = dynamic_cast<TObjectStream*>(strm->stream);
|
||||||
|
|
||||||
if(mystrm != nullptr)
|
if(mystrm != nullptr)
|
||||||
@ -3271,6 +3351,11 @@ namespace Tesses::CrossLang {
|
|||||||
}
|
}
|
||||||
if(netStrm != nullptr)
|
if(netStrm != nullptr)
|
||||||
{
|
{
|
||||||
|
if(key == "GetPort")
|
||||||
|
{
|
||||||
|
cse.back()->Push(gc, netStrm->GetPort());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if(key == "Bind")
|
if(key == "Bind")
|
||||||
{
|
{
|
||||||
std::string ip;
|
std::string ip;
|
||||||
@ -3522,6 +3607,7 @@ namespace Tesses::CrossLang {
|
|||||||
cse.back()->Push(gc, nullptr);
|
cse.back()->Push(gc, nullptr);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(bArray != nullptr)
|
else if(bArray != nullptr)
|
||||||
{
|
{
|
||||||
if(key == "Count" || key == "Length")
|
if(key == "Count" || key == "Length")
|
||||||
@ -4098,6 +4184,53 @@ namespace Tesses::CrossLang {
|
|||||||
stk->Push(gc, Undefined());
|
stk->Push(gc, Undefined());
|
||||||
return false;
|
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))
|
if(std::holds_alternative<THeapObjectHolder>(instance))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(instance).obj;
|
auto obj = std::get<THeapObjectHolder>(instance).obj;
|
||||||
@ -5791,13 +5924,17 @@ namespace Tesses::CrossLang {
|
|||||||
{
|
{
|
||||||
return std::get<bool>(o) ? "true" : "false";
|
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))
|
if(std::holds_alternative<THeapObjectHolder>(o))
|
||||||
{
|
{
|
||||||
auto obj = std::get<THeapObjectHolder>(o).obj;
|
auto obj = std::get<THeapObjectHolder>(o).obj;
|
||||||
auto dict = dynamic_cast<TDictionary*>(obj);
|
auto dict = dynamic_cast<TDictionary*>(obj);
|
||||||
auto list = dynamic_cast<TList*>(obj);
|
auto list = dynamic_cast<TList*>(obj);
|
||||||
auto bArray = dynamic_cast<TByteArray*>(obj);
|
auto bArray = dynamic_cast<TByteArray*>(obj);
|
||||||
|
|
||||||
if(dict != nullptr)
|
if(dict != nullptr)
|
||||||
{
|
{
|
||||||
GCList ls(gc);
|
GCList ls(gc);
|
||||||
|
|||||||
Reference in New Issue
Block a user