Skip to content

Commit 25e9c21

Browse files
committed
feat!: multiple of datetime creation methods was replaced by Astra.datetime.new
1 parent 5fe2759 commit 25e9c21

File tree

2 files changed

+129
-30
lines changed

2 files changed

+129
-30
lines changed

src/components/datetime.lua

Lines changed: 97 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
---@meta
22

33
---@class DateTime
4-
---@field new_now fun(): DateTime
5-
---@field new_from fun(year: number, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
6-
---@field new_utc_now fun(): DateTime
7-
---@field new_utc_from fun(year: number, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
84
---@field get_year fun(datetime: DateTime): number
95
---@field get_month fun(datetime: DateTime): number
106
---@field get_day fun(datetime: DateTime): number
@@ -15,6 +11,8 @@
1511
---@field get_millisecond fun(datetime: DateTime): number
1612
---@field get_epoch_milliseconds fun(datetime: DateTime): number
1713
---@field get_timezone_offset fun(datetime: DateTime): number
14+
---@field to_rfc2822 fun(datetime: DateTime): string
15+
---@field to_rfc3339 fun(datetime: DateTime): string
1816
---@field set_year fun(datetime:DateTime, year: number)
1917
---@field set_month fun(datetime:DateTime, month: number)
2018
---@field set_day fun(datetime:DateTime, day: number)
@@ -23,36 +21,107 @@
2321
---@field set_second fun(datetime:DateTime, sec: number)
2422
---@field set_millisecond fun(datetime:DateTime, milli: number)
2523
---@field set_epoch_milliseconds fun(datetime: DateTime, milli: number)
26-
---@field to_date_string fun(datetime: DateTime): string?
27-
---@field to_time_string fun(datetime: DateTime): string?
28-
---@field to_datetime_string fun(datetime: DateTime): string?
29-
---@field to_iso_string fun(datetime: DateTime): string?
30-
---@field to_locale_date_string fun(datetime: DateTime): string?
31-
---@field to_locale_time_string fun(datetime: DateTime): string?
32-
---@field to_locale_datetime_string fun(datetime: DateTime): string?
24+
---@field to_utc fun(datetime: DateTime): DateTime
25+
---@field to_local fun(datetime: DateTime): DateTime
26+
---@field to_date_string fun(datetime: DateTime): string
27+
---@field to_time_string fun(datetime: DateTime): string
28+
---@field to_datetime_string fun(datetime: DateTime): string
29+
---@field to_iso_string fun(datetime: DateTime): string
30+
---@field to_locale_date_string fun(datetime: DateTime): string
31+
---@field to_locale_time_string fun(datetime: DateTime): string
32+
---@field to_locale_datetime_string fun(datetime: DateTime): string
3333

34-
Astra.datetime = {}
34+
---@class DateTime
35+
local DateTimeWrapper = {}
36+
DateTimeWrapper.__index = DateTimeWrapper
3537

36-
---@return DateTime
37-
function Astra.datetime.new_now()
38-
---@diagnostic disable-next-line: undefined-global
39-
return astra_internal__datetime_new_now()
38+
-- ! THIS CAN BE REUSED AS A LIB
39+
local function create_proxy(wrapper_methods)
40+
local mt = {}
41+
42+
mt.__index = function(self, key)
43+
-- Wrapper methods override everything
44+
if wrapper_methods[key] ~= nil then
45+
return wrapper_methods[key]
46+
end
47+
48+
-- Then any per-instance value
49+
local val = rawget(self, key)
50+
if val ~= nil then
51+
return val
52+
end
53+
54+
-- Fallback to underlying userdata/table
55+
local underlying = rawget(self, "_obj")
56+
local v = underlying[key]
57+
if type(v) == "function" then
58+
return function(_, ...)
59+
return v(underlying, ...)
60+
end
61+
else
62+
return v
63+
end
64+
end
65+
66+
mt.__newindex = function(self, key, value)
67+
-- If wrapper defines it or instance has it—set on proxy
68+
if wrapper_methods[key] ~= nil or rawget(self, key) ~= nil then
69+
rawset(self, key, value)
70+
else
71+
local underlying = rawget(self, "_obj")
72+
local setter = underlying["set_" .. key]
73+
if type(setter) == "function" then
74+
setter(underlying, value)
75+
else
76+
underlying[key] = value
77+
end
78+
end
79+
end
80+
81+
mt.__tostring = function(self)
82+
local u = rawget(self, "_obj")
83+
return (u.to_string and u:to_string()) or tostring(u)
84+
end
85+
86+
mt.__concat = function(a, b)
87+
return tostring(a) .. tostring(b)
88+
end
89+
90+
return mt
4091
end
4192

42-
---@return DateTime
43-
function Astra.datetime.new_utc_now()
44-
---@diagnostic disable-next-line: undefined-global
45-
return astra_internal__datetime_new_now(true)
93+
-- General wrapper factory
94+
local function wrap(obj, wrapper_methods)
95+
assert(type(obj) == "userdata" or type(obj) == "table", "Can only wrap userdata or tables")
96+
local proxy = { _obj = obj }
97+
setmetatable(proxy, create_proxy(wrapper_methods or {}))
98+
return proxy
4699
end
47100

48-
---@type fun(year: number, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
49-
function Astra.datetime.new_from(year, month, day, hour, min, sec, milli)
50-
---@diagnostic disable-next-line: undefined-global
51-
return astra_internal__datetime_new_from(year, month, date, hour, min, sec, milli, false)
101+
---@type fun(differentiator: string | number | nil, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
102+
---@param differentiator string | number | nil This field can be used to determine the type of DateTime. On empty it creates a new local DateTime, on number it starts te sequence for letting you define the DateTime by parameters, and on string it allows you to parse a string to DateTime.
103+
---@return DateTime
104+
local function new_datetime(differentiator, month, day, hour, min, sec, milli)
105+
if type(differentiator) == "string" then
106+
---@diagnostic disable-next-line: undefined-global
107+
return astra_internal__datetime_new_parse(differentiator)
108+
elseif type(differentiator) == "number" then
109+
---@diagnostic disable-next-line: undefined-global
110+
return astra_internal__datetime_new_from(differentiator, month, day, hour, min, sec, milli)
111+
else
112+
---@diagnostic disable-next-line: undefined-global
113+
return astra_internal__datetime_new_now()
114+
end
52115
end
53116

54-
---@type fun(year: number, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
55-
function Astra.datetime.new_utc_from(year, month, day, hour, min, sec, milli)
56-
---@diagnostic disable-next-line: undefined-global
57-
return astra_internal__datetime_new_from(year, month, date, hour, min, sec, milli, true)
117+
Astra.datetime = {}
118+
119+
---@type fun(differentiator: string | number | nil, month: number?, day: number?, hour: number?, min: number?, sec: number?, milli: number?): DateTime
120+
---@param differentiator string | number | nil This field can be used to determine the type of DateTime. On empty it creates a new local DateTime, on number it starts te sequence for letting you define the DateTime by parameters, and on string it allows you to parse a string to DateTime.
121+
---@return DateTime
122+
--- Creates a wrapper for a DateTime-like object
123+
function Astra.datetime.new(differentiator, month, day, hour, min, sec, milli)
124+
-- Create real DateTime using Astra.datetime
125+
local real_dt = new_datetime(differentiator, month, day, hour, min, sec, milli)
126+
return wrap(real_dt, DateTimeWrapper)
58127
end

src/components/datetime.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use chrono::{offset::LocalResult, prelude::*};
2-
use mlua::UserData;
2+
use mlua::{FromLua, UserData};
33

4+
#[derive(Debug, Clone, FromLua)]
45
pub struct LuaDateTime {
56
dt: DateTime<FixedOffset>,
67
}
7-
88
impl LuaDateTime {
99
pub fn register_to_lua(lua: &mlua::Lua) -> mlua::Result<&'static str> {
1010
lua.globals().set(
@@ -19,6 +19,23 @@ impl LuaDateTime {
1919
})?,
2020
)?;
2121

22+
lua.globals().set(
23+
"astra_internal__datetime_new_parse",
24+
lua.create_function(|_, date_str: String| {
25+
match DateTime::parse_from_rfc2822(&date_str) {
26+
Ok(dt) => Ok(Self { dt }),
27+
Err(err1) => match DateTime::parse_from_rfc3339(&date_str) {
28+
Ok(dt) => Ok(Self { dt }),
29+
Err(err2) => Err(mlua::Error::runtime(format!(
30+
"\nRFC 2822 ERR: {:?}\nRFC 3339 ERR: {:?}",
31+
err1.to_string(),
32+
err2.to_string()
33+
))),
34+
},
35+
}
36+
})?,
37+
)?;
38+
2239
lua.globals().set(
2340
"astra_internal__datetime_new_from",
2441
lua.create_function(
@@ -121,6 +138,8 @@ impl UserData for LuaDateTime {
121138
add_getter_method!("get_timezone_offset", offset, |offset: &FixedOffset| offset
122139
.local_minus_utc()
123140
/ 60);
141+
add_getter_method!("to_rfc2822", to_rfc2822);
142+
add_getter_method!("to_rfc3339", to_rfc3339);
124143

125144
add_setter_method!("set_year", with_year, i32, "Invalid year!");
126145
add_setter_method!("set_month", with_month, u32, "Invalid month!");
@@ -148,6 +167,17 @@ impl UserData for LuaDateTime {
148167
}
149168
});
150169

170+
methods.add_method("to_utc", |_, this, _: ()| {
171+
Ok(Self {
172+
dt: this.dt.to_utc().fixed_offset(),
173+
})
174+
});
175+
methods.add_method("to_local", |_, this, _: ()| {
176+
let dt: DateTime<chrono::Local> = chrono::DateTime::from(this.dt);
177+
Ok(Self {
178+
dt: dt.fixed_offset(),
179+
})
180+
});
151181
add_formatted_method!("to_date_string", "%a %b %d %Y");
152182
add_formatted_method!("to_time_string", "%T %Z%z");
153183
add_formatted_method!("to_datetime_string", "%a %b %d %Y %T %Z%z");

0 commit comments

Comments
 (0)