Module:Japanese calendar
![]() | This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
This module is used to calculate dates in the Japanese calendar. It defines an "era" class which is designed to be called from other Lua modules, and it also contains several functions to export Japanese calendar data directly to Wikipedia pages through #invoke.
Usage
Through #invoke
{{#invoke:Japanese calendar|function_name|year=year|era=article name or kanji|previous=yes|next=yes}}
The function name specifies how the data should be outputted. The year
and era
parameters determine what era and year the module outputs. The next
and previous
parameters tell the module to return data for the next or previous era, rather than the one specified. If a combination of parameters is invalid the module will usually output nothing. However, if both the next
and previous
parameters are specified it will output an error.
Year and era
The year
parameter is the year in the Gregorian calendar. The era
parameter can either be the article name for that era, or the era's name in kanji. (Transcribed English era names can usually be used, but will not work if they are ambiguous.) Either year
or era
must be specified. If both are specified, the module defaults to using era
to get the era data. This enables output of the last year of the previous era (for example, Shōwa 64 is the same year as Heisei 1).
Code | Output |
---|---|
{{#invoke:Japanese calendar|link|year=1950}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link|era=Shōwa period}} |
|
{{#invoke:Japanese calendar|link|era=昭和}} |
Shōwa |
{{#invoke:Japanese calendar|link|era=Shōwa}} |
|
{{#invoke:Japanese calendar|link_year|year=1989}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1989|era=Shōwa period}} |
|
{{#invoke:Japanese calendar|link_year|year=1990}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1990|era=Shōwa period}} |
Functions
Code | Description | Example |
---|---|---|
baseyear |
The first year of the specified era. | {{#invoke:Japanese calendar|baseyear|era=Heisei}} →
|
endyear |
The last year of the specified era. | {{#invoke:Japanese calendar|endyear|era=Shōwa period}} → Script error: The function "endyear" does not exist.
|
year |
The year for the specified era, without the era name. Defaults to the newer era, if more than one is applicable. | {{#invoke:Japanese calendar|year|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
kanjiyear |
The same as year , but in kanji. The first year of an era is changed to the kanji 元, and the others are changed to full-width numbers. |
{{#invoke:Japanese calendar|kanjiyear|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
article |
The Wikipedia article for the era, unlinked. | {{#invoke:Japanese calendar|article|year=1950}} → Lua error at line 17: attempt to compare nil with number.
|
label |
The name of the era. Same as article for undisambiguated titles. |
{{#invoke:Japanese calendar|label|year=1950}} → Lua error at line 17: attempt to compare nil with number.
|
link |
A link to the Wikipedia article of the specified era. | {{#invoke:Japanese calendar|link|year=1950}} → Lua error at line 17: attempt to compare nil with number.
|
kanji |
The kanji for the specified era. | {{#invoke:Japanese calendar|kanji|year=1950}} → Lua error at line 17: attempt to compare nil with number.
|
label_year |
label followed by year |
{{#invoke:Japanese calendar|label_year|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
link_year |
link followed by year |
{{#invoke:Japanese calendar|link_year|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
label_kanjiyear |
label followed by kanjiyear |
{{#invoke:Japanese calendar|label_kanjiyear|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
link_kanjiyear |
link followed by kanjiyear |
{{#invoke:Japanese calendar|link_kanjiyear|year=1989}} → Lua error at line 17: attempt to compare nil with number.
|
Next, previous and old
If the next
parameter is specified, the module outputs the data for the subsequent era; if the previous
parameter is specified it outputs the data for the previous one. If the old
parameter is specified, the module outputs the data for the "old" era. This is the same as the current era unless the year is set to the first year of the specified era. If this is the case, then old
outputs the data for the previous era. However, if the module could not find a valid previous era then the data for the current era is returned.
Code | Output |
---|---|
{{#invoke:Japanese calendar|baseyear|era=Shōwa period}} |
|
{{#invoke:Japanese calendar|baseyear|era=Shōwa period|next=yes}} |
|
{{#invoke:Japanese calendar|baseyear|era=Shōwa period|previous=yes}} |
|
{{#invoke:Japanese calendar|baseyear|era=Shōwa period|old=yes}} |
|
{{#invoke:Japanese calendar|link|year=1880}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link|year=1880|next=yes}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link|year=1880|previous=yes}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link|year=1880|old=yes}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1926}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1926|old=yes}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1927}} |
Lua error at line 17: attempt to compare nil with number. |
{{#invoke:Japanese calendar|link_year|year=1927|old=yes}} |
Lua error at line 17: attempt to compare nil with number. |
From another Lua module
First of all, the era class must be loaded, like this:
local era = require( 'Module:Japanese calendar' ).era
Once the class is loaded, you can make a new era object using era:new()
:
local myEra = era:new{ year = year, era = article name or kanji }
Either year
or era
must be specified. It is also possible to use an index
field, corresponding to the index of Module:Japanese calendar/data, but this is for internal use only and will change as new eras are added.
Properties
Era objects have a number of properties. Their values might be nil
if the module did not have enough information to process them, or the values could be false
if they correspond to an invalid era. You can specify properties with the dot syntax:
local article = myEra.article
The properties are as follows:
gregorianYear
: the year in the Gregorian calendar. Same as the input year.startYear
: the first year of the specified era.endYear
: the last year of the specified era.eraYear
: the year of the specified era, without the era name.eraYearKanji
: a string representing the era year in kanji. The first year of an era is changed to the kanji 元, and the others are changed to full-width numbers. Note: even though the output may often look like a number, it will always be a string value.article
: the Wikipedia article for the era, unlinked.label
: the name of the era. Same asarticle
unless the article title is disambiguated.kanji
: the name of the era in kanji.
Methods
Era objects have three methods. Methods can be specified with the colon syntax:
local nextEra = myEra:getNextEra()
The methods are as follows:
era:getNextEra()
- gets the era object for the next era. Returnsnil
if it doesn't exist.era:getPreviousEra()
- gets the era object for the previous era. Returnsnil
if it doesn't exist.era:getOldEra()
- gets the era object for the "old" era. This is the same as the current era object unless eraYear equals 1. If eraYear equals 1 then this returns the era object for the previous era. If the module could not find a valid previous era object then the current era object is returned.
-- This module defines an "era" class for processing eras in the Japanese calendar.
-- It also contains functions to export the class properties to #invoke.
-- @todo FIXME: era:getNextEra() and era:getPreviousEra() are generally broken
-- when used with nonexistent data entries.
local eras = mw.loadData( 'Module:Japanese calendar/data' )
--------------------------------------------------------------------
-- Helper functions
--------------------------------------------------------------------
local function yearToEraIndex( year )
year = tonumber( year )
if type( year ) ~= 'number' then return end
for i, t in ipairs( eras ) do
if year >= t.year then
return i
end
end
end
local function textToEraIndex( s )
for i, t in ipairs( eras ) do
if s == t.article or s == t.kanji then
return i
end
end
end
--------------------------------------------------------------------
-- Era class definition
--------------------------------------------------------------------
local era = {}
era.__index = era
function era:new( init )
init = type( init ) == 'table' and init or {}
local obj = {}
-- Grab the data from the init table.
obj.gregorianYear = tonumber( init.year )
local eraText = type( init.era ) == 'string' and init.era or nil
-- Calculate the era data from the input. Find the era from the era name or the kanji if possible, as this allows
-- us to specify the last year of one era rather than the first year of the next one, if that is the desired behaviour.
local eraIndex
if eraText then
eraIndex = textToEraIndex( eraText )
elseif obj.gregorianYear then
eraIndex = yearToEraIndex( obj.gregorianYear )
end
-- If the data entry was found for the era, process it and add it to the object.
if eraIndex then
local eraData = eras[ eraIndex ]
obj.startYear = eraData.year
obj.article = eraData.article
obj.kanji = eraData.kanji
obj.label = eraData.label
-- Create a link to the era article if possible.
if obj.label and obj.article then
obj.link = mw.ustring.format( '[[%s|%s]]', obj.article, obj.label )
elseif obj.article then
obj.link = mw.ustring.format( '[[%s]]', obj.article )
end
-- Allow matching years to different eras, but only for the first year of the next era. For example, Taisho 15 is also Showa 1, but there is no such thing as Taisho 16.
local nextEraData = eras[ eraIndex - 1 ]
local nextStartYear = nextEraData and nextEraData.year
if obj.gregorianYear
and (
not nextStartYear
or ( nextStartYear and obj.gregorianYear <= nextStartYear )
)
and obj.gregorianYear >= obj.startYear -- Don't allow negative years.
and math.floor( obj.gregorianYear ) ~= 687 -- 686 is a special case as the Shuchō era lasted for less than one year. Disallowing 687 is a quick fix for this.
then
obj.eraYear = obj.gregorianYear - obj.startYear + 1
obj.eraYearKanji = tostring( obj.eraYear ) -- Although most of these will be numbers, one is a kanji character, so convert them all to strings.
if obj.eraYearKanji == '1' then
obj.eraYearKanji = '元'
end
end
end
-- Make sure obj.label is available even if it is the same as the article name.
obj.label = obj.label or obj.article
-- Add methods to get the next and previous eras.
function obj:getNextEra()
if not eraIndex then return end
local eraData = eras[ eraIndex - 1 ]
if eraData then
local initText = eraData.article
local initYear = eraData.year
if initText then
return era:new{ era = initText, year = obj.gregorianYear }
elseif initYear then
return era:new{ year = initYear }
end
end
end
function obj:getPreviousEra()
if not eraIndex then return end
local eraData = eras[ eraIndex + 1 ]
if eraData then
local initText = eraData.article
local initYear = eraData.year
if initText then
return era:new{ era = initText, year = obj.gregorianYear }
elseif initYear then
return era:new{ year = initYear }
end
end
end
return setmetatable( obj, {
__index = self
})
end
--------------------------------------------------------------------
-- Interface for old Japanese calendar templates
--------------------------------------------------------------------
local function getStartYear( obj )
return obj.startYear
end
local function getEraYear( obj )
return obj.eraYear
end
local function getEraYearKanji( obj )
return obj.eraYearKanji
end
local function getArticle( obj )
return obj.article
end
local function getLabel( obj )
return obj.label
end
local function getLink( obj )
return obj.link
end
local function getKanji( obj )
return obj.kanji
end
local function getLabelAndEraYear( obj, kanji )
local eraYear = kanji and obj.eraYearKanji or obj.eraYear
if obj.label and eraYear then
return mw.ustring.format( '%s %s', obj.label, tostring( eraYear ) )
end
end
local function getLinkAndEraYear( obj, kanji )
local eraYear = kanji and obj.eraYearKanji or obj.eraYear
if obj.link and eraYear then
return mw.ustring.format( '%s %s', obj.link, tostring( eraYear ) )
end
end
local function getLabelAndEraYearKanji( obj )
return getLabelAndEraYear( obj, true )
end
local function getLinkAndEraYearKanji( obj )
return getLinkAndEraYear( obj, true )
end
-- Process the arguments from #invoke.
local function makeWrapper( func )
return function( frame )
-- If called via #invoke, use the args passed into the invoking
-- template, or the args passed to #invoke if any exist. Otherwise
-- assume args are being passed directly in from the debug console
-- or from another Lua module.
local origArgs
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
for k, v in pairs( frame.args ) do
origArgs = frame.args
break
end
else
origArgs = frame
end
-- Trim whitespace and remove blank arguments.
local args = {}
for k, v in pairs( origArgs ) do
if type( v ) == 'string' then
v = mw.text.trim( v )
end
if v ~= '' then
args[k] = v
end
end
local myEra
if args.next and args.previous then
return '<strong class="error">[[Module:Japanese calendar]] error: you cannot specify both the "next" parameter and the "previous" parameter.</strong>'
elseif args.next then
myEra = era:new( args ):getNextEra()
elseif args.previous then
myEra = era:new( args ):getPreviousEra()
else
myEra = era:new( args )
end
return myEra and func( myEra ) or ''
end
end
--------------------------------------------------------------------
-- Return the era class and the template interface
--------------------------------------------------------------------
return {
era = era,
baseyear = makeWrapper( getStartYear ),
year = makeWrapper( getEraYear ),
kanjiyear = makeWrapper( getEraYearKanji ),
article = makeWrapper( getArticle ),
label = makeWrapper( getLabel ),
link = makeWrapper( getLink ),
kanji = makeWrapper( getKanji ),
label_year = makeWrapper( getLabelAndEraYear ),
link_year = makeWrapper( getLinkAndEraYear ),
label_kanjiyear = makeWrapper( getLabelAndEraYearKanji ),
link_kanjiyear = makeWrapper( getLinkAndEraYearKanji )
}