mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
402 lines
10 KiB
Lua
402 lines
10 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
-- Copyright © 2022-2072, Nak, https://steamcommunity.com/id/Nak2/
|
|
-- All Rights Reserved. Not allowed to be reuploaded.
|
|
-- License: https://github.com/Nak2/NikNaks/blob/main/LICENSE
|
|
|
|
NikNaks.DateTime = {}
|
|
local localvars, os_time, os_date, rawget, tonumber, getmetatable = {}, os.time, os.date, rawget, tonumber, getmetatable
|
|
|
|
-- TimeZone / Date variables
|
|
do
|
|
local UTC_DAY = os_date( "%d", 0 ) - os_date( "!%d", 0 )
|
|
local UTC_Timezone = tonumber( os_date( "%H", 0 ) ) - tonumber( os_date( "!%H", 0 ) )
|
|
if UTC_DAY == 30 then
|
|
UTC_Timezone = UTC_Timezone - 24
|
|
end
|
|
|
|
local UTC_Timezone_dst = tonumber( os_date( "%z" ) ) / 100
|
|
local DaylightsSaving = UTC_Timezone_dst - UTC_Timezone
|
|
NikNaks.DateTime.dst = DaylightsSaving
|
|
NikNaks.DateTime.timezone = UTC_Timezone
|
|
NikNaks.DateTime.timezone_dst = UTC_Timezone_dst
|
|
end
|
|
|
|
local function is_leap_year( year )
|
|
return year % 4 == 0 and ( year % 100 ~= 0 or year % 400 == 0 )
|
|
end
|
|
|
|
function NikNaks.DateTime.IsLeapYear( year )
|
|
return is_leap_year( year or NikNaks.DateTime.year )
|
|
end
|
|
|
|
do
|
|
local months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
|
|
|
function NikNaks.DateTime.DaysInMonth( month, year )
|
|
if month == 2 and is_leap_year( year or NikNaks.DateTime.year ) then
|
|
return 29
|
|
end
|
|
|
|
return months[month]
|
|
end
|
|
|
|
function NikNaks.DateTime.Calender( year )
|
|
year = year or NikNaks.DateTime.year
|
|
local c = {}
|
|
c.year = year
|
|
c.month = {}
|
|
|
|
for i = 1, 12 do
|
|
if i == 2 and is_leap_year( year ) then
|
|
c.month[i] = 29
|
|
else
|
|
c.month[i] = months[i]
|
|
end
|
|
end
|
|
|
|
return c
|
|
end
|
|
end
|
|
|
|
-- Date variables
|
|
local function updatedate()
|
|
local date = string.Explode( ":", os_date( "%H:%M:%S:%d:%m:%Y" ) )
|
|
NikNaks.DateTime.day = tonumber( date[4] )
|
|
NikNaks.DateTime.month = tonumber( date[5] )
|
|
NikNaks.DateTime.year = tonumber( date[6] )
|
|
|
|
-- Calculates next cycle
|
|
local t_seconds = tonumber( date[1] ) * 3600 + tonumber( date[2] ) * 60 + tonumber( date[3] )
|
|
local nextUpdate = 86400 - t_seconds
|
|
timer.Create( "NikNaks_DateUpdate", math.max( nextUpdate, 1 ), 1, updatedate )
|
|
end
|
|
updatedate()
|
|
|
|
-- Branch metatable
|
|
setmetatable( NikNaks.DateTime, {
|
|
__index = function( _, v )
|
|
local l = rawget( localvars, v )
|
|
return rawget( NikNaks.DateTime, v ) or l and l()
|
|
end,
|
|
__call = function( _, var )
|
|
return NikNaks.DateTime.Get( var )
|
|
end
|
|
} )
|
|
|
|
local string_to_var
|
|
do
|
|
-- Tries to parse hour, minute and seconds
|
|
local function findTime( str )
|
|
local h, m, s, ampm = string.match( str:upper(), "([01]?%d):(%d%d?):?(%d*)%s*([AP][M])" )
|
|
|
|
if not h then
|
|
h, m, s = string.match( str, "(%d%d?):(%d%d?):?(%d*)" )
|
|
end
|
|
|
|
if not h then return nil end
|
|
h = tonumber( h )
|
|
m = tonumber( m )
|
|
s = tonumber( s )
|
|
|
|
if ampm then
|
|
if ampm == "AM" then
|
|
if h == 12 then h = 0 end
|
|
else
|
|
if h ~= 12 then h = h + 12 end
|
|
end
|
|
end
|
|
|
|
return h, m, s
|
|
end
|
|
|
|
-- Tries to parse year, month, day
|
|
local findDate
|
|
do
|
|
local date_tab = {
|
|
"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
|
|
}
|
|
|
|
local date_pattern = "[JFMASOND][AEPUCO][NBRYLGPTVC]"
|
|
local function findMonthNameAndDate( str )
|
|
if not string.match( str, date_pattern ) then return nil end
|
|
|
|
for m_id, date in ipairs( date_tab ) do
|
|
if string.match( str, date ) then
|
|
local d = string.match( str, date .. "%a*%s?(%d%d?)" ) or string.match( str, "(%d%d?)%s?" .. date )
|
|
return m_id, d and tonumber( d ) or 1
|
|
end
|
|
end
|
|
end
|
|
|
|
function findDate( str )
|
|
-- The year number tent to mess with the rest, if found replace it if found.
|
|
local fy = true
|
|
local y = string.match( str, "(%d%d%d%d)" )
|
|
local m, d
|
|
if y then
|
|
str = string.gsub( str, "%d%d%d%d", "", 1 )
|
|
y = tonumber( y )
|
|
else
|
|
-- Check of YY/MM/DD
|
|
y, m, d = string.match( str, "(%d+)[/%-](%d%d?)[/%-](%d%d?)" )
|
|
if not y then -- Year must be today
|
|
y = NikNaks.DateTime.year
|
|
fy = false
|
|
else
|
|
return tonumber( y ), tonumber( m ), tonumber( d )
|
|
end
|
|
end
|
|
|
|
-- Find MM/DD
|
|
m, d = string.match( str, "(%d%d?)[/%-](%d%d?)" )
|
|
if m and d then
|
|
return y, tonumber( m ), tonumber( d )
|
|
end
|
|
|
|
-- No date found. Try string-scan for month names
|
|
m, d = findMonthNameAndDate( str:upper() ) -- Try parse letters
|
|
if m then
|
|
return y, m, d
|
|
end
|
|
|
|
-- If only a year is given, then return the first day in that year.
|
|
if fy then
|
|
return y, 1, 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Tries to parse timezone. Since os.time use the locate time, this will be negative.
|
|
local function findOffset( str )
|
|
if str:sub( -1 ) == "Z" then return -NikNaks.DateTime.timezone_dst end
|
|
local sign, h, m = str:match( "([%-%+])(%d%d?):?(%d?%d?)$" )
|
|
if sign then
|
|
return ( tonumber( sign .. h ) + tonumber( sign .. m ) / 60 ) - NikNaks.DateTime.timezone_dst
|
|
else
|
|
-- Use local
|
|
return 0
|
|
end
|
|
end
|
|
|
|
function string_to_var( str )
|
|
str = string.Trim( str )
|
|
|
|
if #str ~= 4 then
|
|
local n = string.match( str, "%d+" )
|
|
if #n == #str then return tonumber( n ) end
|
|
end
|
|
|
|
--[[
|
|
Sun, 03 Jan 2010 00:00:00 GMT
|
|
September 26, 2006 12:12 AM
|
|
2012-10-06T04:13:00+00:00
|
|
2012/10/6
|
|
2008-05-01T07:34:42-5:00
|
|
2008-05-01 7:34:42Z
|
|
Thu, 01 May 2008 07:34:42 GMT
|
|
]]
|
|
local h, m, s = findTime( str )
|
|
|
|
-- Get Time & Date
|
|
local year, month, day = findDate( str )
|
|
|
|
-- Find offset
|
|
local offsetH = findOffset( str ) or 0
|
|
|
|
-- Convert to unix
|
|
return os_time( {
|
|
day = day or 1,
|
|
hour = h or 0,
|
|
min = m or 0,
|
|
month = month or 1,
|
|
sec = tonumber( s ) or 0,
|
|
year = year
|
|
} ) + offsetH * 3600
|
|
end
|
|
end
|
|
|
|
--- @class DateTime
|
|
local datetime_obj = {}
|
|
datetime_obj.__index = datetime_obj
|
|
NikNaks.__metatables["DateTime"] = datetime_obj
|
|
function NikNaks.DateTime.Get( var, t_zone )
|
|
if not var then
|
|
var = os_time()
|
|
else
|
|
local _type = type( var )
|
|
if _type == "string" then
|
|
var = string_to_var( var )
|
|
elseif _type == "table" then
|
|
if var.time then
|
|
var = var.time + os_time()
|
|
elseif var.unix then
|
|
var = var.unix
|
|
else -- Unknown
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Unable to create
|
|
if not var then return nil end
|
|
|
|
-- Create object and return
|
|
--- @class DateTime
|
|
local t = {}
|
|
t.unix = var
|
|
t.timezone = t_zone
|
|
return setmetatable( t, datetime_obj )
|
|
end
|
|
|
|
function datetime_obj:GetUnix()
|
|
return self.unix
|
|
end
|
|
|
|
function datetime_obj:TimeUntil( var )
|
|
local unix
|
|
local _type = type( var )
|
|
|
|
if _type == "string" then
|
|
unix = string_to_var( var )
|
|
elseif _type == "table" then
|
|
if var.time then
|
|
return var.time -- Will always be relative
|
|
elseif var.unix then
|
|
unix = var.unix
|
|
end
|
|
end
|
|
|
|
return NikNaks.TimeDelta( unix - self.unix, tonumber( os.date( "%Y", self.unix ) ) )
|
|
end
|
|
|
|
-- Local variable functions: DateTime.<X>
|
|
function localvars.now()
|
|
return NikNaks.DateTime.Get( os_time() )
|
|
end
|
|
localvars.today = localvars.now
|
|
|
|
function localvars.yesterday()
|
|
return NikNaks.DateTime.Get( os_time() - NikNaks.TimeDelta.Day )
|
|
end
|
|
|
|
function localvars.tomorrow()
|
|
return NikNaks.DateTime.Get( os_time() + NikNaks.TimeDelta.Day )
|
|
end
|
|
|
|
--- Returns the time using os.date
|
|
--- @param format string
|
|
--- @return string
|
|
function datetime_obj:ToDate( format )
|
|
return os_date( format, self.unix )
|
|
end
|
|
datetime_obj.__tostring = function( self )
|
|
return os_date( nil, self.unix )
|
|
end
|
|
|
|
-- Operations
|
|
function datetime_obj.__sub( a, b )
|
|
if not getmetatable( a ) then -- A is most likely a number. Number - Obj = TimeDelta
|
|
return NikNaks.TimeDelta( a - b.unix )
|
|
elseif not getmetatable( b ) then -- B is most likely a number. Obj - Number = New Obj
|
|
return NikNaks.DateTime.Get( a.unix - b )
|
|
else -- Both are objects
|
|
if a.unix and b.unix then
|
|
return NikNaks.TimeDelta( a.unix - b.unix )
|
|
elseif a.unix then
|
|
return NikNaks.DateTime.Get( a.unix - ( b.time or b ) )
|
|
elseif b.unix then
|
|
return NikNaks.DateTime.Get( b.unix - ( a.time or a ) )
|
|
end
|
|
end
|
|
end
|
|
|
|
function datetime_obj.__add( a, b )
|
|
if not getmetatable( a ) then -- A is most likely a number. Number + Obj = New Obj
|
|
return NikNaks.DateTime.Get( b.unix + a )
|
|
elseif not getmetatable( b ) then -- B is most likely a number. Obj - Number = New Obj
|
|
return NikNaks.DateTime.Get( a.unix + b )
|
|
else -- Both are objects
|
|
if a.unix and b.unix then -- Get the higest unix-time and add the delta between the two
|
|
return NikNaks.DateTime.Get( math.max( a.unix, b.unix ) + abs( a.unix - b.unix ) )
|
|
elseif a.unix then
|
|
return NikNaks.DateTime.Get( a.unix + ( b.time or b ) )
|
|
elseif b.unix then
|
|
return NikNaks.DateTime.Get( b.unix + ( a.time or a ) )
|
|
end
|
|
end
|
|
end
|
|
|
|
function datetime_obj.__concat( a, b )
|
|
return tostring( a ) .. tostring( b )
|
|
end
|
|
|
|
-- Not supported in Gmod!
|
|
datetime_obj.__shl = datetime_obj.__sub
|
|
datetime_obj.__shr = datetime_obj.__add
|
|
|
|
-- Sadly Lua doesn't support mixed types for compare-operations
|
|
function datetime_obj.__eq( a, b )
|
|
return a.unix == b.unix
|
|
end
|
|
|
|
function datetime_obj.__lt( a, b )
|
|
return a.unix < b.unix
|
|
end
|
|
|
|
function datetime_obj.__le( a, b )
|
|
return a.unix <= b.unix
|
|
end
|
|
|
|
-- TimeDelta functions
|
|
for key, var in pairs( NikNaks.TimeDelta ) do
|
|
datetime_obj["Add" .. key .. "s"] = function( self, num )
|
|
self.unix = self.unix + num * var
|
|
return self
|
|
end
|
|
|
|
datetime_obj["Remove" .. key .. "s"] = function( self, num )
|
|
self.unix = self.unix - num * var
|
|
return self
|
|
end
|
|
|
|
datetime_obj["Sub" .. key .. "s"] = datetime_obj["Remove" .. key .. "s"]
|
|
end
|
|
|
|
-- DateTime string debug test
|
|
if true then return end
|
|
local t = { "Sun, 01 Sep 2022 00:12:00",
|
|
"September 01, 2022 12:12 AM",
|
|
"2022-09-01T00:12:00+02:00",
|
|
"2022/09/1",
|
|
"2022-09-01T07:12:00-5:00",
|
|
"2022-09-01 02:12:00Z",
|
|
"Thu, 01 Sep 2022 00:12:00" }
|
|
|
|
function ParseTest()
|
|
for _, str in ipairs( t ) do
|
|
print( str .. string.rep( " ", 30 - #str ), "=>", NikNaks.DateTime.Get( str ) )
|
|
end
|
|
end
|
|
|
|
function SpeedTest()
|
|
local n = 20000 * #t
|
|
local s = SysTime()
|
|
|
|
for _, str in ipairs( t ) do
|
|
for _ = 1, 20000 do
|
|
NikNaks.DateTime.Get( str )
|
|
end
|
|
end
|
|
|
|
print( string.format( n .. " took: %fs", SysTime() - s ) )
|
|
end
|