Working with date / time in Lua
Posted: January 9th, 2018, 7:46 pm
One of the things that Lua is particularly good at is working with dates and times This can be valuable when you are parsing the <pubDate> from an RSS feed, or pretty much any other date/time string that you get from anywhere, and want to know how far in the past or the future the value is.
While there are good ways turn date/time strings into Windows timestamps in Rainmeter, using the Time measure, this can entail a ton of Time and Calc measures to deal with multiple date/time strings you might receive. Let's take a look at the basics of working with dates and times in Lua, and a couple of examples of how you might use this.
The basics: os.time() and os.date()
These are the two functions that do all the work with date and time in Lua. While the names are a bit confusing, in fact they both have to do with both date and time.
They are complementary. At its most basic, os.time() is used to "get or set" a date/time as a timestamp, based on a table of units, and os.date() is used to "format or break into a table of units" a date/time based on a timestamp. That is how they are in a sense "complementary". os.time() can use a table created by os.date() as its input, and os.date() can use a timestamp created by os.time() as its input.
So:
os.time() requires a {table} of units like year, month, day, hour, minute, second and returns a unix timestamp value.
os.date() requires a unix timestamp, and returns a {table} of units like year, month, day, hour, minute, second.
os.time()
First off, it is important to know that in Lua, all timestamps are based on the unix EPOCH time. That is defined as the number of seconds since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, minus the number of leap seconds that have taken place since then. Timestamps before 1970 will be negative. Don't trust results before about 1901.
The input to os.time() is a {table} of one or more of the following table index names:
year (4 digit year)
month (month 0-12)
day (1-31)
hour (24-hour 0-23)
min (minute 0-59)
sec (second 0-59)
isdst (daylight saving time, boolean true or false)
Example:
myTimeStamp = os.time({year=2001, month=9, day=11, hour=13, min=46})
Would return a unix EPOC timestamp of 1000215960, reflecting Tuesday, September 11, 2001 13:46:00 UTC
Current date / time
While we will get into the details of os.date() in a second, be aware that there are two "shortcuts" to get the current date and time into an os.time() function to return the current date / time as a timestamp.
currentLocalTime = os.time(os.date('*t'))
currentUTCTime = os.time(os.date('!*t'))
Note the ! in the second one...
This works because as noted earlier, the two functions are complementary. os.date() returns a table, and os.time() requires a table. All will become clear when we talk about os.date().
These will return either the timestamp of the current local time on your system, or of the current UTC time. In addition simply using:
currentLocalTime = os.time() will default to returning the current local time on your system.
Math with os.time()
Now that we have a unix EPOCH timestamp, a number of seconds, we can easily do "math" with that number.
inAnHour = os.time(os.date('*t')) + 3600
tomorrowSameTime = os.time(os.date('*t')) + 86400
secondsSince911=os.time(os.date('*!t')) - os.time({year=2001, month=9, day=11, hour=13, min=46})
os.date()
The os.date() function has two purposes:
1) Return a formatted string using the current time or a timestamp as input. Used to display a date / time.
2) Return a {table} of units like year, month, day, hour, minute, second using the current local or UTC time or a timestamp as input. Generally used as input to an os.time() function.
1) Formatting an os.date() string
In order to use os.date() to format a date / string, call the function with the first parameter being a 'mask string' that uses pretty much the same format codes as the Time measure in Rainmeter. These are:
The second parameter, completely optional, is a unix EPOCH timestamp number representing a date and time. The default if it is not used is the current local system date and time.
Examples:
prettyNow = os.date('%A, %B %d %Y at %I:%M:%S %p')
Might return Saturday, January 09 2018 at 12:42:19 AM.
pretty911 = os.date('%A, %B %d %Y at %H:%M UTC', 1000215960)
Would return Tuesday, September 11 2001 at 13:46 UTC.
prettyDerived911 = os.date('%A, %B %d %Y at %H:%M UTC', os.time({year=2001, month=9, day=11, hour=13, min=46}))
Would return Tuesday, September 11 2001 at 13:46 UTC.
While the default for the second timestamp parameter is the current local time, the current UTC time can also be used:
prettyNowUTC = os.date('%A, %B %d %Y at %I:%M:%S %p', os.time(os.date('!*t')))
2) Returning a table with os.date()
The other primary function of os.date() is to return a populated {table} of the current local or UTC date / time that can be used as input to os.time(). This is important, as any time you want to do "math" on a timestamp, any time you want to know "how long since" or "how long until", the first thing you need is "now" as a timestamp number.
This is done with two special mask strings on the os.date() function:
os.date('*t')
Returns a {table} representing the current local date / time.
os.date('!*t')
Returns a {table} representing the current UTC date / time.
In addition, os.date() can be used with an optional timestamp value as a second parameter, which will return the same table with the values for the defined timestamp. If the '*t' mask is used, the value is automatically adjusted to reflect your local offset from UTC and any DST settings. If the '!*t' mask is used, the value is treated at UTC and DST is ignored.
Again, the table values that are returned are:
year (4 digit year)
month (month 0-12)
day (1-31)
hour (24-hour 0-23)
min (minute 0-59)
sec (second 0-59)
isdst (daylight saving time, boolean true or false)
in addition, two other table fields are populated. They are not used with os.time() but can be useful for other purposes:
yday (day of the year 1-366)
wday (day of the week 1-7 - Sunday is 1)
You can use the table created as input to os.time() as:
nowTimestamp = os.time(os.date('*t'))
Returns a unix EPOC timestamp of the current local time.
And you can use the elements of the table for other purposes:
Note that tableName.indexName is a standard Lua table "shortcut", and is the same as nowHour = nowTable['hour'].
That's the basics of how os.time() and os.date() work in Lua. In our next post, we are going to look at some example skins that use them. Stay tuned...
While there are good ways turn date/time strings into Windows timestamps in Rainmeter, using the Time measure, this can entail a ton of Time and Calc measures to deal with multiple date/time strings you might receive. Let's take a look at the basics of working with dates and times in Lua, and a couple of examples of how you might use this.
The basics: os.time() and os.date()
These are the two functions that do all the work with date and time in Lua. While the names are a bit confusing, in fact they both have to do with both date and time.
They are complementary. At its most basic, os.time() is used to "get or set" a date/time as a timestamp, based on a table of units, and os.date() is used to "format or break into a table of units" a date/time based on a timestamp. That is how they are in a sense "complementary". os.time() can use a table created by os.date() as its input, and os.date() can use a timestamp created by os.time() as its input.
So:
os.time() requires a {table} of units like year, month, day, hour, minute, second and returns a unix timestamp value.
os.date() requires a unix timestamp, and returns a {table} of units like year, month, day, hour, minute, second.
os.time()
First off, it is important to know that in Lua, all timestamps are based on the unix EPOCH time. That is defined as the number of seconds since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970, minus the number of leap seconds that have taken place since then. Timestamps before 1970 will be negative. Don't trust results before about 1901.
The input to os.time() is a {table} of one or more of the following table index names:
year (4 digit year)
month (month 0-12)
day (1-31)
hour (24-hour 0-23)
min (minute 0-59)
sec (second 0-59)
isdst (daylight saving time, boolean true or false)
Example:
myTimeStamp = os.time({year=2001, month=9, day=11, hour=13, min=46})
Would return a unix EPOC timestamp of 1000215960, reflecting Tuesday, September 11, 2001 13:46:00 UTC
Current date / time
While we will get into the details of os.date() in a second, be aware that there are two "shortcuts" to get the current date and time into an os.time() function to return the current date / time as a timestamp.
currentLocalTime = os.time(os.date('*t'))
currentUTCTime = os.time(os.date('!*t'))
Note the ! in the second one...
This works because as noted earlier, the two functions are complementary. os.date() returns a table, and os.time() requires a table. All will become clear when we talk about os.date().
These will return either the timestamp of the current local time on your system, or of the current UTC time. In addition simply using:
currentLocalTime = os.time() will default to returning the current local time on your system.
Math with os.time()
Now that we have a unix EPOCH timestamp, a number of seconds, we can easily do "math" with that number.
inAnHour = os.time(os.date('*t')) + 3600
tomorrowSameTime = os.time(os.date('*t')) + 86400
secondsSince911=os.time(os.date('*!t')) - os.time({year=2001, month=9, day=11, hour=13, min=46})
os.date()
The os.date() function has two purposes:
1) Return a formatted string using the current time or a timestamp as input. Used to display a date / time.
2) Return a {table} of units like year, month, day, hour, minute, second using the current local or UTC time or a timestamp as input. Generally used as input to an os.time() function.
1) Formatting an os.date() string
In order to use os.date() to format a date / string, call the function with the first parameter being a 'mask string' that uses pretty much the same format codes as the Time measure in Rainmeter. These are:
Examples:
prettyNow = os.date('%A, %B %d %Y at %I:%M:%S %p')
Might return Saturday, January 09 2018 at 12:42:19 AM.
pretty911 = os.date('%A, %B %d %Y at %H:%M UTC', 1000215960)
Would return Tuesday, September 11 2001 at 13:46 UTC.
prettyDerived911 = os.date('%A, %B %d %Y at %H:%M UTC', os.time({year=2001, month=9, day=11, hour=13, min=46}))
Would return Tuesday, September 11 2001 at 13:46 UTC.
While the default for the second timestamp parameter is the current local time, the current UTC time can also be used:
prettyNowUTC = os.date('%A, %B %d %Y at %I:%M:%S %p', os.time(os.date('!*t')))
2) Returning a table with os.date()
The other primary function of os.date() is to return a populated {table} of the current local or UTC date / time that can be used as input to os.time(). This is important, as any time you want to do "math" on a timestamp, any time you want to know "how long since" or "how long until", the first thing you need is "now" as a timestamp number.
This is done with two special mask strings on the os.date() function:
os.date('*t')
Returns a {table} representing the current local date / time.
os.date('!*t')
Returns a {table} representing the current UTC date / time.
In addition, os.date() can be used with an optional timestamp value as a second parameter, which will return the same table with the values for the defined timestamp. If the '*t' mask is used, the value is automatically adjusted to reflect your local offset from UTC and any DST settings. If the '!*t' mask is used, the value is treated at UTC and DST is ignored.
Again, the table values that are returned are:
year (4 digit year)
month (month 0-12)
day (1-31)
hour (24-hour 0-23)
min (minute 0-59)
sec (second 0-59)
isdst (daylight saving time, boolean true or false)
in addition, two other table fields are populated. They are not used with os.time() but can be useful for other purposes:
yday (day of the year 1-366)
wday (day of the week 1-7 - Sunday is 1)
You can use the table created as input to os.time() as:
nowTimestamp = os.time(os.date('*t'))
Returns a unix EPOC timestamp of the current local time.
And you can use the elements of the table for other purposes:
Code: Select all
nowTable = os.date('*t')
nowYear = nowTable.year
nowHour = nowTable.hour
That's the basics of how os.time() and os.date() work in Lua. In our next post, we are going to look at some example skins that use them. Stay tuned...