mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
401
lua/niknaks/modules/sh_datetime.lua
Normal file
401
lua/niknaks/modules/sh_datetime.lua
Normal file
@@ -0,0 +1,401 @@
|
||||
--[[
|
||||
| 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
|
||||
Reference in New Issue
Block a user