模块:Date

来自萌娘共享
跳转至: 导航搜索

简介

这个模块用于创建各种语言版本的日期。各语言版的日期可以在I18n/date模块中查看。并由ISOdate模块调用。

用法

{{#invoke:Date|Date|year=...|month=...|day=...|hour=...|minute=...|second=...|tzhour=...|tzmin=...|lang=...}}

参数

参数名称 含义
year
month
day
hour
minute
second
tzhour UTC小时
tzmin UTC分
lang 语言
class 增加HTML参数class。
case 增加Switch...Case...条件。
trim_year 格式化年参数

在其他模块中调用该模块

当你需要在其他模块中使用该模块时,只需调用该模块即可。

比如:

local DateMod = require('Module:Date')

_Date函数

用法:

date_string = DateMod._Date({year,month,day,hour,minute, second},lang)

  1. --[[
  2. This module is intended for processing of date strings.
  3. Please do not modify this code without applying the changes first at Module:Date/sandbox and testing
  4. at Module:Date/sandbox/testcases and Module talk:Date/sandbox/testcases.
  5. Authors and maintainers:
  6. * User:Parent5446 - original version of the function mimicking template:ISOdate
  7. * User:Jarekt - original version of the functions mimicking template:Date and template:ISOyear
  8. ]]
  9. local p = {}
  10. -- =======================================
  11. -- === Dependencies ======================
  12. -- =======================================
  13. local i18n = require('Module:I18n/date') -- get localized translations of date formats
  14. local yesno = require('Module:Yesno')
  15. local function langSwitch(list,lang)
  16. local langList = mw.language.getFallbacksFor(lang)
  17. table.insert(langList,1,lang)
  18. for i,language in ipairs(langList) do
  19. if list[language] then
  20. return list[language]
  21. end
  22. end
  23. end
  24. --[[
  25. Date
  26. This function is the core part of the ISOdate template.
  27. Usage:
  28. {{#invoke:Date|Date|year=|month=|day=|hour=|minute=|second=|tzhour=|tzmin=|lang=en}}
  29. Parameters:
  30. year,month,day,hour,minute,second: broken down date-time component strings
  31. tzhour, tzmin: timezone offset from UTC, hours and minutes
  32. lang: The language to display it in
  33. case: Language format (genitive, etc.) for some languages
  34. class: CSS class for the <time> node, use "" for no metadata at all
  35. Error Handling:
  36. ]]
  37. function p.Date(frame)
  38. local args = frame.args
  39. if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then
  40. args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
  41. end
  42. return p._Date(
  43. {
  44. args.year or '',
  45. args.month or '',
  46. args.day or '',
  47. args.hour or '',
  48. args.minute or '',
  49. args.second or '',
  50. args.tzhour or '',
  51. args.tzmin or ''
  52. },
  53. args.lang, -- language
  54. args.case or '', -- allows to specify grammatical case for the month for languages that use them
  55. args.class or 'dtstart', -- allows to set the html class of the time node where the date is included. This is useful for microformats.
  56. args.trim_year or '100-999' -- by default pad one and 2 digit years to be 4 digit long, while keeping 3 digit years as is
  57. )
  58. end
  59. function p._Date(datevec, lang, case, class, trim_year)
  60. -- make sure inputs are in the right format
  61. for i = #datevec + 1, 8 do
  62. datevec[i] = ''
  63. end
  64. if not case then case = '' end
  65. if not class then class = '' end
  66. if not trim_year then trim_year = '100-999' end
  67. -- if language is not provided than look up users language
  68. -- WARNING: This step should be done by the template as it does not seem to work as well here (cache issues?)
  69. if not lang or not mw.language.isValidCode( lang ) then
  70. lang = 'en'
  71. end
  72. -- Just in case someone broke the internationalization code than fix the english defaults
  73. if i18n.DateLang['en'] == nil then
  74. i18n.DateLang['en'] = 'en-form'
  75. end
  76. if i18n.DateFormat['en-form'] == nil then
  77. i18n.DateFormat['en-form'] = {YMDHMS='j F Y, H:i:s', YMDHM='j F Y, H:i', YMD='j F Y', YM='F Y', MD='j F', Y='Y'}
  78. end
  79. -- create datecode based on which variables are provided and check for out of bound values
  80. local maxval = {9999, 12, 31, 23, 59, 60, 23, 59} -- max values for year, month, ...
  81. local c = {'Y', 'M', 'D', 'H', 'M', 'S', '', ''}
  82. local datecode = '' -- a string signifying which combination of variables was provided
  83. local datenum = {} -- date-time encoded as a vector = [year, month, ... , second]
  84. for i, v in ipairs( datevec ) do
  85. if v~=nil and v~='' then
  86. datecode = datecode .. c[i]
  87. datenum[i] = tonumber(v)
  88. if datenum[i]==nil and i==2 then
  89. -- month is not a number -> check if it is a month name in English
  90. v = mw.language.new('en'):formatDate( "n", v)
  91. datenum[i] = tonumber(v)
  92. end
  93. if datenum[i]==nil or datenum[i]>maxval[i] then
  94. -- Some numbers are out of range -> abort and return the empty string
  95. return ''
  96. end
  97. end
  98. end
  99. -- create time stamp string (for example 2000-02-20 02:20:20) based on which variables were provided
  100. local timeStamp
  101. if datecode == 'YMDHMS' then
  102. timeStamp = string.format('%04i-%02i-%02i %02i:%02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5], datenum[6] )
  103. elseif datecode == 'YMDHM' then
  104. timeStamp = string.format('%04i-%02i-%02i %02i:%02i', datenum[1], datenum[2], datenum[3], datenum[4], datenum[5] )
  105. elseif datecode:sub(1,3)=='YMD' then
  106. timeStamp = string.format('%04i-%02i-%02i', datenum[1], datenum[2], datenum[3] )
  107. datecode = 'YMD' -- 'YMD', 'YMDHMS' and 'YMDHM' are the only supported format starting with 'YMD'. All others will be converted to 'YMD'
  108. elseif datecode == 'YM' then
  109. timeStamp = string.format('%04i-%02i', datenum[1], datenum[2] )
  110. elseif datecode:sub(1,1)=='Y' then
  111. timeStamp = string.format('%04i', datenum[1] )
  112. datecode = 'Y'
  113. elseif datecode == 'M' then
  114. timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], 1 )
  115. class = '' -- date not complete -> no html formating or micro-tagging of date string
  116. elseif datecode == 'MD' then
  117. timeStamp = string.format('%04i-%02i-%02i', 2000, datenum[2], datenum[3] )
  118. class = '' -- date not complete -> no html formating or micro-tagging of date string
  119. else
  120. return '' -- format not supported
  121. end
  122. -- ==========================================================
  123. -- === Create Date String using in chosen language
  124. -- ==========================================================
  125. -- which form should the date take?
  126. -- Use langSwitch to pick formating for each language
  127. local langDateForm = langSwitch(i18n.DateLang, lang)
  128. -- special case of French and Gallic dates, which require different date format for the 1st day of the month
  129. if datenum[3]==1 and (langDateForm=='fr-form' or langDateForm=='ga-form') then
  130. langDateForm = langDateForm .. '1' -- ordinal form for the first day of the month
  131. end
  132. -- special case of Basque dates, which require different date format for the 1st, 11th, 21st and 31st day of the month
  133. if langDateForm=='eu-form' then
  134. if (datenum[3]==1 or datenum[3]==21) then
  135. langDateForm = 'eu-form01'
  136. elseif (datenum[3]==11 or datenum[3]==31) then
  137. langDateForm = 'eu-form11'
  138. end
  139. end
  140. -- Look up country specific format input to {{#time}} function
  141. local dFormat = i18n.DateFormat[langDateForm][datecode]
  142. -- overwrite default grammatical case of the month (applies mostly to Slavic languages)
  143. if (case=='gen') then
  144. -- CAUTION: at the moment i18n.DateFormat uses "F" only as month name, but this might change and this operation does not check if 'F' is in "" brackets or not, so if some language starts using 'F' in "" than this will not work for that language
  145. dFormat = dFormat:gsub("F", "xg");
  146. end
  147. if (case=='nom') then
  148. -- CAUTION: at the moment i18n.DateFormat uses "xg" only as month name, but this might change and this operation does not check if 'xg' is in "" brackets or not, so if some language starts using 'xg' in "" than this will not work for that language
  149. dFormat = dFormat:gsub("xg", "F");
  150. end
  151. if ((lang=='ru' or lang=='pl' or lang=='cs' or lang=='sl' or lang=='sk') and (case=='loc' or case=='ins')) or
  152. (lang=='fi' and (case=='ptv' or case=='ine'or case=='ela'or case=='ill') ) then
  153. local monthEn = mw.language.new('en'):formatDate( "F", timeStamp) -- month name in English
  154. -- month name using proper case and language. It relies on messages stored in MediaWiki namespace for some cases and languages
  155. -- That is why this IF statement uses "lang" not "langDateForm" variable to decide
  156. local monthMsg = mw.message.new( string.format('%s-%s', monthEn, case ) ):inLanguage( lang )
  157. if not monthMsg:isDisabled() then -- make sure it exists
  158. local month=monthMsg:plain()
  159. dFormat = dFormat:gsub('F', '"'..month..'"'); -- replace default month with month name we already looked up
  160. dFormat = dFormat:gsub('xg', '"'..month..'"');
  161. end
  162. end
  163. -- Special case related to Quechua and Kichwa languages
  164. -- see https://commons.wikimedia.org/wiki/Template_talk:Date#Quechua from 2014
  165. if (lang=='qu' or lang=='qug') and case=='nom' then
  166. dFormat = dFormat:gsub('F"pi"', 'F');
  167. end
  168. -- Lua only date formating using {{#time}} parser function (new)
  169. -- prefered call which gives "Lua error: too many language codes requested." on the [[Module talk:Date/sandbox/testcases]] page
  170. --local datestr = mw.language.new(lang):formatDate( dFormat, timeStamp)
  171. local datestr = mw.getCurrentFrame():callParserFunction( "#time", { dFormat, timeStamp, lang } )
  172. -- Another special case related to Thai solar calendar
  173. if lang=='th' and datenum[1]~= nil and datenum[1]<=1940 then
  174. -- As of 2014 {{#time}} parser function did not resolve those cases properly
  175. -- See https://en.wikipedia.org/wiki/Thai_solar_calendar#New_year for reference
  176. -- Disable once https://bugzilla.wikimedia.org/show_bug.cgi?id=66648 is fixed
  177. if datecode=='Y' then -- date is ambiguous
  178. datestr = string.format('%04i หรือ %04i', datenum[1]+542, datenum[1]+543 )
  179. elseif datenum[2]<=3 then -- year is wrong (one too many)
  180. datestr = datestr:gsub( string.format('%04i', datenum[1]+543), string.format('%04i', datenum[1]+542 ) )
  181. end
  182. end
  183. -- If year<1000 than either keep it padded to the length of 4 digits or trim it
  184. -- decide if the year will stay padded with zeros (for years in 0-999 range)
  185. if datenum[1]~= nil and datenum[1]<1000 then
  186. local trim = yesno(trim_year,nil)
  187. if trim == nil then
  188. local YMin, YMax = trim_year:match( '(%d+)-(%d+)' )
  189. trim = (YMin~=nil and datenum[1]>=tonumber(YMin) and datenum[1]<=tonumber(YMax))
  190. end
  191. -- If the date form isn't the Thai solar calendar, don't zero pad years in the range of 100-999.
  192. -- If at some point support for Islamic/Hebrew/Japanese years is added, they may need to be skipped as well.
  193. if trim then
  194. --local yearStr1 = mw.language.new(lang):formatDate( 'Y', timeStamp)
  195. local yearStr1 = mw.getCurrentFrame():callParserFunction( "#time", { 'Y', timeStamp, lang } )
  196. --local yearStr1 = datestr:match( '%d%d%d%d' ) -- 4 digits in a row (in any language) - that must be a year
  197. local yearStr2 = yearStr1
  198. local zeroStr = mw.ustring.sub(yearStr1,1,1)
  199. for i=1,3 do -- trim leading zeros
  200. if mw.ustring.sub(yearStr2,1,1)==zeroStr then
  201. yearStr2 = mw.ustring.sub(yearStr2, 2, 5-i)
  202. else
  203. break
  204. end
  205. end
  206. datestr = datestr:gsub( yearStr1, yearStr2 )
  207. --datestr = string.format('%s (%s, %s)', datestr, yearStr1, yearStr2 )
  208. end
  209. end
  210. -- append timezone if present
  211. if datevec[7] ~= '' and (datecode == 'YMDHMS' or datecode == 'YMDHM') then
  212. local tzstr, tzhournum = '', tonumber(datevec[7])
  213. if tzhournum < 0 then tzstr = '−' else tzstr = '+' end
  214. tzstr = tzstr..string.format("%02d", math.abs(tzhournum))..':'
  215. if datevec[8] ~= '' then tzstr = tzstr..datevec[8] else tzstr = tzstr..'00' end
  216. datestr = datestr..' '..tzstr
  217. end
  218. -- html formating and tagging of date string
  219. if class ~= '' then
  220. local DateHtmlTags = '<span style="white-space:nowrap"><time class="%s" datetime="%s">%s</time></span>'
  221. datestr = DateHtmlTags:format(class, timeStamp, datestr)
  222. end
  223. return datestr
  224. end
  225. return p