Работа с временем в Lua
Давайте сразу определимся. В Lua нет понятия «Календарная дата». Есть понятие «время», которое включает в себя как цифру в календаре, так и показания стрелок будильника. Поэтому в дальнейшем будем оперировать термином «время», подразумевая, что оно включает в себя и день/месяц/год и все остальное.
Для хранения времени в Lua 5.1 используются 2 типа данных.
Первый – это таблица с полями
- year (год, четыре цифры)
- month (месяц, 1 – 12)
- day (день, 1 – 31)
- hour (час, 0 – 23)
- min (минуты, 0 – 59)
- sec (секунды, 0 – 61)
- wday (день недели, воскресенью соответствует 1)
- yday (день года)
- isdst (флаг дневного времени суток, тип boolean).
Давайте в дальнейшем такую таблицу именовать как таблицу datetime. Эта таблица может использоваться как в качестве параметра для функций даты/времени языка lua, так и в качестве возвращаемого результата. Взависимости от контекста не все поля требуют заполнения.
Второй формат хранения даты и времени – это так называемый Posix формат времени (или Unix-время). Изобретать определение не смысла, Википедия нам в помощь:
UNIX-время (англ. Unixtime) или POSIX-время — система описания моментов во времени, принятая в UNIX и других POSIX-совместимых операционных системах. Определяется как количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года (четверг); время с этого момента называют «эрой (эпохой) UNIX» (англ. UnixEpoch).
Время UNIX согласуется с UTC — в частности, при объявлении високосных секунд UTC соответствующие номера секунд повторяются, то есть високосные секунды не учитываются.
Представление времени в виде количества секунд удобно использовать для сравнения и хранения дат (дата и время в этом формате занимают всего 4 или 8 байтов). При необходимости обращения к элементам дат (день, месяц, год) секунды можно преобразовать в любой подходящий формат (и наоборот), но если такие преобразования выполняются часто, они снижают производительность.
Я отдельно подчеркну удобство posix формата времени. Мы можем легко прибавлять, вычитать, сравнивать и находить разницу между двумя временными моментами путем простейших арифметических операций.
Теперь о функциях работы со временем, которые нам предоставляет Lua 5.1. Собственно, основных две:
- os.time ([table]) – преобразует таблицу datetime в posix
- os.date ([format [, time]]) – преобразует posix в таблицу datetime.
Как видно, они комплементарные. Однако на самом деле все намного интереснее. Давайте остановимся на каждой из них подробнее. В примерах ниже я буду использовать функцию print(). Если у Вас не установлен пакет Lua 5.1, а только терминал QUIK, замените print() на message()
1379094015 Надо иметь ввиду, что os.time() выдает не локальное время, а UTC. Это время отличается от локального на величину смещения часового пояса. Пример был выполнен на компьютере с установленным часовым поясом +4 часа (+0400) Замечу, что поля year, month и day обязательны, а остальные – нет. Если некотрые из них пропущены, то интерпретируются как нулевые. year = 2013 month = 9 day = 13 hour = 17 min = 40 sec = 15 weekday = 6 day of year = 256 iddst = false Первым параметром os.date() идет строка "!*t". Расшифрую. Если первый параметр начинается с '!', то время форматируется в соответствии с универсальным глобальным временем (по Гринвичу). Далее если следуют символы "*t", то os.date() возвращает таблицу datetime. 1379151677 Вызов os.time() без параметров позволяет получить системное время компьютера. 2013 9 14 10 28 11 7 257 false September 1 14:41:35 или Сейчас 14 часов 41 минут 35 секунд 02/28/13 В posix можно легко прибавлять и вычитать любые промежутки времени, выраженные в секундах Сегодня 14 September 2013, день недели 6 Следующий рабочий день 16 September 2013, день недели 1 субботаdatetime в posix
datetime = { year = 2013,
month = 09,
day = 13,
hour = 21,
min = 40,
sec = 15
}
seconds_since_epoch = os.time(datetime)
print(tostring(seconds_since_epoch))
posix в datetime
seconds_since_epoch = 1379094015
datetime = os.date("!*t",seconds_since_epoch)
print( "year = " .. tostring(datetime.year) .. " " ..
" month = " .. tostring(datetime.month) .. " " ..
"day = " .. tostring(datetime.day) .. " " ..
"hour = " .. tostring(datetime.hour) .. " " ..
"min = " .. tostring(datetime.min) .. " " ..
"sec = " .. tostring(datetime.sec) .. " " ..
"weekday = " .. tostring(datetime.wday) .. " " ..
"day of year = " .. tostring(datetime.yday) .. " " ..
" iddst = " .. tostring(datetime.isdst))Получение текущего времени в формате posix
print(os.time())
Текущее времени в формат datetime
datetime = os.date("!*t",os.time())
print( tostring(datetime.year) .. " " ..
tostring(datetime.month) .. " " ..
tostring(datetime.day) .. " " ..
tostring(datetime.hour) .. " " ..
tostring(datetime.min) .. " " ..
tostring(datetime.sec) .. " " ..
tostring(datetime.wday) .. " " ..
tostring(datetime.yday) .. " " ..<
tostring(datetime.isdst))
Варианты работы os.date()
%a
abbreviated weekday name (e.g., Wed)
%A
full weekday name (e.g., Wednesday)
%b
abbreviated month name (e.g., Sep)
%B
full month name (e.g., September)
%c
date and time (e.g., 09/16/98 23:48:10)
%d
day of the month (16) [01-31]
%H
hour, using a 24-hour clock (23) [00-23]
%I
hour, using a 12-hour clock (11) [01-12]
%M
minute (48) [00-59]
%m
month (09) [01-12]
%p
either "am" or "pm" (pm)
%S
second (10) [00-61]
%U
sunday week of the year 00 (53)
%w
weekday (3) [0-6 = Sunday-Saturday]
%W
monday week of the year, from 00 (48)
%x
date (e.g., 09/16/98)
%X
time (e.g., 23:48:10)
%Y
full year (1998)
%y
two-digit year (98) [00-99]
%z
timezone string
%%
the character %
Какой сегодня месяц?
print(os.date("%B",os.time())
В какой день недели родилась моя дочь?
print(os.date("%w",os.time({ year=1997, month = 11, day = 10}))
Номер недели в году для 10 ноября 1997 года?
print(os.date("%W",os.time({ year=1997, month = 11, day = 10}) ))
45Текущая дата строкой
print(os.date("%d.%m.%Y"))
14.09.2013Текущее время строкой
print(os.date("%X",os.time()))
print(os.date("Сейчас %H часов %M минут %S секунд",os.time()))
Текущие время и дата строкой
print(os.date())
09/14/2013 22:35:36Какой день предшествовал 1 марта 2013 года?
datetime = { year = 2013,
month = 3,
day = 1
}
seconds_since_epoch = os.time(datetime) - 24 * 60 * 60
datestr = os.date("%x",seconds_since_epoch )
print(datestr)Когда будет следующий рабочий день?
datetime = os.time()
weekday = os.date("%w",datetime)
print(os.date("Сегодня %d %B %Y, день недели " .. weekday,datetime))
if weekday == "6" then -- суббота
diff_time = 2 * 24 * 60 * 60
else
diff_time = 24 * 60 * 60
end<
print(os.date("Следующий рабочий день %d %B %Y, день недели %w" ,datetime + diff_time))
Как получить название дня недели?
datetime = os.time()
weekday = os.date("%w",datetime)
weekdays = {
["0"] = "воскресенье",
["1"] = "понедельник",
["2"] = "вторник",
["3"] = "среда",
["4"] = "четверг",
["5"] = "пятница",
["6"] = "суббота"
}
print(weekdays[weekday])Сейчас больше 12:44?
epoch_time = os.time()
datetime = os.date("!*t",epoch_time)
datetime.hour = 12
datetime.min = 44
datetime.sec = 0
print(tostring(os.time(datetime) > epoch_time))Преобразование строки даты в datetime
Для формата DD.MM.YYYY:
datetime = {}
datetime.day,datetine.month,datetime.year = string.match("13.09.2013","(%d*)\.(%d*)\.(%d*)")
Для формата YYYYMMDD:
datetime = {}
datetime.year,datetime.month,datetime.day = string.match("20130913","(%d%d%d%d)(%d%d)(%d%d)")
Замечу, что в обоих случаях string.match() выдает текстовые строки, а не числовые значения, которые сохраняются в datetime. Тем не менее os.time() прекрасно это понимает.Преобразование строки времени в datetime
datetime={}
datetime.hour,datetime.min,datetime.sec = string.match("21:17:43","(%d%d)%p(%d%d)%p(%d%d)")
Нужно четко понимать, что вычисления идут в локальном времени Гринвича. Москва находится в другом часовом поясе, который еще и меняется в зависимости от текущего кремлёвского рулевого персонажа.
См. также:
Искал как узнать последний день месяца в Lua и нашел у вас.
Нужен запрет на действия в определенные часы/минуты.
часы*3600 + минуты*60 + секунды.
Проверяйте, попадает ли это число в заранее заданный диапазон.
Спасибо за ответ!
А если проще сделать, если не требуется точность до секунд: получать минуты из os.sysdate() и выполнять действия если они не равны 00, например. Так нормально должно работать?
До этого пробовал получать серверное время, переводить его в строку, отбрасывать секунды и сравнивать со строками "10:00", "10:30" и т.д. Но такой чудной фильтр иногда проскакивал мимо ненужного времени. Вот не возникнет ли пропусков если сделать как я выше написал?
Не изобретайте велосипед. Напишите один раз и на все случаи жизни отдельную универсальную функцию/модуль и пользуйтесь ей во всех своих роботах.
Поэтому, как вы и написали, вариант постоянной проверки времени есть наиболее простой и надежный.
Он не займет много ресурсов процессора, если вызывать его раз в секунду, поэтому на производительно сти скрипта никак не скажется. Единственное, что нужно учесть- это проверять время не на совпадение с 23-50, а на превышение его и при этом устанавливать флаг, что сегодня уже сохранение было. При наступлении следующего дня флаг нужно очищать. Дело в том, что нет гарантий, что ваш скрипт проверит время именно в нужную вам секунду и вы можете пропустить момент сохранения.
RSS лента комментариев этой записи