How would I make it so that an event always happens on a half hour. e.g 4:30pm or 9am
you can use os.date with the minute parameter and then check if its divisible by 30
while task.wait(1) do
local isHalfMinute = os.date("%M") % 30 == 0
end
this might be a bit overkill but this is what i use:
--- returns a timestamp of current utc time with respect to format option or time in minutes
function Encoder.timestamp(format:
| number
| "Hour"
| "Biphase"
| "Day"
| "Week"
| "Season"
| "Biseason"
| "Year"
)
local T0 = os.date("!*t")
local T1 = table.clone(T0)
local timestamp = {
--- unique, non-recurring string describing format time
Id = "";
--- unique, non-recurring number describing format time
Seed = 0;
--- time until format changes
Until = 0;
}
if type(format) == "number" then
--- `Format: 5`
--- `February 14, 2024, 06:44` --> `"2024_45_6_8"`
--- `Format: 10`
--- `February 14, 2024, 06:44` --> `"2024_45_6_4"`
--- `Format: 15`
--- `February 14, 2024, 06:44` --> `"2024_45_6_2"`
T1.min = format * math.ceil((T1.min + 1) / format)
T1.sec = 0
local year, yday, hour, qtrhour = T0.year, T0.yday, T0.hour, math.ceil((T0.min + 1) / format) - 1
timestamp.Id = string.format("%d_%d_%d_%d", year, yday, hour, qtrhour)
timestamp.Seed = tonumber(year .. yday .. hour .. qtrhour) :: number
else
if format == "Hour" then
--- `February 14, 2024, 06:44` --> `"2024_45_6"`
T1.hour = math.floor(T1.hour + 1)
T1.min = 0
T1.sec = 0
local year, yday, hour = T0.year, T0.yday, T0.hour
timestamp.Id = string.format("%d_%d_%d", year, yday, hour)
timestamp.Seed = tonumber(year .. yday .. hour) :: number
elseif format == "Biphase" then
--- `February 14, 2024, 06:44` --> `"2024_45_AM"`
--- `February 14, 2024, 16:44` --> `"2024_45_PM"`
T1.hour = 12 * math.ceil((T1.hour + 1) / 12)
T1.min = 0
T1.sec = 0
local year, yday, phase = T0.year, T0.yday, os.date("!%p")
timestamp.Id = string.format("%d_%d_%s", year, yday, phase)
timestamp.Seed = tonumber(year .. yday .. string.byte(phase)) :: number
elseif format == "Day" then
--- `February 14, 2024` --> `"2024_45"`
T1.day += 1
T1.hour = 0
T1.min = 0
T1.sec = 0
local year, yday = T0.year, T0.yday
timestamp.Id = string.format("%d_%d", year, yday)
timestamp.Seed = tonumber(year .. yday) :: number
elseif format == "Week" then
--- `February 14, 2024` --> `"2024_7_06"` (06th week of 2024)
T1.day += 8 - T0.wday
T1.hour = 0
T1.min = 0
T1.sec = 0
local year, week, yweek = T0.year, T0.wday, os.date("!%U")
timestamp.Id = string.format("%d_%d_%s", year, week, yweek)
timestamp.Seed = tonumber(year .. week .. yweek) :: number
elseif format == "Season" then
--- `February 14, 2024` --> `"2024_1"`
--- Mar-May: `1` (spring)
--- Jun-Aug: `2` (summer)
--- Sep-Nov: `3` (fall)
--- Dec-Feb: `4` (winter)
T1.month += 1 + ((11 - math.ceil((T1.month - 3) % 12)) % 3)
T1.day = 1
T1.hour = 0
T1.min = 0
T1.sec = 0
local year, month = T0.year, math.ceil((1 + ((T0.month - 3) % 12)) / 3)
timestamp.Id = string.format("%d_%d", year, month)
timestamp.Seed = tonumber(year .. month) :: number
elseif format == "Biseason" then
--- `February 14, 2024` --> `"2024_1"`
--- Jan-Jun: `1` (SS)
--- Jul-Dec: `2` (FW)
T1.month = math.ceil(T1.month / 6)
T1.day = 1
T1.hour = 0
T1.min = 0
T1.sec = 0
local year, month = T0.year, math.ceil(T0.month / 6)
timestamp.Id = string.format("%d_%d", year, month)
timestamp.Seed = tonumber(year .. month) :: number
elseif format == "Year" then
--- `February 14, 2024` --> `"2024"`
T1.year += 1
T1.month = 1
T1.day = 1
T1.hour = 0
T1.min = 0
T1.sec = 0
timestamp.Id = tostring(T0.year)
timestamp.Seed = tonumber(T0.year) :: number
end
end
timestamp.Until = os.time(T1) - os.time(T0)
return timestamp
end
it can be accurate down to the minute and has no conflicts with servers in different timezones. i use it so my games have shared global weather and an hourly rotating store