Date Formatting Functions


The following code provides date formatting functions which are not available in the string.format function.

Ideal for formatting dates in reports, or converting dates between different formats when importing data.

..from Sam Lie

--=====================================================
-- the reason this routine is needed is because lua does not 
-- have a sort indexed table function
function table_sort(a, sortfield)
local new1 = {}
local new2 = {}
 for k,v in pairs(a) do
 table.insert(new1, { key=k, val=v } ) 
 end
 table.sort(new1, function (a,b) return (a.val[sortfield] < b.val[sortfield]) end) 
 for k,v in pairs(new1) do
 table.insert(new2, v.val)
 end
 return new2
end
---============================================================
function padzero(s, count)
 return string.rep("0", count-string.len(s)) .. s 
end
--========================================================================
-- get date parts for a given ISO 8601 date format (http://richard.warburton.it )
function get_date_parts(date_str)
 _,_,y,m,d=string.find(date_str, "(%d+)-(%d+)-(%d+)")
 return tonumber(y),tonumber(m),tonumber(d)
end
--====================================================
function getmonth(month)
 local months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }
 return months[tonumber(month)]
end
--====================================================
function getday_posfix(day)
local idd = math.mod(day,10)
 return (idd==1 and day~=11 and "st") or (idd==2 and day~=12 and "nd") or (idd==3 and day~=13 and "rd") or "th"
end
--========================================================================
-- Given a date of certain date_format, returns the date parts yy,mm,dd
-- eg. "12 May 2007" with date_format "dd mmm yyyy"
-- or "12.05.07" with date_format "dd.mm.yy"
-- will return 2007, 5, 12
--
function get_formatted_date_parts(date_str, date_format)
 local d,m,y, arr, x, yy, mm, dd, use_month_names
 local months = { jan=1, feb=2, mar=3, apr=4, may=5, jun=6, jul=7, aug=8, sep=9, oct=10, nov=11, dec=12 }
 if (date_format) then
 
 if string.find(date_format, "mmm") then
 use_month_names = true
 else
 use_month_names = false
 end
 d = string.find(date_format, "dd")
 m = string.find(date_format, "mm")
 y = string.find(date_format, "yy")
 
 arr = { { pos=y, b="yy" }, { pos=m, b="mm" } , { pos=d, b="dd" } }
 arr = table_sort(arr, "pos")
 date_format = string.gsub(date_format,"yyyy","(%%d+)")
 date_format = string.gsub(date_format,"mmm","(%%a+)")
 date_format = string.gsub(date_format,"yy","(%%d+)")
 date_format = string.gsub(date_format,"mm","(%%d+)")
 date_format = string.gsub(date_format,"dd","(%%d+)")
 date_format = string.gsub(date_format," ","%%s")
 else
 date_format = "(%d+)-(%d+)-(%d+)"
 arr = { { pos=1, b="yy" }, { pos=2, b="mm" } , { pos=3, b="dd" } }
 end
 if (date_str and date_str~="") then 
 _, _, arr[1].c, arr[2].c, arr[3].c = string.find(string.lower(date_str), date_format)
 else
 return nil, nil, nil
 end
 arr = table_sort(arr, "b")
 yy = arr[3].c
 mm = arr[2].c
 dd = arr[1].c
 if (use_month_names) then 
 
 mm = months[lower(string.sub(mm,1,3))]
 if (not mm) then
 error("Invalid month name.")
 end
 end
 -- for naughty people who still use two digit years.
 if (string.len(yy)==2) then
 if (tonumber(yy)>40) then
 yy = "19"..yy
 else
 yy = "20"..yy
 end
 end
 return tonumber(yy),tonumber(mm),tonumber(dd)
end
--========================================================================
-- Note : date_str has to be ISO 8601 date format ie. yyyy-mm-dd
--
function format_date(date_str, dateformat)
local iyy, imm, idd 
 if (date_str and date_str~="") then
 iyy, imm, idd = get_date_parts(date_str)
 dateformat = string.gsub(dateformat, "DDD", idd..string.upper(getday_posfix(idd)))
 dateformat = string.gsub(dateformat, "ddd", idd..getday_posfix(idd) )
 dateformat = string.gsub(dateformat, "dd", padzero(idd,2))
 dateformat = string.gsub(dateformat, "MMM", string.upper(getmonth(imm)))
 dateformat = string.gsub(dateformat, "mmm", getmonth(imm))
 dateformat = string.gsub(dateformat, "mm", padzero(imm,2))
 dateformat = string.gsub(dateformat, "yyyy", padzero(iyy,4))
 dateformat = string.gsub(dateformat, "yy", string.sub(padzero(iyy,4),3,4))
 else
 dateformat = ""
 end
 return(dateformat)
end
--===============================================
-- convert date to excel serial day number
--
function date_to_excel_date(dd, mm, yy) 
local days, monthdays, leapyears, nonleapyears, nonnonleapyears
 monthdays= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 leapyears=tonumber(math.floor((yy-1900)/4));
 nonleapyears=tonumber(math.floor((yy-1900)/100))
 nonnonleapyears=tonumber(math.floor((yy-1600)/400))
 if ((math.mod(yy,4)==0) and mm<3) then
 leapyears = leapyears - 1
 end
 days= 365 * (yy-1900) + leapyears - nonleapyears + nonnonleapyears
 c=1
 while (c<mm) do
 days = days + monthdays[c]
 c=c+1
 end
 days=days+dd+1
 return days
end
	

Here is a test suite.

adate = os.date()
print("Todays date according to your OS format :", adate)
-- for example "mm/dd/yyyy" could be your OS locale date format.
yy,mm,dd = get_formatted_date_parts(adate, "mm/dd/yyyy")
ISO_date = yy .. "-" .. mm .. "-" .. dd
print("Date formated in ISO 8601", ISO_date)
print(format_date(ISO_date, "dd MMM yyyy") )
print(format_date(ISO_date, "ddd mmm yyyy") )
print(format_date(ISO_date, "dd/mm/yy") )
print(format_date(ISO_date, "yyyy.mm.dd") )
print(format_date(ISO_date, "Today is the ddd of mmm, yyyy.") )
print( date_to_excel_date(22, 2, 2009) ) -- outputs 39866
 


RecentChanges · preferences
edit · history
Last edited May 15, 2017 5:15 am GMT (diff)

AltStyle によって変換されたページ (->オリジナル) /