Lua functions : os.date, os.tile & os.difftime.

Apr 4, 2014 at 11:29 AM
NeoLithos, here C# source code for Lua functions : os.date, os.time& os.difftime.

date(), time(), difftime() functions
    public class TestLuaGlobal : LuaGlobal
    {
        public TestLuaGlobal(Lua lua) : base(lua) { }

        protected override void OnPrint(string sText) { Console.WriteLine(sText); }

        /// <summary>
        /// Converts a number representing the date and time back to some higher-level representation. 
        /// </summary>
        /// <param name="format">Format string. Same format as the C <see href="http://www.cplusplus.com/reference/ctime/strftime/">strftime()</see> function.</param>
        /// <param name="time">Numeric date-time. It defaults to the current date and time.</param>
        /// <returns>Formatted date string, or table of time information.</returns>
        [LuaMember("date")]
        private object LuaDate(string format, object time)
        {
            // Unix timestamp is seconds past epoch. Epoch date for time_t is 00:00:00 UTC, January 1, 1970.
            DateTime unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            DateTime stm;

            var firstC = string.IsNullOrEmpty(format) ? (char?)null : format[0];
            if (firstC == '!')
            {
                // Date and time expressed as coordinated universal time (UTC).
                if (time == null) { stm = DateTime.UtcNow; }
                else { stm = unixStartTime.AddSeconds((int)time).ToUniversalTime(); }
                format = format.Substring(1);
            }
            else 
            {
                // Date and time adjusted to the local time zone.
                if (time == null) { stm = DateTime.Now; }
                else { stm = unixStartTime.AddSeconds((int)time).ToLocalTime(); }
            }

            if (String.Equals(format, "*t"))
            {
                LuaTable lt = new LuaTable();
                lt["year"] = stm.Year;
                lt["month"] = stm.Month;
                lt["day"] = stm.Day;
                lt["hour"] = stm.Hour;
                lt["min"] = stm.Minute;
                lt["sec"] = stm.Second;
                lt["wday"] = (int)stm.DayOfWeek;
                lt["yday"] = stm.DayOfYear;
                lt["isdst"] = (stm.Kind == DateTimeKind.Local ? true : false);
                return (lt);
            }
            else { return (stm.ToStrFTime(format)); }
        } // func date

        /// <summary>
        /// Calculate the current date and time, coded as a number. That number is the number of seconds since Epoch date, that is 00:00:00 UTC, January 1, 1970.
        /// When called with a table, it returns the number representing the date and time described by the table.
        /// </summary>
        /// <param name="table">Table representing the date and time</param>
        /// <returns>The time in system seconds. </returns>
        [LuaMember("time")]
        private LuaResult LuaTime(LuaTable table)
        {
            // Unix timestamp is seconds past epoch. Epoch date for time_t is 00:00:00 UTC, January 1, 1970.
            DateTime unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            DateTime dateTimeCurrent;
            TimeSpan timeSpanCurrent;

            if (table == null)
            {
                // Returns the current time when called without arguments
                timeSpanCurrent = DateTime.Now.Subtract(unixStartTime);  //DateTime.UtcNow.Subtract(unixStartTime);
            }
            else
            {
                try
                {
                    dateTimeCurrent = new DateTime(
                            table.ContainsKey("year") ? (int)table["year"] < 1970 ? 1970 : (int)table["year"] : 1970,
                            table.ContainsKey("month") ? (int)table["month"] : 1,
                            table.ContainsKey("day") ? (int)table["day"] : 1,
                            table.ContainsKey("hour") ? (int)table["hour"] : 0,
                            table.ContainsKey("min") ? (int)table["min"] : 0,
                            table.ContainsKey("sec") ? (int)table["sec"] : 0,
                            table.ContainsKey("isdst") ? (table.ContainsKey("isdst") == true) ? DateTimeKind.Local : DateTimeKind.Utc : DateTimeKind.Local
                        );
                    timeSpanCurrent = dateTimeCurrent.Subtract(unixStartTime);
                }
                catch (Exception e)
                {
                    return new LuaResult(null, e.Message);
                }
            }

            return new LuaResult(Convert.ToInt64(timeSpanCurrent.TotalSeconds));
        } // func time

        /// <summary>
        /// Calculate the number of seconds between time t1 to time t2. 
        /// </summary>
        /// <param name="t2">Higher bound of the time interval whose length is calculated.</param>
        /// <param name="t1">Lower bound of the time interval whose length is calculated. If this describes a time point later than end, the result is negative.</param>
        /// <returns>The number of seconds from time t1 to time t2. In other words, the result is t2 - t1.</returns>
        [LuaMember("difftime")]
        private Int64 LuaDiffTime(int t2, int t1)
        {
            int l1, l2;

            if (!int.TryParse(t1.ToString(), out l1)) { return 0; }
            if (!int.TryParse(t2.ToString(), out l2)) { return 0; }

            return l2 - l1;
        } // func difftime
    }
Apr 4, 2014 at 11:31 AM
This functions use strftime function.

strftime() function (strftime.cs)
using System;
using System.Collections.Generic;
using System.Globalization;

namespace AT.MIN
{
    public static class Tools
    {
        public delegate string DateTimeDelegate(DateTime dateTime);
        private static readonly Dictionary<string, DateTimeDelegate> Formats = new Dictionary<string, DateTimeDelegate>
        {
            // abbreviated weekday name (e.g., Wed)
            { "a", (dateTime) => dateTime.ToString("ddd", CultureInfo.CurrentCulture) },
            // full weekday name (e.g., Wednesday)
            { "A", (dateTime) => dateTime.ToString("dddd", CultureInfo.CurrentCulture) },
            // abbreviated month name (e.g., Sep)
            { "b", (dateTime) => dateTime.ToString("MMM", CultureInfo.CurrentCulture) },
            // full month name (e.g., September)
            { "B", (dateTime) => dateTime.ToString("MMMM", CultureInfo.CurrentCulture) },
            // date and time (e.g., 09/16/98 23:48:10)
            { "c", (dateTime) => dateTime.ToString("ddd MMM dd HH:mm:ss yyyy", CultureInfo.CurrentCulture) },
            // day of the month (16) (01-31)
            { "d", (dateTime) => dateTime.ToString("dd", CultureInfo.CurrentCulture) },
            // day of the month, space-padded ( 1-31)
            { "e", (dateTime) => dateTime.ToString("%d", CultureInfo.CurrentCulture).PadLeft(2, ' ') },
            // hour, using a 24-hour clock (00-23)
            { "H", (dateTime) => dateTime.ToString("HH", CultureInfo.CurrentCulture) },
            // hour, using a 12-hour clock (01-12)
            { "I", (dateTime) => dateTime.ToString("hh", CultureInfo.CurrentCulture) },
            // day of the year (001-366)
            { "j", (dateTime) => dateTime.DayOfYear.ToString().PadLeft(3, '0') },
            //month (01-12)
            { "m", (dateTime) => dateTime.ToString("MM", CultureInfo.CurrentCulture) },
            // minute (00-59)
            { "M", (dateTime) => dateTime.Minute.ToString().PadLeft(2, '0') },
            // either "AM" or "PM"
            { "p", (dateTime) => dateTime.ToString("tt",new CultureInfo("en-US")) },
            // second (00-59)
            { "S", (dateTime) => dateTime.ToString("ss", CultureInfo.CurrentCulture) },
            // week number with the first Sunday as the first day of week one (00-53)   
            { "U", (dateTime) => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(dateTime, CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule, DayOfWeek.Sunday).ToString().PadLeft(2, '0') },
            // week number with the first Monday as the first day of week one (00-53)
            { "W", (dateTime) => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(dateTime, CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule, DayOfWeek.Monday).ToString().PadLeft(2, '0') },
            // weekday as a decimal number with Sunday as 0 (0-6)
            { "w", (dateTime) => ((int) dateTime.DayOfWeek).ToString() },
            // date (e.g., 09/16/98)
            { "x", (dateTime) => dateTime.ToString("d", CultureInfo.CurrentCulture) },
            // time (e.g., 23:48:10)
            { "X", (dateTime) => dateTime.ToString("T", CultureInfo.CurrentCulture) },
            // two-digit year [00-99]
            { "y", (dateTime) => dateTime.ToString("yy", CultureInfo.CurrentCulture) },
            // full year (e.g., 2014)
            { "Y", (dateTime) => dateTime.ToString("yyyy", CultureInfo.CurrentCulture) },
            // Timezone name or abbreviation, If timezone cannot be termined, no characters
            { "Z", (dateTime) => dateTime.ToString("zzz", CultureInfo.CurrentCulture) },
            // the character `%´
            { "%", (dateTime) => "%" }
        };
        // http://www.cplusplus.com/reference/ctime/strftime/

        /// <summary>
        /// Format time as string
        /// </summary>
        /// <param name="dateTime">Instant in time, typically expressed as a date and time of day.</param>
        /// <param name="pattern">String containing any combination of regular characters and special format specifiers.They all begin with a percentage (%).</param>
        /// <returns>String with expanding its format specifiers into the corresponding values that represent the time described in dateTime</returns>
        public static string ToStrFTime(this DateTime dateTime, string pattern)
        {
            string output = "";
            int n = 0;

            if (string.IsNullOrEmpty(pattern)) { return dateTime.ToString(); }

            while (n < pattern.Length)
            {
                string s = pattern.Substring(n, 1);

                if (n + 1 >= pattern.Length)
                    output += s;
                else
                    output += s == "%"
                        ? Formats.ContainsKey(pattern.Substring(++n, 1)) ? Formats[pattern.Substring(n, 1)].Invoke(dateTime) : "%" + pattern.Substring(n, 1)
                        : s;
                n++;
            }

            return output;
        }
    }
}
Apr 4, 2014 at 11:35 AM
Edited Apr 4, 2014 at 11:38 AM
After integrayed in Lua script with Neolua you can do :
print('Unit NeoLua Test: os.date()')
print('====================')
print(os.date('Today is %A, in %B'))
--> Today is vendredi, in avril
print(os.date('%x', 906000490))
--> 17/09/1998
print(os.date('%d.%m.%Y'))
--> 04.04.2104
for k, v in pairs(os.date('*t')) do print(k, v) end
--> year    2014
--> month   4
--> day     4
--> hour    10
--> min     20
--> sec     39
--> wday    5
--> yday    94
--> isdst   True
for k, v in pairs(os.date('!*t')) do print(k, v) end
--> year    2014
--> month   4
--> day     4
--> hour    8
--> min     22
--> sec     56
--> wday    5
--> yday    94
--> isdst   False
print(os.date())
--> 04/04/2014 10:35:45
print('Unit NeoLua Test: os.time()')
print('====================')
t=os.date('*t')
print(os.time(t))
t = {}
t.year = 2001
print(os.time(t))
During my tests, I found another bug with this Lua script
table.foreach(os.date('*t'), print)
I got LuaParseException with message : Unexpected token 'foreach'. 'Identifier' expected.
Apr 4, 2014 at 12:16 PM
Thank you. I will integrate your code asap.

What did you expected, should NeoLua do with this line?
table.foreach(os.date('*t'), print)
"foreach", "cast" are a new keywords, that I introduced. Maybe, I should not parse it on member calls?
Apr 4, 2014 at 12:47 PM
Edited Apr 4, 2014 at 12:47 PM
I expected same result as
for k, v in pairs(os.date('*t')) do print(k, v) end
Apr 4, 2014 at 2:09 PM
Edited Apr 4, 2014 at 2:10 PM
I did not know that this table function exists in lua?

Is it possible to use language keywords as members in lua?
Apr 4, 2014 at 2:22 PM
I don't know.
I found example here : http://lua-users.org/wiki/OsLibraryTutorial in os.date([format [, time]]) paragraph.
Apr 4, 2014 at 2:27 PM
It looks like self written.

I will check, if I can allow keywords as identifiers.
Apr 7, 2014 at 3:52 PM
os.date() & os.time OK in release 0.8.5.
But I got exception with os.difftime() "No conversion defined from Int32 to LuaTable"
e.g.,
t1=os.date('*t')
print(os.time(t1))
t2 = {}
t2.year = 2001
print(os.time(t2))
print(os.difftime(t2,t1));
Normally difftime function should be defined as
[LuaMember("difftime")]
private int LuaDiffTime(int t2, int t1)
Apr 7, 2014 at 4:34 PM
t1 and t2 are LuaTable's and the difftime function expects integer's (e.g. the result of os.time). If this works in Lua, they changed internally the metatable of the datetime table.

But it is easy to change this, that also Tables are excepted.

Next release.

btw. it might be easier to use in new Scripts the .net DateTime.