Resource icon

OBS Lua Datetime digital clock 2019-12-24

erikfdev

New Member
The script makes OBS crash when the syntax of the date-time format you enter as parameter is not correct.
Be aware that the format is evaluated every second. For this reason, make sure that you enter an additional % and its valid character very quickly.
 

avgjoefriday

New Member
I have done several modifications to the script to accommodate timezone in the format specifiers and appending st, nd, rd th to the day of month.

Richard,
THANK YOU so much for your additions to this plugin! (And thanks to the original author too!)
If you have a moment, could you add a way to drop the leading zero from the day and month?
Much thanks!
 

avgjoefriday

New Member
Here is a new and improved version that includes Richard's additions as well as the ability to get the hour, day, month without the leading zero. Also someone had asked in an earlier question how to get a blank line between the parts, you can use %n to get a new line in your string.

Best!
Lua:
--[[ OBS Studio datetime script

This script transforms a text source into a digital clock. The datetime format
is configurable and uses the same syntax than the Lua os.date() call.
https://www.lua.org/pil/22.1.html
v1 - Created by Albin Kauffmann (albinou)  https://gitlab.com/albinou/obs-scripts/-/blob/master/datetime.lua
v2 - Revisions by Richard Gagnon
    added %dx   day of month with st,rd,th,nd (01st) [01-31]\
    noted %z
    noted %Z
    fixed ability to choose Text Source
v3 - Revisions by Scott Hardwick
    added %dn    day of the month as a decimal number [1-31]
    added %mn    month as a decimal number [1-12]
    added %In    hour, using a 12-hour clock as a decimal number [1-12]
    noted %n
]]

obs             = obslua
source_name     = ""
datetime_format = ""

activated       = false


-- Function to set the time text
function set_datetime_text(source, format)
    if string.find(format, "%%dx") ~= nil then
        local s = "thstndrd"
        local i = 0
        local x = 0
        local d = os.date("%d")
        x = tonumber(d) -- make the day string a number
        if x < 4 or x > 20 then
            i = tonumber(d.sub(d, -1)) * 2 -- get the number value of the last digit and multiple by 2 for indexing into s
            if i > 6 then
                i = 0
            end
        end
        format = format.gsub(format, "%%dx", tostring(x)..string.sub(s, i + 1, i + 2))
    end
    if string.find(format, "%%dn") ~= nil then
        local x = 0
        local d = os.date("%d")
        x = tonumber(d) -- make the day string a number
        format = format.gsub(format, "%%dn", tostring(x))
    end
    if string.find(format, "%%mn") ~= nil then
        local x = 0
        local d = os.date("%m")
        x = tonumber(d) -- make the month string a number
        format = format.gsub(format, "%%mn", tostring(x))
    end
    if string.find(format, "%%In") ~= nil then
        local x = 0
        local d = os.date("%I")
        x = tonumber(d) -- make the hour (12 hour clock) string a number
        format = format.gsub(format, "%%In", tostring(x))
    end
    local text = os.date(format)
    local settings = obs.obs_data_create()

    obs.obs_data_set_string(settings, "text", text)
    obs.obs_source_update(source, settings)
    obs.obs_data_release(settings)
end

function timer_callback()
    local source = obs.obs_get_source_by_name(source_name)
    if source ~= nil then
        set_datetime_text(source, datetime_format)
        obs.obs_source_release(source)
    end
end

function activate(activating)
    if activated == activating then
        return
    end

    activated = activating

    if activating then
        obs.timer_add(timer_callback, 1000)
    else
        obs.timer_remove(timer_callback)
    end
end

-- Called when a source is activated/deactivated
function activate_signal(cd, activating)
    local source = obs.calldata_source(cd, "source")
    if source ~= nil then
        local name = obs.obs_source_get_name(source)
        if (name == source_name) then
            activate(activating)
        end
    end
end

function source_activated(cd)
    activate_signal(cd, true)
end

function source_deactivated(cd)
    activate_signal(cd, false)
end

function reset()
    activate(false)
    local source = obs.obs_get_source_by_name(source_name)
    if source ~= nil then
        local active = obs.obs_source_showing(source)
        obs.obs_source_release(source)
        activate(active)
    end
end

----------------------------------------------------------

function script_description()
return "Sets a text source to act as a clock when the source is active.\
\
The datetime format can use the following tags:\
\
%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]\
%dn    day of the month as a decimal number [1-31]\
%dx day of month with st,rd,th,nd (01st) [01-31]\
%H hour, using a 24-hour clock (23) [00-23]\
%I hour, using a 12-hour clock (11) [01-12]\
%In    hour, using a 12-hour clock as a decimal number [1-12]\
%M minute (48) [00-59]\
%m month (09) [01-12]\
%mn    month as a decimal number [1-12]\
%p either \"am\" or \"pm\" (pm)\
%S second (10) [00-61]\
%w weekday (3) [0-6 = Sunday-Saturday]\
%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 (0600)\
%Z timezone (Mountain Standard Time)\
%n newline\
%% the character `%´"
end

function script_properties()
    local props = obs.obs_properties_create()

    obs.obs_properties_add_text(props, "format", "Datetime format", obs.OBS_TEXT_DEFAULT)

    local p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
    local sources = obs.obs_enum_sources()
    if sources ~= nil then
        for _, source in ipairs(sources) do
            -- THIS LINE IS INCORRECT use following line source_id = obs.obs_source_get_id(source)
            source_id = obs.obs_source_get_unversioned_id(source)
            if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
                local name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
            end
        end
    end
    obs.source_list_release(sources)

    return props
end

function script_defaults(settings)
    obs.obs_data_set_default_string(settings, "format", "%X")
end

function script_update(settings)
    activate(false)

    source_name = obs.obs_data_get_string(settings, "source")
    datetime_format = obs.obs_data_get_string(settings, "format")

    reset()
end

function script_load(settings)
    local sh = obs.obs_get_signal_handler()
    obs.signal_handler_connect(sh, "source_show", source_activated)
    obs.signal_handler_connect(sh, "source_hide", source_deactivated)
end
 

fruv

New Member
Is it possible to manually set a timezone? IE I'm in EST (-4) but want to display PST (-7)
 

albinou

New Member
Is it possible to change the language to german?
As @erikfdev mentioned, you need to change the locale in order to change the language. Update the start of the set_date_time() function with something like this (where "de_DE.UTF-8" is the German locale):

Lua:
function set_datetime_text(source, format)
   -- save the current locale "time" setting
    local locale_backup = os.setlocale(nil, "time")
   -- set our own "time" locale setting
    os.setlocale("de_DE.UTF-8", "time")
    
    local text = os.date(format)
    -- restore the original "time" locale setting
    os.setlocale(locale_backup, "time")
    
    local settings = obs.obs_data_create()
    ...
    ...

PS: I only noticed all this discussion about my script. Thanks guys for your reactions!
 

albinou

New Member
Is it possible to manually set a timezone? IE I'm in EST (-4) but want to display PST (-7)

Yes, with a script update. Indeed, os.date() can be called with a second argument (the date to display, in seconds). This date can obtained with a call to os.time().

So if you want to display time at PST (-7), which the same than UTC-8 I guess, you can replace the os.date() call with:
Lua:
local text = os.date(format, os.time() * - 8 * 60 * 60)

Not tested, but I guess it would work.
 

untukku

New Member
Datetime digital clock 2019-12-24.png


how to make it look like my screenshot? display HOUR above its position and DATE below its position, with Indonesian not English.
 

untukku

New Member
Did you to use a "\n" into the date & time format? ("\n" is a line break).

And in order to get the Indonesian date, you should change the locale (to "id_ID" I guess ?).
14 20 - 01-12-2021.png

Using \n still can't. What is the solution?
where in the lua script change or add the "id_ID"? I can't find it, fyi I'm not a programmer and don't understand coding.
 

JonathanC09

New Member
Hello, I am a Spanish speaker and I am using a translator. Excuse me if I'm writing wrong.

This script is impressive and thanks to previous comments I was able to put it in Spanish, so thank you very much to everyone who has contributed to this script.

Well, I would like to ask if is there any way to create a variant that displays a personalized message depending on the day of the week?

E.g. Sundays: Sunday Mass || Thursdays: Eucharistic Thursday. (I help in a church).

I know it would have to be something like
Code:
if "variable" == "value"
%ñ = "Sunday Mass"
but I don't know what that variable is or even if that's how it is written in this language. I appreciate any help.
 

ElektroHeld

New Member
Hello @albinou,
I did the work and wrote a small change in your script. It's not 100% perfect, but it works.

You may or may not want to include this in your next version, it's up to you.


Lua:
--[[ OBS Studio datetime script

This script transforms a text source into a digital clock. The datetime format
is configurable and uses the same syntax than the Lua os.date() call.
]]

obs             = obslua
source_name     = ""
datetime_format = ""
time_offset     = ""

activated       = false


-- Function to set the time text
function set_datetime_text(source, format)
    local time = os.time()
    local time = time - (60*60*11) + (60*60*time_offset)
    local text = os.date("!".. format, time)
    
    -- print(text)
    local settings = obs.obs_data_create()

    obs.obs_data_set_string(settings, "text", text)
    obs.obs_source_update(source, settings)
    obs.obs_data_release(settings)
end

function timer_callback()
    local source = obs.obs_get_source_by_name(source_name)
    if source ~= nil then
        set_datetime_text(source, datetime_format)
        obs.obs_source_release(source)
    end
end

function activate(activating)
    if activated == activating then
        return
    end

    activated = activating

    if activating then
        obs.timer_add(timer_callback, 1000)
    else
        obs.timer_remove(timer_callback)
    end
end

-- Called when a source is activated/deactivated
function activate_signal(cd, activating)
    local source = obs.calldata_source(cd, "source")
    if source ~= nil then
        local name = obs.obs_source_get_name(source)
        if (name == source_name) then
            activate(activating)
        end
    end
end

function source_activated(cd)
    activate_signal(cd, true)
end

function source_deactivated(cd)
    activate_signal(cd, false)
end

function reset()
    activate(false)
    local source = obs.obs_get_source_by_name(source_name)
    if source ~= nil then
        local active = obs.obs_source_showing(source)
        obs.obs_source_release(source)
        activate(active)
    end
end

----------------------------------------------------------

function script_description()
    return "Sets a text source to act as a clock when the source is active.\
\
The datetime format can use the following tags:\
\
    %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]\
    %w    weekday (3) [0-6 = Sunday-Saturday]\
    %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]\
    %%    the character `%´"
end

function script_properties()
    local props = obs.obs_properties_create()

    obs.obs_properties_add_text(props, "format", "Datetime format", obs.OBS_TEXT_DEFAULT)
    int = obs.obs_properties_add_list(props, "offset", "Houre offset", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_INT)
    obs.obs_property_list_add_int(int, "UTC", 11)
    obs.obs_property_list_add_int(int, "UTC + 1", 12)
    obs.obs_property_list_add_int(int, "UTC + 2", 13)
    obs.obs_property_list_add_int(int, "UTC + 3", 14)
    obs.obs_property_list_add_int(int, "UTC + 4", 15)
    obs.obs_property_list_add_int(int, "UTC + 5", 16)
    obs.obs_property_list_add_int(int, "UTC + 6", 17)
    obs.obs_property_list_add_int(int, "UTC + 7", 18)
    obs.obs_property_list_add_int(int, "UTC + 8", 19)
    obs.obs_property_list_add_int(int, "UTC + 9", 20)
    obs.obs_property_list_add_int(int, "UTC + 10", 21)
    obs.obs_property_list_add_int(int, "UTC + 11", 22)
    obs.obs_property_list_add_int(int, "UTC + 12", 23)
    obs.obs_property_list_add_int(int, "UTC - 1", 10)
    obs.obs_property_list_add_int(int, "UTC - 2", 9)
    obs.obs_property_list_add_int(int, "UTC - 3", 8)
    obs.obs_property_list_add_int(int, "UTC - 4", 7)
    obs.obs_property_list_add_int(int, "UTC - 5", 6)
    obs.obs_property_list_add_int(int, "UTC - 6", 5)
    obs.obs_property_list_add_int(int, "UTC - 7", 4)
    obs.obs_property_list_add_int(int, "UTC - 8", 3)
    obs.obs_property_list_add_int(int, "UTC - 9", 2)
    obs.obs_property_list_add_int(int, "UTC - 10", 1)
    obs.obs_property_list_add_int(int, "UTC - 11", 0)

    local p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
    local sources = obs.obs_enum_sources()
    if sources ~= nil then
        for _, source in ipairs(sources) do
            source_id = obs.obs_source_get_id(source)
            if source_id == "text_gdiplus_v2" or source_id == "text_ft2_source_v2" then
                local name = obs.obs_source_get_name(source)
                obs.obs_property_list_add_string(p, name, name)
            end
        end
    end
    obs.source_list_release(sources)

    return props
end

function script_defaults(settings)
    obs.obs_data_set_default_string(settings, "format", "%X")
end

function script_update(settings)
    activate(false)

    source_name = obs.obs_data_get_string(settings, "source")
    datetime_format = obs.obs_data_get_string(settings, "format")
    time_offset = obs.obs_data_get_int(settings, "offset")

    reset()
end

function script_load(settings)
    local sh = obs.obs_get_signal_handler()
    obs.signal_handler_connect(sh, "source_show", source_activated)
    obs.signal_handler_connect(sh, "source_hide", source_deactivated)
end
 

Rediflow

New Member
Is there a way to change the language of the shown date?
at my Windows System and my OBS, wich are both completely run in German settings, Days and months are presented by this lua script in English. How could I make it apere in German, or French or Italien etc...?
 

AlphaThemis

New Member
Can some one help I am getting this error and Idk why it happens.


[clock1.lua] Error loading file: /Users/bur/Desktop/clock1.lua:1: unexpected symbol near '{'
 
Top