如何将自纪元以来的秒数转换为当前日期和时间?

4

我知道我之前发布过这个问题,但我已经找到了解决方案。我为一个名为Roblox的游戏编写了这段代码,但我在这里发布代码,以防其他遇到同样问题的人需要解决方案。无论如何,以下是代码:

outputTime = true -- true: will print the current time to output window. false: won't print time
createVariable = true -- true: creates variables under game.Lighting. false: won't create variables

-----------------------------------------------------------------------------------------------
--DO NOT EDIT BELOW----------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------

if(createVariable) then
    yearVar = Instance.new("IntValue", game.Lighting)
    yearVar.Name = "Year"
    yearVar.Value = 0
    monthVar = Instance.new("IntValue", game.Lighting)
    monthVar.Name = "Month"
    monthVar.Value = 0
    dayVar = Instance.new("IntValue", game.Lighting)
    dayVar.Name = "Day"
    dayVar.Value = 0
    hourVar = Instance.new("IntValue", game.Lighting)
    hourVar.Name = "Hour"
    hourVar.Value = 0
    minuteVar = Instance.new("IntValue", game.Lighting)
    minuteVar.Name = "Minute"
    minuteVar.Value = 0
    secondVar = Instance.new("IntValue", game.Lighting)
    secondVar.Name = "Second"
    secondVar.Value = 0
    dayOfWeek = Instance.new("StringValue", game.Lighting)
    dayOfWeek.Name = "DayOfWeek"
    dayOfWeek.Value = "Thursday"
end
function giveZero(data)
    if string.len(data) <= 1 then
        return "0" .. data
    else
        return data
    end
end
function hasDecimal(value)
    if not(value == math.floor(value)) then
        return true
    else
        return false
    end
end
function isLeapYear(year)
    if(not hasDecimal(year / 4)) then
        if(hasDecimal(year / 100)) then
            return true
        else
            if(not hasDecimal(year / 400)) then
                return true
            else
                return false
            end
        end
    else
        return false
    end
end
local eYear = 1970
local timeStampDayOfWeak = 5
local secondsInHour = 3600
local secondsInDay = 86400
local secondsInYear = 31536000
local secondsInLeapYear = 31622400
local monthWith28 = 2419200
local monthWith29 = 2505600
local monthWith30 = 2592000
local monthWith31 = 2678400
local monthsWith30 = {4, 6, 9, 11}
local monthsWith31 = {1, 3, 5, 7, 8, 10, 12}
local daysSinceEpoch = 0
local DOWAssociates = {"Tursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday"}
while(true) do
    now = tick()
    year = 1970
    secs = 0
    daysSinceEpoch = 0
    while((secs + secondsInLeapYear) < now or (secs + secondsInYear) < now) do
        if(isLeapYear(year+1)) then
            if((secs + secondsInLeapYear) < now) then
                secs = secs + secondsInLeapYear
                year = year + 1
                daysSinceEpoch = daysSinceEpoch + 366
            end
        else
            if((secs + secondsInYear) < now) then
                secs = secs + secondsInYear
                year = year + 1
                daysSinceEpoch = daysSinceEpoch + 365
            end
        end
    end
    secondsRemaining = now - secs
    monthSecs = 0
    yearIsLeapYear = isLeapYear(year)
    month = 1 -- January
    while((monthSecs + monthWith28) < secondsRemaining or (monthSecs + monthWith30) < secondsRemaining or (monthSecs + monthWith31) < secondsRemaining) do
        if(month == 1) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 2
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 2) then
            if(not yearIsLeapYear) then
                if((monthSecs + monthWith28) < secondsRemaining) then
                    month = 3
                    monthSecs = monthSecs + monthWith28
                    daysSinceEpoch = daysSinceEpoch + 28
                else
                    break
                end
            else
                if((monthSecs + monthWith29) < secondsRemaining) then
                    month = 3
                    monthSecs = monthSecs + monthWith29
                    daysSinceEpoch = daysSinceEpoch + 29
                else
                    break
                end
            end
        end
        if(month == 3) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 4
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 4) then
            if((monthSecs + monthWith30) < secondsRemaining) then
                month = 5
                monthSecs = monthSecs + monthWith30
                daysSinceEpoch = daysSinceEpoch + 30
            else
                break           
            end
        end
        if(month == 5) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 6
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 6) then
            if((monthSecs + monthWith30) < secondsRemaining) then
                month = 7
                monthSecs = monthSecs + monthWith30
                daysSinceEpoch = daysSinceEpoch + 30
            else
                break
            end
        end
        if(month == 7) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 8
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 8) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 9
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 9) then
            if((monthSecs + monthWith30) < secondsRemaining) then
                month = 10
                monthSecs = monthSecs + monthWith30
                daysSinceEpoch = daysSinceEpoch + 30
            else
                break
            end
        end
        if(month == 10) then
            if((monthSecs + monthWith31) < secondsRemaining) then
                month = 11
                monthSecs = monthSecs + monthWith31
                daysSinceEpoch = daysSinceEpoch + 31
            else
                break
            end
        end
        if(month == 11) then
            if((monthSecs + monthWith30) < secondsRemaining) then
                month = 12
                monthSecs = monthSecs + monthWith30
                daysSinceEpoch = daysSinceEpoch + 30
            else
                break
            end
        end
    end
    day = 1 -- 1st
    daySecs = 0
    daySecsRemaining = secondsRemaining - monthSecs
    while((daySecs + secondsInDay) < daySecsRemaining) do
        day = day + 1
        daySecs = daySecs + secondsInDay
        daysSinceEpoch = daysSinceEpoch + 1
    end
    hour = 0 -- Midnight
    hourSecs = 0
    hourSecsRemaining = daySecsRemaining - daySecs
    while((hourSecs + secondsInHour) < hourSecsRemaining) do
        hour = hour + 1
        hourSecs = hourSecs + secondsInHour
    end
    minute = 0 -- Midnight
    minuteSecs = 0
    minuteSecsRemaining = hourSecsRemaining - hourSecs
    while((minuteSecs + 60) < minuteSecsRemaining) do
        minute = minute + 1
        minuteSecs = minuteSecs + 60
    end
    second = math.floor(now % 60)
    year = giveZero(year)
    month = giveZero(month)
    day = giveZero(day)
    hour = giveZero(hour)
    minute = giveZero(minute)
    second = giveZero(second)
    remanderForDOW = daysSinceEpoch % 7
    DOW = DOWAssociates[remanderForDOW + 1]
    if(createVariable) then
        yearVar.Value = year
        monthVar.Value = month
        dayVar.Value = day
        hourVar.Value = hour
        minuteVar.Value = minute
        secondVar.Value = second
        dayOfWeek.Value = DOW
    end
    if(outputTime) then
        str = "Year: " .. year .. ", Month: " .. month .. ", Day: " .. day .. ", Hour: " .. hour .. ", Minute: " .. minute .. ", Second: ".. second .. ", Day of Week: " .. DOW
        print(str)
    end
    wait(1)
end

----原帖----

如果没有任何资源,只有自Epoch以来的秒数,如何计算以下内容的公式?

这是我需要的列表:

当前月份:例如7

当前日期:例如25

当前星期几:例如星期四(1-7也可以)

当前小时数:例如22

当前分钟数:例如34

当前秒数:例如07

6个回答

9

以下是一些从谷歌找到的 C 代码改编而来的 Lua 代码。它没有处理时区或夏令时,因此输出结果是指协调世界时(UTC)。

-- based on http://www.ethernut.de/api/gmtime_8c_source.html

local floor=math.floor

local DSEC=24*60*60 -- secs in a day
local YSEC=365*DSEC -- secs in a year
local LSEC=YSEC+DSEC    -- secs in a leap year
local FSEC=4*YSEC+DSEC  -- secs in a 4-year interval
local BASE_DOW=4    -- 1970-01-01 was a Thursday
local BASE_YEAR=1970    -- 1970 is the base year

local _days={
    -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
}
local _lpdays={}
for i=1,2  do _lpdays[i]=_days[i]   end
for i=3,13 do _lpdays[i]=_days[i]+1 end

function gmtime(t)
print(os.date("!\n%c\t%j",t),t)
    local y,j,m,d,w,h,n,s
    local mdays=_days
    s=t
    -- First calculate the number of four-year-interval, so calculation
    -- of leap year will be simple. Btw, because 2000 IS a leap year and
    -- 2100 is out of range, this formula is so simple.
    y=floor(s/FSEC)
    s=s-y*FSEC
    y=y*4+BASE_YEAR         -- 1970, 1974, 1978, ...
    if s>=YSEC then
        y=y+1           -- 1971, 1975, 1979,...
        s=s-YSEC
        if s>=YSEC then
            y=y+1       -- 1972, 1976, 1980,... (leap years!)
            s=s-YSEC
            if s>=LSEC then
                y=y+1   -- 1971, 1975, 1979,...
                s=s-LSEC
            else        -- leap year
                mdays=_lpdays
            end
        end
    end
    j=floor(s/DSEC)
    s=s-j*DSEC
    local m=1
    while mdays[m]<j do m=m+1 end
    m=m-1
    local d=j-mdays[m]
    -- Calculate day of week. Sunday is 0
    w=(floor(t/DSEC)+BASE_DOW)%7
    -- Calculate the time of day from the remaining seconds
    h=floor(s/3600)
    s=s-h*3600
    n=floor(s/60)
    s=s-n*60
    print("y","j","m","d","w","h","n","s")
    print(y,j+1,m,d,w,h,n,s)
end

local t=os.time()
gmtime(t)

t=os.time{year=1970, month=1, day=1, hour=0} gmtime(t)
t=os.time{year=1970, month=1, day=3, hour=0} gmtime(t)
t=os.time{year=1970, month=1, day=2, hour=23-3, min=59, sec=59} gmtime(t)

3

这个公式并不简单,尤其是在闰年时。建议您使用此页面上的date函数,而不是试图自己计算。


1
我无法使用date()函数,我的唯一选择是自己计算。 - ProtectedMethod
1
只是让你知道,我正在使用沙盒版本的Lua。时间的唯一访问方式是自纪元以来的秒数。 - ProtectedMethod
1
我也无法导入或包含任何东西。 - ProtectedMethod
1
好的,那么请看这个问题:https://dev59.com/xWw05IYBdhLWcg3wnjAk - Vyassa Baratham

2

一个更快的解决方案是使用我的方法,我并没有看到其他人使用过,因为大多数人都可以访问os.date()。

由于我无法访问os.date(),这是我的解决方案:

local tabIndexOverflow = function(seed, table)
    -- This subtracts values from the table from seed until an overflow
    -- This can be used for probability :D
    for i = 1, #table do
        if seed - table[i] <= 0 then
            return i, seed
        end
        seed = seed - table[i]
    end
end

local getDate = function(unix)
    -- Given unix date, return string date
    assert(unix == nil or type(unix) == "number" or unix:find("/Date%((%d+)"), "Please input a valid number to \"getDate\"")
    local unix = (type(unix) == "string" and unix:match("/Date%((%d+)") / 1000 or unix or os.time()) -- This is for a certain JSON compatability. It works the same even if you don't need it

    local dayCount, year, days, month = function(yr) return (yr % 4 == 0 and (yr % 100 ~= 0 or yr % 400 == 0)) and 366 or 365 end, 1970, math.ceil(unix/86400)

    while days >= dayCount(year) do days = days - dayCount(year) year = year + 1 end -- Calculate year and days into that year

    month, days = tabIndexOverflow(days, {31,(dayCount(year) == 366 and 29 or 28),31,30,31,30,31,31,30,31,30,31}) -- Subtract from days to find current month and leftover days

--  hours = hours > 12 and hours - 12 or hours == 0 and 12 or hours -- Change to proper am or pm time
--  local period = hours > 12 and "pm" or "am"

--  Formats for you!
--  string.format("%d/%d/%04d", month, days, year) 
--  string.format("%02d:%02d:%02d %s", hours, minutes, seconds, period)
    return {Month = month, day = days, year = year, hours = math.floor(unix / 3600 % 24), minutes = math.floor(unix / 60 % 60), seconds = math.floor(unix % 60)}
end

然而,当涉及到寻找星期几时,你需要自己解决。我从未关心过它是Thor的日子还是Frige的日子。


2
你可以使用luatz
x = 1234567890
t = require "luatz.timetable".new_from_timestamp ( x )

print(t.year,t.month,t.day,t.hour,t.min,t.sec,t.yday,t.wday)
-- Or just
print(t:rfc_3339())

2
请注意,luatz是一个纯lua库,如果您愿意,可以直接复制/粘贴src/timetable.lua中的代码。 - daurnimator

2
这是我处理 IT 技术的方法。
> time0=os.time()
> time0
1571439964
> os.date("%Y%m%d%H%M%S",time0)
20191019120604
>

1

os.date是Lua的标准函数,如果将第一个参数传递为"%t",它将返回一个包含以下字段的表:year(四位数),month(1-12),day(1-31),hour(0-23),min(0-59),sec(0-61),wday(星期几,星期日为1),yday(一年中的天数)和isdst(夏令时标志,布尔值)。

给它一个测试:

time = os.time()
print("time since epoch: " .. time)
date = os.date("*t", time)
print("year: " .. date.year)
print("month: " .. date.month)
print("day: " .. date.day)
print("hour: " .. date.hour)
print("minute: " .. date.min)
print("second: " .. date.sec)
print("weekday: " .. date.wday)

输出:

time since epoch: 1374826427
year: 2013
month: 7
day: 26
hour: 16
minute: 13
second: 47
weekday: 6

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接