|
1 | 1 | ---@meta |
2 | 2 |
|
3 | 3 | ---@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 |
8 | 4 | ---@field get_year fun(datetime: DateTime): number |
9 | 5 | ---@field get_month fun(datetime: DateTime): number |
10 | 6 | ---@field get_day fun(datetime: DateTime): number |
|
15 | 11 | ---@field get_millisecond fun(datetime: DateTime): number |
16 | 12 | ---@field get_epoch_milliseconds fun(datetime: DateTime): number |
17 | 13 | ---@field get_timezone_offset fun(datetime: DateTime): number |
| 14 | +---@field to_rfc2822 fun(datetime: DateTime): string |
| 15 | +---@field to_rfc3339 fun(datetime: DateTime): string |
18 | 16 | ---@field set_year fun(datetime:DateTime, year: number) |
19 | 17 | ---@field set_month fun(datetime:DateTime, month: number) |
20 | 18 | ---@field set_day fun(datetime:DateTime, day: number) |
|
23 | 21 | ---@field set_second fun(datetime:DateTime, sec: number) |
24 | 22 | ---@field set_millisecond fun(datetime:DateTime, milli: number) |
25 | 23 | ---@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 |
33 | 33 |
|
34 | | -Astra.datetime = {} |
| 34 | +---@class DateTime |
| 35 | +local DateTimeWrapper = {} |
| 36 | +DateTimeWrapper.__index = DateTimeWrapper |
35 | 37 |
|
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 |
40 | 91 | end |
41 | 92 |
|
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 |
46 | 99 | end |
47 | 100 |
|
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 |
52 | 115 | end |
53 | 116 |
|
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) |
58 | 127 | end |
0 commit comments