mirror of
https://github.com/Chatterino/chatterino2.git
synced 2026-08-24 02:24:18 -05:00
feat(plugins): Add c2.DateTime (#7096)
This adds the `DateTime` API described in #7021. Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl> Reviewed-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
Vendored
+14
@@ -664,6 +664,20 @@ declare namespace c2 {
|
||||
}
|
||||
|
||||
var windows: WindowManager;
|
||||
|
||||
class DateTime {
|
||||
static from_iso_string(str: string): DateTime;
|
||||
to_iso_string(): string;
|
||||
to_iso_string_without_ms(): string;
|
||||
|
||||
static current_local(): DateTime;
|
||||
static current_utc(): DateTime;
|
||||
|
||||
static from_unix_milliseconds(ts: number): DateTime;
|
||||
static from_unix_seconds(ts: number): DateTime;
|
||||
to_unix_milliseconds(): number;
|
||||
to_unix_seconds(): number;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "chatterino.json" {
|
||||
|
||||
@@ -332,6 +332,58 @@ function c2.ConnectionHandle:is_connected() end
|
||||
|
||||
-- End src/controllers/plugins/api/ConnectionHandle.hpp
|
||||
|
||||
-- Begin src/controllers/plugins/api/DateTime.hpp
|
||||
|
||||
|
||||
|
||||
---A zoned date and time.
|
||||
---@class c2.DateTime
|
||||
c2.DateTime = {}
|
||||
|
||||
---Parse a date from an ISO 8601 string with milliseconds (yyyy-MM-ddTHH:mm:ss.zzz)
|
||||
---@param str string
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_iso_string(str) end
|
||||
|
||||
---Format the datetime as an ISO string with milliseconds (yyyy-MM-ddTHH:mm:ss.zzz)
|
||||
---@return string
|
||||
function c2.DateTime:to_iso_string() end
|
||||
|
||||
---Format the datetime as an ISO string without milliseconds (yyyy-MM-ddTHH:mm:ss)
|
||||
---@return string
|
||||
function c2.DateTime:to_iso_string_without_ms() end
|
||||
|
||||
---Get the current datetime in the system's local time zone.
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.current_local() end
|
||||
|
||||
---Get the current datetime in the UTC time zone (00:00).
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.current_utc() end
|
||||
|
||||
---Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
---
|
||||
---The returned date time will be in the local time zone.
|
||||
---@param ts number
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_unix_milliseconds(ts) end
|
||||
|
||||
---Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
---
|
||||
---The returned date time will be in the local time zone.
|
||||
---@param ts number
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_unix_seconds(ts) end
|
||||
|
||||
---Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
---@return number
|
||||
function c2.DateTime:to_unix_milliseconds() end
|
||||
|
||||
---Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
---@return number
|
||||
function c2.DateTime:to_unix_seconds() end
|
||||
-- End src/controllers/plugins/api/DateTime.hpp
|
||||
|
||||
-- Begin src/controllers/plugins/api/HTTPResponse.hpp
|
||||
|
||||
---@class c2.HTTPResponse
|
||||
@@ -801,6 +853,7 @@ c2.MessageFlag = {
|
||||
InvalidReplyTarget = 0,
|
||||
WatchStreak = 0,
|
||||
Announcement = 0,
|
||||
UncategorizedNotification = 0,
|
||||
}
|
||||
|
||||
-- End src/messages/MessageFlag.hpp
|
||||
|
||||
@@ -981,6 +981,50 @@ Get all open windows.
|
||||
|
||||
The global [`WindowManager`](#windowmanager).
|
||||
|
||||
#### `DateTime`
|
||||
|
||||
A zoned date and time.
|
||||
|
||||
##### `DateTime.from_iso_string(str)`
|
||||
|
||||
Parse a date from an ISO 8601 string with milliseconds (`yyyy-MM-ddTHH:mm:ss.zzz±hh:mm`)
|
||||
|
||||
##### `DateTime:to_iso_string()`
|
||||
|
||||
Format the datetime as an ISO string with milliseconds (`yyyy-MM-ddTHH:mm:ss.zzz±hh:mm`)
|
||||
|
||||
##### `DateTime:to_iso_string_without_ms()`
|
||||
|
||||
Format the datetime as an ISO string without milliseconds (`yyyy-MM-ddTHH:mm:ss±hh:mm`)
|
||||
|
||||
##### `DateTime.current_local()`
|
||||
|
||||
Get the current datetime in the system's local time zone.
|
||||
|
||||
##### `DateTime.current_utc()`
|
||||
|
||||
Get the current datetime in the UTC time zone (00:00).
|
||||
|
||||
##### `DateTime.from_unix_milliseconds(ts)`
|
||||
|
||||
Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
|
||||
The returned date time will be in the local time zone.
|
||||
|
||||
##### `DateTime.from_unix_seconds(ts)`
|
||||
|
||||
Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
|
||||
The returned date time will be in the local time zone.
|
||||
|
||||
##### `DateTime:to_unix_milliseconds()`
|
||||
|
||||
Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
|
||||
##### `DateTime:to_unix_seconds()`
|
||||
|
||||
Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
|
||||
### Input/Output API
|
||||
|
||||
These functions are wrappers for Lua's I/O library. Functions on file pointer
|
||||
|
||||
@@ -262,6 +262,8 @@ set(SOURCE_FILES
|
||||
controllers/plugins/api/ChannelRef.hpp
|
||||
controllers/plugins/api/ConnectionHandle.cpp
|
||||
controllers/plugins/api/ConnectionHandle.hpp
|
||||
controllers/plugins/api/DateTime.cpp
|
||||
controllers/plugins/api/DateTime.hpp
|
||||
controllers/plugins/api/DebugLibrary.cpp
|
||||
controllers/plugins/api/DebugLibrary.hpp
|
||||
controllers/plugins/api/EventType.hpp
|
||||
|
||||
@@ -95,6 +95,7 @@ sol::table toTable(lua_State *L, const CompletionEvent &ev);
|
||||
* @includefile controllers/plugins/api/Accounts.hpp
|
||||
* @includefile controllers/plugins/api/ChannelRef.hpp
|
||||
* @includefile controllers/plugins/api/ConnectionHandle.hpp
|
||||
* @includefile controllers/plugins/api/DateTime.hpp
|
||||
* @includefile controllers/plugins/api/HTTPResponse.hpp
|
||||
* @includefile controllers/plugins/api/HTTPRequest.hpp
|
||||
* @includefile controllers/plugins/api/Images.hpp
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
# include "controllers/plugins/api/Accounts.hpp"
|
||||
# include "controllers/plugins/api/ChannelRef.hpp"
|
||||
# include "controllers/plugins/api/ConnectionHandle.hpp"
|
||||
# include "controllers/plugins/api/DateTime.hpp"
|
||||
# include "controllers/plugins/api/DebugLibrary.hpp"
|
||||
# include "controllers/plugins/api/HTTPRequest.hpp"
|
||||
# include "controllers/plugins/api/HTTPResponse.hpp"
|
||||
@@ -255,6 +256,7 @@ void PluginController::initSol(sol::state_view &lua, Plugin *plugin)
|
||||
lua::api::images::createUserTypes(c2);
|
||||
lua::api::createAccounts(c2);
|
||||
lua::api::windowmanager::createUserTypes(c2);
|
||||
lua::api::datetime::createUserTypes(c2);
|
||||
c2["ChannelType"] = lua::createEnumTable<Channel::Type>(lua);
|
||||
c2["HTTPMethod"] = lua::createEnumTable<NetworkRequestType>(lua);
|
||||
c2["EventType"] = lua::createEnumTable<lua::api::EventType>(lua);
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "controllers/plugins/api/DateTime.hpp"
|
||||
|
||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||
|
||||
# include "controllers/plugins/SolTypes.hpp" // IWYU pragma: keep
|
||||
|
||||
# include <QDateTime>
|
||||
|
||||
namespace chatterino::lua::api::datetime {
|
||||
|
||||
void createUserTypes(sol::table &c2)
|
||||
{
|
||||
c2.new_usertype<QDateTime>(
|
||||
"DateTime", sol::no_constructor, //
|
||||
|
||||
// __tostring uses the ISO date.
|
||||
sol::meta_method::to_string,
|
||||
[](const QDateTime &self) {
|
||||
return self.toString(Qt::ISODateWithMs);
|
||||
},
|
||||
|
||||
// ISO 8601 conversion.
|
||||
"from_iso_string",
|
||||
[](const QString &s) {
|
||||
return QDateTime::fromString(s, Qt::ISODateWithMs);
|
||||
},
|
||||
"to_iso_string",
|
||||
[](const QDateTime &self) {
|
||||
return self.toString(Qt::ISODateWithMs);
|
||||
},
|
||||
"to_iso_string_without_ms",
|
||||
[](const QDateTime &self) {
|
||||
return self.toString(Qt::ISODate);
|
||||
},
|
||||
|
||||
// System time constructors.
|
||||
"current_local",
|
||||
[] {
|
||||
return QDateTime::currentDateTime();
|
||||
},
|
||||
"current_utc",
|
||||
[] {
|
||||
return QDateTime::currentDateTimeUtc();
|
||||
},
|
||||
|
||||
// Unix (milli)seconds conversion.
|
||||
"from_unix_milliseconds",
|
||||
[](int64_t ts) {
|
||||
return QDateTime::fromMSecsSinceEpoch(ts);
|
||||
},
|
||||
"from_unix_seconds",
|
||||
[](int64_t ts) {
|
||||
return QDateTime::fromSecsSinceEpoch(ts);
|
||||
},
|
||||
"to_unix_milliseconds",
|
||||
[](const QDateTime &self) {
|
||||
return self.toMSecsSinceEpoch();
|
||||
},
|
||||
"to_unix_seconds",
|
||||
[](const QDateTime &self) {
|
||||
return self.toSecsSinceEpoch();
|
||||
} //
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace chatterino::lua::api::datetime
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef CHATTERINO_HAVE_PLUGINS
|
||||
|
||||
# include <sol/forward.hpp>
|
||||
|
||||
namespace chatterino::lua::api::datetime {
|
||||
|
||||
/* @lua-fragment
|
||||
|
||||
---A zoned date and time.
|
||||
---@class c2.DateTime
|
||||
c2.DateTime = {}
|
||||
|
||||
---Parse a date from an ISO 8601 string with milliseconds (yyyy-MM-ddTHH:mm:ss.zzz)
|
||||
---@param str string
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_iso_string(str) end
|
||||
|
||||
---Format the datetime as an ISO string with milliseconds (yyyy-MM-ddTHH:mm:ss.zzz)
|
||||
---@return string
|
||||
function c2.DateTime:to_iso_string() end
|
||||
|
||||
---Format the datetime as an ISO string without milliseconds (yyyy-MM-ddTHH:mm:ss)
|
||||
---@return string
|
||||
function c2.DateTime:to_iso_string_without_ms() end
|
||||
|
||||
---Get the current datetime in the system's local time zone.
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.current_local() end
|
||||
|
||||
---Get the current datetime in the UTC time zone (00:00).
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.current_utc() end
|
||||
|
||||
---Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
---
|
||||
---The returned date time will be in the local time zone.
|
||||
---@param ts number
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_unix_milliseconds(ts) end
|
||||
|
||||
---Get a datetime from a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
---
|
||||
---The returned date time will be in the local time zone.
|
||||
---@param ts number
|
||||
---@return c2.DateTime
|
||||
function c2.DateTime.from_unix_seconds(ts) end
|
||||
|
||||
---Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in milliseconds.
|
||||
---@return number
|
||||
function c2.DateTime:to_unix_milliseconds() end
|
||||
|
||||
---Convert a datetime to a Unix timestamp (offset from 1970-01-01 00:00 UTC) in seconds.
|
||||
---@return number
|
||||
function c2.DateTime:to_unix_seconds() end
|
||||
*/
|
||||
|
||||
/// Creates
|
||||
/// - `c2.DateTime` (QDateTime)
|
||||
void createUserTypes(sol::table &c2);
|
||||
|
||||
} // namespace chatterino::lua::api::datetime
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
---@generic T
|
||||
---@param a T
|
||||
---@param b T
|
||||
local function assert_eq(a, b)
|
||||
if a ~= b then
|
||||
error(tostring(a) .. " ~= " .. tostring(b))
|
||||
end
|
||||
end
|
||||
|
||||
local specs_ms = {
|
||||
{
|
||||
iso_ms = "2026-07-10T20:14:41.477Z",
|
||||
iso_sec = "2026-07-10T20:14:41Z",
|
||||
unix_ms = 1783714481477,
|
||||
unix_sec = 1783714481,
|
||||
},
|
||||
{
|
||||
iso_ms = "1930-11-18T00:28:29.123Z",
|
||||
iso_sec = "1930-11-18T00:28:29Z",
|
||||
unix_ms = -1234567890877,
|
||||
unix_sec = -1234567890,
|
||||
},
|
||||
}
|
||||
local specs_sec = {
|
||||
{
|
||||
iso_ms = "2026-07-10T20:14:41.000Z",
|
||||
iso_sec = "2026-07-10T20:14:41Z",
|
||||
unix_ms = 1783714481000,
|
||||
unix_sec = 1783714481,
|
||||
},
|
||||
{
|
||||
iso_ms = "1930-11-18T00:28:29.000Z",
|
||||
iso_sec = "1930-11-18T00:28:29Z",
|
||||
unix_ms = -1234567891000,
|
||||
unix_sec = -1234567891,
|
||||
},
|
||||
}
|
||||
|
||||
local tests = {
|
||||
iso_string_invalid = function()
|
||||
local dt = c2.DateTime.from_iso_string("invalid")
|
||||
assert_eq(dt:to_unix_milliseconds(), 0)
|
||||
assert_eq(dt:to_iso_string(), "")
|
||||
end,
|
||||
iso_string_ms = function()
|
||||
for _, spec in pairs(specs_ms) do
|
||||
local dt = c2.DateTime.from_iso_string(spec.iso_ms)
|
||||
|
||||
assert_eq(dt, c2.DateTime.from_iso_string(spec.iso_ms))
|
||||
assert_eq(dt:to_iso_string(), tostring(dt))
|
||||
assert_eq(dt:to_iso_string(), spec.iso_ms)
|
||||
assert_eq(dt:to_iso_string_without_ms(), spec.iso_sec)
|
||||
assert_eq(dt:to_unix_milliseconds(), spec.unix_ms)
|
||||
assert_eq(dt:to_unix_seconds(), spec.unix_sec)
|
||||
end
|
||||
end,
|
||||
iso_string_sec = function()
|
||||
for _, spec in pairs(specs_sec) do
|
||||
local dt = c2.DateTime.from_iso_string(spec.iso_sec)
|
||||
|
||||
assert_eq(dt, c2.DateTime.from_iso_string(spec.iso_ms))
|
||||
assert_eq(dt, c2.DateTime.from_iso_string(spec.iso_sec))
|
||||
assert_eq(dt:to_iso_string(), tostring(dt))
|
||||
assert_eq(dt:to_iso_string(), spec.iso_ms)
|
||||
assert_eq(dt:to_iso_string_without_ms(), spec.iso_sec)
|
||||
assert_eq(dt:to_unix_milliseconds(), spec.unix_ms)
|
||||
assert_eq(dt:to_unix_seconds(), spec.unix_sec)
|
||||
end
|
||||
end,
|
||||
|
||||
current_time = function()
|
||||
local dt = c2.DateTime.current_local()
|
||||
-- We don't know what it should be, but we know that it must be valid.
|
||||
assert(dt:to_iso_string() ~= "")
|
||||
dt = c2.DateTime.current_utc()
|
||||
assert(dt:to_iso_string() ~= "")
|
||||
end,
|
||||
|
||||
unix_timestamp_ms = function()
|
||||
for _, spec in pairs(specs_ms) do
|
||||
local dt = c2.DateTime.from_unix_milliseconds(spec.unix_ms)
|
||||
assert_eq(dt, c2.DateTime.from_unix_milliseconds(spec.unix_ms))
|
||||
assert_eq(dt:to_unix_milliseconds(), spec.unix_ms)
|
||||
assert_eq(dt:to_unix_seconds(), spec.unix_sec)
|
||||
|
||||
-- FIXME: Check the ISO string here, but it's in the local time zone right now.
|
||||
-- assert_eq(dt, c2.DateTime.from_iso_string(spec.iso_ms))
|
||||
-- assert_eq(dt:to_iso_string(), spec.iso_ms)
|
||||
-- assert_eq(dt:to_iso_string_without_ms(), spec.iso_sec)
|
||||
end
|
||||
end,
|
||||
unix_timestamp_sec = function()
|
||||
for _, spec in pairs(specs_sec) do
|
||||
-- without milliseconds
|
||||
local dt = c2.DateTime.from_unix_seconds(spec.unix_sec)
|
||||
assert_eq(dt, c2.DateTime.from_unix_seconds(spec.unix_sec))
|
||||
assert_eq(dt, c2.DateTime.from_unix_milliseconds(spec.unix_ms))
|
||||
assert_eq(dt:to_unix_milliseconds(), spec.unix_ms)
|
||||
assert_eq(dt:to_unix_seconds(), spec.unix_sec)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
for name, fn in pairs(tests) do
|
||||
local ok, res = xpcall(fn, debug.traceback)
|
||||
if not ok then
|
||||
error(name .. " failed: " .. res)
|
||||
end
|
||||
end
|
||||
@@ -1698,6 +1698,19 @@ TEST_F(PluginImageTest, NoPerms)
|
||||
INSTANTIATE_TEST_SUITE_P(PluginImage, PluginImageTest,
|
||||
testing::ValuesIn(discoverLuaTests("images")));
|
||||
|
||||
class PluginDateTimeTest : public PluginTest,
|
||||
public ::testing::WithParamInterface<QString>
|
||||
{
|
||||
};
|
||||
TEST_P(PluginDateTimeTest, Run)
|
||||
{
|
||||
this->configure();
|
||||
runLuaTest("datetime", GetParam(), *this->lua);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(PluginChannel, PluginDateTimeTest,
|
||||
testing::ValuesIn(discoverLuaTests("datetime")));
|
||||
|
||||
// verify that all snapshots are included
|
||||
TEST(PluginMessageConstructionTest, Integrity)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user