| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- using System.Runtime.CompilerServices;
- using System.Text;
- namespace Lua.Standard.Internal;
- internal static class DateTimeHelper
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double GetUnixTime(DateTime dateTime)
- {
- return GetUnixTime(dateTime, DateTime.UnixEpoch);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static double GetUnixTime(DateTime dateTime, DateTime epoch)
- {
- var time = (dateTime - epoch).TotalSeconds;
- if (time < 0.0) return 0;
- return time;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static DateTime FromUnixTime(double unixTime)
- {
- var ts = TimeSpan.FromSeconds(unixTime);
- return DateTime.UnixEpoch + ts;
- }
- public static DateTime ParseTimeTable(LuaThread thread, LuaTable table)
- {
- static int GetTimeField(LuaThread thread, LuaTable table, string key, bool required = true, int defaultValue = 0)
- {
- if (!table.TryGetValue(key, out var value))
- {
- if (required)
- {
- throw new LuaRuntimeException(thread.GetTraceback(), $"field '{key}' missing in date table");
- }
- else
- {
- return defaultValue;
- }
- }
- if (value.TryRead<double>(out var d) && MathEx.IsInteger(d))
- {
- return (int)d;
- }
- throw new LuaRuntimeException(thread.GetTraceback(), $"field '{key}' is not an integer");
- }
- var day = GetTimeField(thread, table, "day");
- var month = GetTimeField(thread, table, "month");
- var year = GetTimeField(thread, table, "year");
- var sec = GetTimeField(thread, table, "sec", false, 0);
- var min = GetTimeField(thread, table, "min", false, 0);
- var hour = GetTimeField(thread, table, "hour", false, 12);
- return new DateTime(year, month, day, hour, min, sec);
- }
- public static string StrFTime(LuaThread thread, ReadOnlySpan<char> format, DateTime d)
- {
- // reference: http://www.cplusplus.com/reference/ctime/strftime/
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- static string? STANDARD_PATTERNS(char c)
- {
- return c switch
- {
- 'a' => "ddd",
- 'A' => "dddd",
- 'b' => "MMM",
- 'B' => "MMMM",
- 'c' => "f",
- 'd' => "dd",
- 'D' => "MM/dd/yy",
- 'F' => "yyyy-MM-dd",
- 'g' => "yy",
- 'G' => "yyyy",
- 'h' => "MMM",
- 'H' => "HH",
- 'I' => "hh",
- 'm' => "MM",
- 'M' => "mm",
- 'p' => "tt",
- 'r' => "h:mm:ss tt",
- 'R' => "HH:mm",
- 'S' => "ss",
- 'T' => "HH:mm:ss",
- 'y' => "yy",
- 'Y' => "yyyy",
- 'x' => "d",
- 'X' => "T",
- 'z' => "zzz",
- 'Z' => "zzz",
- _ => null,
- };
- }
- var builder = new ValueStringBuilder();
- bool isEscapeSequence = false;
- for (int i = 0; i < format.Length; i++)
- {
- char c = format[i];
- if (c == '%')
- {
- if (isEscapeSequence)
- {
- builder.Append('%');
- isEscapeSequence = false;
- }
- continue;
- }
- if (!isEscapeSequence)
- {
- builder.Append(c);
- continue;
- }
- if (c == 'O' || c == 'E')
- {
- continue; // no modifiers
- }
- isEscapeSequence = false;
- var pattern = STANDARD_PATTERNS(c);
- if (pattern != null)
- {
- builder.Append(d.ToString(pattern));
- }
- else if (c == 'e')
- {
- var s = d.ToString("%d");
- builder.Append(s.Length < 2 ? $" {s}" : s);
- }
- else if (c == 'n')
- {
- builder.Append('\n');
- }
- else if (c == 't')
- {
- builder.Append('\t');
- }
- else if (c == 'C')
- {
- // TODO: reduce allocation
- builder.Append((d.Year / 100).ToString());
- }
- else if (c == 'j')
- {
- builder.Append(d.DayOfYear.ToString("000"));
- }
- else if (c == 'u')
- {
- int weekDay = (int)d.DayOfWeek;
- if (weekDay == 0) weekDay = 7;
- builder.Append(weekDay.ToString());
- }
- else if (c == 'w')
- {
- int weekDay = (int)d.DayOfWeek;
- builder.Append(weekDay.ToString());
- }
- else if (c == 'U')
- {
- // Week number with the first Sunday as the first day of week one (00-53)
- builder.Append("??");
- }
- else if (c == 'V')
- {
- // ISO 8601 week number (00-53)
- builder.Append("??");
- }
- else if (c == 'W')
- {
- // Week number with the first Monday as the first day of week one (00-53)
- builder.Append("??");
- }
- else
- {
- throw new LuaRuntimeException(thread.GetTraceback(), $"bad argument #1 to 'date' (invalid conversion specifier '{format.ToString()}')");
- }
- }
- return builder.ToString();
- }
- }
|