モジュールの解説[表示] [編集] [履歴] [キャッシュを破棄]

このモジュールは、ウィキデータから営業時間を取得するために使用されます。{{#invoke: Hours | getHours }}のように記述することで、記事の中で使うこともできます。

ウィキデータでのバージョン: 2025-03-15 問題あり

使用状況

このモジュールを使用しているモジュールは以下の通りです:

メンテナンスカテゴリ

このモジュールは以下のメンテナンスカテゴリを使用します:

ウィキデータ 名前 営業時間
Q99477686 Chuchichäschtli 営業:全曜日 18:00-24:00
Q6373 大英博物館 営業:全曜日 10:00-17:00;閉店:12月24日、12月25日、12月26日、1月1日
Q219867 キングス・クロス駅 営業:月火水木金、土 6:00-22:00;日 7:45-22:00
Q2292227 ski resort Gaissau-Hintersee 営業:全曜日 9:00-16:00 (12月15日-3月15日)
Q11323320 パブロ・ガルガーリョ博物館 営業:火-土 10:00-14:00、17:00-21:00;日、公休 10:00-14:30
Q27831262 Öömrang Hüs 営業:月火水木金 11:00-13:30、15:00-17:00 (ハイシーズン);土 11:00-13:30 (ハイシーズン);閉店:日、公休
Q99690036 Nationalpark-Tor Rurberg 営業:全曜日 9:00-13:00、13:30-17:00 (4月1日-10月31日)、10:00-13:00、13:30-16:00 (11月1日-3月31日)
Q2583681 大エジプト博物館 営業:全曜日 9:00-17:00 (展覧会)、8:30-18:00

注意事項

今の時点では、営業時間が保存されているウィキデータのアイテムはごくわずかで、時間の経過とともにこの情報が修正されていくことは確かです。

テンプレート呼び出し

モジュール内ではなく、地の文でテンプレート呼び出しを行う場合、構文は{{#invoke: Hours | getHours }}のようになります。パラメータは以下の通りです:

  • id(必須):取得元のウィキデータID。はじめに「Q」を付けることを忘れずに。
  • format:開始時間がある場合、デフォルトの文字列の代わりに表示する文字列のフォーマットです。例えば:「オープン:%s」。%sは開始時間に置き換わります。
  • fallback:開始時間にウィキの言語(日本語版ウィキボヤージュならば日本語)での名前がない場合、代わりに表示する言語。例:en
  • show:表示に関する設定をカンマ区切りで行うことができます。現在はmsg(メンテナンスメッセージの表示)とnomsg(メンテナンスメッセージの非表示)がサポートされています。

使用例

  • {{#invoke: Hours | getHours | id = Q6373 }}
  • {{#invoke: Hours | getHours | id = Q6373 | fallback = en }}
  • {{#invoke: Hours | getHours | id = Q6373 | show = msg }}

-- getting opening hours from Wikidata  -- module variable and administration local hr = { 	moduleInterface = { 		suite  = 'Hours', 		serial = '2024-05-17', 		item   = 99600452 	}, 	labelTable = nil, 	typeTables = nil }  -- module import -- require( 'strict' ) local hi = require( 'Module:Hours/i18n' ) local wu = require( 'Module:Wikidata utilities' )  -- local variables local categIds    = {} local showOptions = {}  local function isSet( s ) 	return s and s ~= '' end  -- insert a value into a table only if it is set local function tableInsert( tab, value ) 	if isSet( value ) then 		table.insert( tab, value ) 	end end  -- value count for any variable local function getCount( tab ) 	return type( tab ) == 'table' and #tab or 0 end  local function getLabelFromTables( id ) 	local label = hi.dateIds[ id ] 	if not label and hr.labelTable then 		label = hr.labelTable[ id ] 	end 	if not label and hr.typeTables and hr.typeTables.idTable then 		local item = hr.typeTables.typeTable[ hr.typeTables.idTable[ id ] ] 		if item then 			item = item.label or item.n or item 			local at = mw.ustring.find( item, ',' ) 			if at then 				item = mw.ustring.sub( item, 1, at - 1 ) 			end 			label = mw.text.trim( item ) 		end 	end 	return label end  -- getting normalized time hh:dd local function getNormalizedTime( s ) 	local count 	s, count = mw.ustring.gsub( s, hi.texts.timePattern, '%1:%2' ) 	return ( count > 0 ) and s or nil end  function hr.formatTime( s ) 	local t = getNormalizedTime( s ) 	if not t then 		return s 	end  	local formatStr = hi.texts.formatTime 	t = mw.text.split( t, ':', true ) 	if #t == 1 then 		t[ 2 ] = '00' 	end 	if hi.options.hour12 then 		local isAM = true 		local n = tonumber( t[ 1 ] ) 		if n > 12 then 			isAM = false 			t[ 1 ] = '' .. ( n - 12 ) 		end 		formatStr = isAM and hi.texts.formatAM or hi.texts.formatPM 	end 	s = mw.ustring.format( formatStr, mw.text.trim( t[ 1 ] ), 		mw.text.trim( t[ 2 ] ) ) 	if hi.options.leadingZero then 		s = s:gsub( '^(%d):', '0%1:' ) 	else 		s = s:gsub( '^0(%d):', '%1:' ) 	end 	if hi.options.removeZeros then 		s = s:gsub( '^(%d%d?):00', '%1' ) 	end 	return s end  -- getting label for a qualifier id -- to save computing time firstly the id will fetched from Hours/i18n table -- if available, otherwise from Wikidata local function getLabelFromId( id, wikilang, fallbackLang ) 	if not isSet( id ) then 		return '' 	end  	-- from table 	local label = getLabelFromTables( id )  	-- from Wikidata 	if not label and mw.wikibase.isValidEntityId( id ) then 		label = wu.getLabel( id, wikilang ) 		if not label and isSet( fallbackLang ) then 			label = wu.getLabel( id, fallbackLang ) 			if label then 				categIds.fallbackLabel = 1 			end 		end 		if label then 			categIds.hoursLabelFromWikidata = 1 		end 	end  	-- abbreviate labels 	if isSet( label ) then 		for i, abbr in ipairs( hi.abbr ) do 			label = mw.ustring.gsub( label, abbr.f, abbr.a ) 		end 		label = mw.ustring.gsub( label, '​', '' ) -- zero-width space 	end  	-- additional time formatting 	if isSet( label ) then 		if hi.months then 			for full, short in pairs( hi.months ) do 				label = mw.ustring.gsub( label, full, short ) 			end 		end 		label = hr.formatTime( label ) 	end 	return label or '' end  local function abbreviateTimeStr( s, all, pattern, repl ) 	if not isSet( s ) or not isSet( pattern ) or not repl then         return s or '' 	end 	if all then 		s = mw.ustring.gsub( s, pattern, repl ) 	else 		local matchPattern = mw.ustring.gsub( pattern, '%(%%d%)', '' ) 		local first, stop = mw.ustring.find( s, pattern ) 		if first then 			local second = mw.ustring.find( s, pattern, stop + 1 ) 			if second and mw.ustring.match( s, matchPattern ) == 				mw.ustring.match( s, matchPattern, stop + 1 ) then         		s = mw.ustring.gsub( s, pattern, repl, 1 )         	end     	end     end     return s end  -- getting time period string -- i:  position in from and to arrays -- id: label for P3035 value local function getTimePeriod( from, to, i, id ) 	local result = '' 	if id and ( id == getLabelFromTables( hi.times.daily ) 		or id == getLabelFromTables( hi.times.is24_7 ) ) 		and from and to and from[ i ] == getLabelFromTables( hi.times.Jan1 ) and 		to[ i ] == getLabelFromTables( hi.times.Dec31 ) then 		return '' 	end 	if from and isSet( from[ i ] ) and to and isSet( to[ i ] ) then 		result = mw.ustring.format( hi.texts.fromTo, from[ i ], to[ i ] ) 		if isSet( hi.texts.hourPattern ) then 			result = abbreviateTimeStr( result, hi.texts.hourReplAll, 				hi.texts.hourPattern, hi.texts.hourRepl ) 		end 	elseif from and isSet( from[ i ] ) then 		result = mw.ustring.format( hi.texts.from, from[ i ] ) 	elseif to and isSet( to[ i ] ) then 		result = mw.ustring.format( hi.texts.to, to[ i ] ) 	end 	return result end  -- collecting all maintenance categories function hr.getCategories( formatStr ) 	local result = wu.getCategories( formatStr ) 	for k, v in pairs( categIds ) do 		result = result .. ( hi.categories[ k ] or hi.categories.unknownError ) 	end 	if showOptions.demo then 		-- remove category links 		result = result:gsub( '%[%[[^%[]*%]%]', '' ) 	end 	return result end  -- getting a string with listed days at which an establishment is closed local function getClosed( arr ) 	return ( arr and #arr > 0 ) and mw.ustring.format( hi.texts.closed or '%s',  		table.concat( arr, hi.texts.comma ) ) or '' end  -- converting day range from Mo, Tu, We to Mo–We, and so on local function getRange( arr, minPos, maxPos ) 	if maxPos > 0 and minPos > 0 and maxPos > minPos then 		arr[ minPos ] = mw.ustring.format( hi.texts.fromTo, arr[ minPos ], 			arr[ maxPos ] ) 		for i = maxPos, minPos + 1, -1 do 			table.remove( arr, i ) 		end 	end end  -- looking for day ranges like Mo, Tu, We and so on and converting them local function convertDayRange( arr ) 	local count = #arr 	local minPos = 0 	local maxPos = 0 	local value, valueMin 	while count > 0 do 		value = hi.weekdays[ arr[ count ] ] 		if not value then 			getRange( arr, minPos, maxPos ) 			maxPos = 0 		elseif maxPos == 0 then 			maxPos = count 			valueMin = value 		elseif maxPos > 0 and value == valueMin - 1 then 			minPos = count 			valueMin = value 		else 			getRange( arr, minPos, maxPos ) 			maxPos = 0 		end 		count = count - 1 	end 	getRange( arr, minPos, maxPos ) end  -- concating non-empty strings local function concatStrings( sep, str1, str2 ) 	local tab = {} 	tableInsert( tab, str1 ) 	tableInsert( tab, str2 ) 	return table.concat( tab, sep ) end  -- add comment if not yet exists local function addComment( tab, value ) 	if not isSet( value ) then 		return 	elseif #tab == 0 then 		table.insert( tab, value ) 	else 		for i = 1, #tab, 1 do 			if tab[ i ] == value then 				break 			end 			if i == #tab then 				table.insert( tab, value ) 			end 		end 	end end  -- main function for usage in Lua modules -- entity: entity id or entity table -- wikilang: content language of the wiki -- fallbackLang: optional additional language for fallback -- formatStr: optional format string for property categories -- show: table of show options (addCategories, msg, nomsg) or nil -- lastedit: dat of last edit. If false no date will be fetched -- labelTabel: additional table with Q-id label pairs function hr.getHoursFromWikidata( entity, wikilang, fallbackLang, formatStr, 	show, lastEdit, labelTable, typeTables )  	-- collecting days at which an establishment is closed 	local closeDays = {} 	local closeDaysHelper = {} 	local function mergeDays( days ) 		if not days or #days == 0 then 			return 		end 		for i, day in ipairs( days ) do 			if not closeDaysHelper[ day ] then 				table.insert( closeDays, day ) 				closeDaysHelper[ day ] = '' 			end 		end 	end 	local function clearDays() 		closeDays = {} 		closeDaysHelper = {} 	end  	-- adding additional properties if an additional Q-id table is given 	hr.labelTable = labelTable 	hr.typeTables = typeTables  	-- preparing show options 	showOptions = show or {} 	showOptions.addCategories = hi.options.addCategories 	if showOptions.msg then 		showOptions.addCategories = true 	elseif showOptions.nomsg then 		showOptions.addCategories = false 	end  	-- format string for property categories 	if not isSet( formatStr ) then 		formatStr = hi.categories.properties 	end  	-- 1st step: getting statements for P3025: open days 	local statements = wu.getValuesWithQualifiers( entity, hi.wd.opened, nil, 		hi.wd.all, hi.wd.retrieved, nil, getLabelFromId, wikilang, fallbackLang ) 	lastEdit = wu.getLastedit( lastEdit, statements )  	-- converting statements to human-readable strings 	local result = {} 	local comments, s 	local is24_7 = getLabelFromTables( hi.times.is24_7 )  	for i, statement in ipairs( statements ) do 		-- opening times 		local times = {} 		local count = math.max( getCount( statement[ hi.wd.hourOpenFrom ] ), 			getCount( statement[ hi.wd.hourOpenTo ] ) ) 		if count > 0 then 			for j = 1, count, 1 do 				s = getTimePeriod( statement[ hi.wd.hourOpenFrom ], 					statement[ hi.wd.hourOpenTo ], j ) 				if isSet( s ) then 					table.insert( times, s ) 				elseif statement.value ~= is24_7 then 					categIds.withoutTime = 1 				end 			end 		elseif statement.value ~= is24_7 then 			categIds.withoutTime = 1 		end 		s = table.concat( times, hi.texts.comma )  		-- comments 		comments = {} 		count = math.max( getCount( statement[ hi.wd.dayOpenFrom ] ), 			getCount( statement[ hi.wd.dayOpenTo ] ) ) 		for j = 1, count, 1 do 			addComment( comments, 				getTimePeriod( statement[ hi.wd.dayOpenFrom ], 					statement[ hi.wd.dayOpenTo ], j, statement.value ) ) 		end 		for j, key in ipairs( hi.wd.comments ) do 			if statement[ key ] then 				addComment( comments, table.concat( statement[ key ], 					hi.texts.comma ) ) 			end 		end  		-- concating times and comments 		times = {} 		tableInsert( times, s ) 		s = table.concat( comments, hi.texts.comma ) 		if isSet( s ) then 			table.insert( times, mw.ustring.format( hi.texts.parentheses, s ) ) 		end  		local item = {} 		tableInsert( item, table.concat( times, hi.texts.space ) )  		-- close statements (P3026) as qualifiers for open days property (P3025) 		mergeDays( statement[ hi.wd.closed ] ) 		if not hi.options.clusterClosed and ( i == #statements or 			statements[ i ].value ~= statements[ i + 1 ].value ) then 			convertDayRange( closeDays ) 			tableInsert( item, getClosed( closeDays ) ) 			clearDays() 		end 		s = table.concat( item, hi.texts.comma ) 	 		-- copying each statement to result table 		if statement.sort2 == 1 then 			tableInsert( result, { value = { statement.value }, times = s } ) 		elseif s ~= '' then 			result[ #result ].times = concatStrings( hi.texts.comma, 				result[ #result ].times, s ) 		end 	end  	-- checking for duplicates 	for i = #result, 2, -1 do 		if result[ i ].times == result[ i - 1 ].times then 			for j, value in ipairs( result[ i ].value ) do 				table.insert( result[ i - 1 ].value, value ) 			end 			table.remove( result, i ) 		end 	end  	-- converting day range 	for i = 1, #result, 1 do 		local arr = result[ i ].value 		convertDayRange( arr ) 		result[ i ] = concatStrings( hi.texts.space, 			table.concat( arr, hi.texts.comma ), result[ i ].times ) 	end  	-- 2nd step: getting separated close statements (P3026) 	local statements = wu.getValuesWithQualifiers( entity, hi.wd.closed, nil, 		hi.wd.commentsForClosed, hi.wd.retrieved, nil, getLabelFromId, wikilang, 		fallbackLang ) 	if #statements > 0 then 		lastEdit = wu.getLastedit( lastEdit, statements )  		-- getting closed values 		local closed = {}	 		for i, statement in ipairs( statements ) do 			local closedDate = {} 			table.insert( closedDate, statement.value )  			-- getting comments 			comments = {} 			for j, key in ipairs( hi.wd.commentsForClosed ) do 				if statement[ key ] then 					addComment( comments, table.concat( statement[ key ], 						hi.texts.comma ) ) 				end 			end 			s = table.concat( comments, hi.texts.comma ) 			if isSet( s ) then 				table.insert( closedDate, mw.ustring.format( hi.texts.parentheses, s ) ) 			end  			table.insert( closed, table.concat( closedDate, hi.texts.space ) ) 		end 		mergeDays( closed ) 	end 	convertDayRange( closeDays ) 	tableInsert( result, getClosed( closeDays ) )  	-- 3rd step: adding additional statements 	local statements = wu.getValuesWithQualifiers( entity, hi.wd.stateOfUse, 		nil, {}, hi.wd.retrieved, nil, getLabelFromId, wikilang, fallbackLang ) 	if #statements > 0 then 		lastEdit = wu.getLastedit( lastEdit, statements ) 		for i, statement in ipairs( statements ) do 			tableInsert( result, statement.value ) 		end 	end  	-- merging all statements 	local result = table.concat( result, hi.texts.semicolon )  	-- adding maintenance categories 	if result ~= '' then 		categIds.hoursFromWikidata = 1 		if showOptions.addCategories then 			result = result .. hr.getCategories( formatStr ) 		end 	end 	return result, lastEdit end  -- invoke helper functions -- splitting show parameters local function splitAndCheck( s ) 	local arr = {} 	local err = {} 	if isSet( s ) then 		for i, v in ipairs( mw.text.split( s, ',', true ) ) do 			v = mw.text.trim( v ) 			if not hi.show[ v ] then 				table.insert( err, v ) 			else 				arr[ v ] = '' 			end 		end 	end 	return arr, err end  -- check if pareameters are valid local function checkParameters( args ) 	local err = {} 	if not args and type( args ) ~= 'table' then 		return err 	end 	for k, v in pairs( args ) do 		if not hi.params[ k ] then 			table.insert( err, k ) 		end 	end 	return err end  -- formating and concating error strings local function getErrorStr( arr, formatStr ) 	return #arr == 0 and '' or 		mw.ustring.format( formatStr, table.concat( arr, hi.texts.comma ) ) end  -- main function for template #invoke calls -- id: Q id of an establishment -- format: output format like 'opened at %s' -- fallback: fallback language if labels are not available in content language function hr.getHours( frame )     local args = frame.args     args.id = mw.text.trim( args.id or '' )     if not isSet( args.id ) or not mw.wikibase.isValidEntityId( args.id ) then         return hi.categories.invalidId     end     if not isSet( args.format ) then     	args.format = hi.texts.format     else 	    local s, count = args.format:gsub( '%%s', '%%s' )     	if count ~= 1 then         	args.format = hi.texts.format     	end     end     args.fallback = args.fallback or ''     local wikilang = mw.getContentLanguage():getCode()  	local paramErr = checkParameters( args ) 	local show, showErr = splitAndCheck( args.show )      local result, lastEdit = hr.getHoursFromWikidata( args.id, wikilang,     	args.fallback, '', show, false, nil )     if result ~= '' then     	result = mw.ustring.format( args.format, result )     end     return result .. getErrorStr( paramErr, hi.categories.unknownParams )     	.. getErrorStr( showErr, hi.categories.unknownShowOptions ) end  return hr