Module talk:Time

This is an old revision of this page, as edited by BrandonXLF (talk | contribs) at 22:57, 10 August 2018 (Template-protected edit request on 9 August 2018). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Latest comment: 7 years ago by BrandonXLF in topic Template-protected edit request on 9 August 2018

Shortin month

@Trappist the monk: I think we should shortin the month names to allow for use on Template:Datetime and to keep other templaes short aswell. --★BrandonALF★ talk edits 22:41, 16 December 2017 (UTC)Reply

It looks to me like you have broken existing uses of {{datetime}}. Please revert your changes there.
Trappist the monk (talk) 22:59, 16 December 2017 (UTC)Reply
@Trappist the monk: I'm sorry, I didn't realize that was there. So now I need to do my edit for Template:Local time --★BrandonALF★ talk edits 23:06, 16 December 2017 (UTC)Reply
Thank you. There are 1000+, mostly user pages, that use {{time}} and so use this module. Given that, it would seem to me that you either accept long month names or find a way to tell the module to abbreviate specific {{#invoke:}} instances. You don't just decide for everyone that from now on the date will render as an abbreviation.
Trappist the monk (talk) 23:26, 16 December 2017 (UTC)Reply
I have raised the protection level of this module to require WP:Template editor permission because you have elected to edit war instead of discuss. Feel free to use sandboxen for your template development. Also, use testcases pages to do testing before adding your template to mainspace articles. Testing as you have been doing is considered disruptive and may result in your editing privileges being restricted or revoked.
Trappist the monk (talk) 00:00, 17 December 2017 (UTC)Reply

Documentation

Hey I just discovered this module after I saw it was used on a table at the NFL playoffs article and would like an explanation as to how it works. –Piranha249 (talk) 02:03, 9 January 2018 (UTC)Reply

I think that you are mistaken. This module is not used at NFL playoffs. You can prove this to your self. Follow this link. Below the Publish changes button you will see 'Pages transcluded onto the current version of this page'. Click that to get a list of all templates and modules transcluded in NFL playoffs. Module:Time is not there.
What you are seeing is the #time parser function.
Trappist the monk (talk) 02:22, 9 January 2018 (UTC)Reply
Oh, I thought it was there, but I forgot the modules start with Invoke. –Piranha249 (talk) 02:32, 9 January 2018 (UTC)Reply

Abbreviations for Hawaii-Aleutian time zones are wrong

Someone recently changed the Hawaii–Aleutian Time Zone page to have the abbreviations HAST/HADT in the infobox for time zone (North America) to match the abbreviations here, but the abbreviations are wrong. Please see references on that page. The correct abbreviations are HST/HDT, and are what were in the page beforehand. The abbreviations used here are incorrect also. The lines that read:

['hast'] = {	-- same as AleutST and HST
 abbr = 'HAST',
 dst_abbr = 'HADT',

need to be changed to:

['hst'] = {	-- same as AleutST
 abbr = 'HST',	-- note: not HAST or HADT
 dst_abbr = 'HDT',

Template-protected edit request on 8 August 2018

local function get_utc_offset_hour (timezone)
	local hours;
	
	hours = mw.ustring.match (tz[timezone].utc_offset, '[+-±−]?(%d%d):%d%d');

	return hours;
end

local function get_utc_offset_min (timezone)
	local minutes;
	
	minutes = mw.ustring.match (tz[timezone].utc_offset, '[+-±−]?%d%d:(%d%d)');
	
	return minutes;
end

local function get_utc_offset_sign (timezone)
	local sign;
	
	sign = mw.ustring.match (tz[timezone].utc_offset, '([%+%-±−]?)%d%d:%d%d');
	
	if '-' == sign then sign = '-'; else sign = '+'; end

	return sign;
end

function p.offset (frame)
	local args = getArgs(frame);
	local utc_offset_hour;
	local utc_offset_min;
	local utc_offset_sign;
	
	if args[1] then
		args[1] = args[1]:lower();

		if mw.ustring.match (args[1], 'utc[%+%-±−]?%d%d:%d%d') then
			args[1] = 'utc_offsets';
		end
		if not is_set (tz[args[1]]) then
			return '<span style="font-size:100%" class="error">{{time}} – unknown timezone ([[Template:Time#Error messages|help]])</span>';
		end
	else
		args[1] = 'utc';
	end

	utc_offset_hour = get_utc_offset_hour (args[1]);
	utc_offset_min = get_utc_offset_min (args[1]);
	utc_offset_sign = get_utc_offset_sign (args[1]);

	return string.format ('[[UTC%s%s:%s]]', utc_offset_sign, utc_offset_hour, utc_offset_min);

end
I added <syntaxhighlight>...</syntaxhighlight> to make your code more readable. How does this change make {{Infobox time zone}} work more reliably? If that template is 'unreliable', shouldn't fixes be applied there? Why is your proposed code so complex? Can't it be made simpler?
Trappist the monk (talk) 16:04, 8 August 2018 (UTC)Reply
Wouldn't this work just as well?
function p.offset (frame)
	local args = getArgs(frame);
	if args[1] then
		args[1] = args[1]:lower();												
	
		if not is_set (tz[args[1]]) then
			return '<span style="font-size:100%" class="error">{{time}} – unknown timezone ([[Template:Time#Error messages|help]])</span>';
		end
	end
	
	return table.concat ({'[[UTC', tz[args[1]].utc_offset:gsub ('^(%d)', '+%1'):gsub ('^-', '−'), ']]'});
	end
Trappist the monk (talk) 16:37, 8 August 2018 (UTC)Reply

@Trappist the monk: Yes it would, because it's smaller and more efficient I prefer if your code is added. It makes {{Infobox time zone}} more reliable because currently it's using a template that doesn't have a lot of timezone, where as Module:time as a lot of time zones already. —  BrandonXLF   (t@lk) (ping back) 16:51, 8 August 2018 (UTC)Reply

You are speaking of {{Timezoneoffset}}? Looks to me like there are 155 timezones listed. That number is rather more than the number listed in Module:Time.
Trappist the monk (talk) 17:04, 8 August 2018 (UTC)Reply
@Trappist the monk: Sorry, I forgot I switch it back to use that tempalte, but the issue is there's many repeated abbreviation and rather then breaking the template into DST and non DST it would be easier to add this function, besides the infobox already uses module:time to display the time of the timezone. —  BrandonXLF   (t@lk) (ping back) 17:10, 8 August 2018 (UTC)Reply
I'm confused. You created that template which does support DST, something that p.offset() won't. If there are repeated abbreviation[s] then isn't it a simple matter of locating and excising those? I could imagine translating the information in {{Timezoneoffset}} into a Lua table and then having p.offset() mw.loadData() and use that table instead of using the tz{} table. Later, tz{} might be adapted to use the offsets{} table.
Trappist the monk (talk) 10:33, 9 August 2018 (UTC)Reply
@Trappist the monk: I'll figure something out. —  BrandonXLF   (t@lk) (ping back) 14:27, 9 August 2018 (UTC)Reply

Template-protected edit request on 9 August 2018

replace p.time with

Extended content
function p.time (frame)
	local args = getArgs(frame);
	local utc_timestamp, timestamp;												-- current or _TEST_TIME_ timestamps; timestamp is local ST or DST time used in output
	local dst_begin_ts, dst_end_ts;												-- DST begin and end timestamps in UTC
	local tz_abbr;																-- select ST or DST timezone abbreviaion used in output 
	local tz_string;															-- output time in |df= format
	local utc_offset;
	local invert;																-- true when southern hemisphere
	local df;																	-- date format flag; the |df= parameter
	local hf;                                                                   -- hour format flag; derived from the |df=dmy12 and |df=mdy12 parameters
	local timeonly;
	local dateonly;
	
	if args[1] then
		args[1] = args[1]:lower();												-- make lower case because tz table member indexes are lower case

		if mw.ustring.match (args[1], 'utc[%+%-±−]?%d%d:%d%d') then				-- if rendering time for a UTC offset timezone
			tz['utc_offsets'].abbr = args[1]:upper():gsub('%-', '−');			-- set the link label to upper case and replace hyphen with a minus character (U+2212)
			tz['utc_offsets'].article = tz['utc_offsets'].abbr;					-- article title same as abbreviation
			tz['utc_offsets'].utc_offset = mw.ustring.match (args[1], 'utc([%+%-±−]?%d%d:%d%d)'):gsub('−', '%-');	-- extract the offset value; replace minus character with hyphen
			args[1] = 'utc_offsets';											-- point to the generic utc offsets table 
		end
		if not is_set (tz[args[1]]) then
			return '<span style="font-size:100%" class="error">{{time}} – unknown timezone ([[Template:Time#Error messages|help]])</span>';
		end
	else
		args[1] = 'utc';														-- default to utc
	end
	
	timeonly = args.timeonly;
	dateonly = args.dateonly;
	
	df = args.df or args[2] or tz[args[1]].df or '';							-- template |df= overrides typical df from tz properties TODO: error check these values?
	if is_set (df) then
		df = df:lower();														-- lower case because we will compare to lower case values later
	end

	hf = df:match ('%l%ly(12)');												-- hf == '12' selects 12-hour AM/PM display; other values ignored and 24 hour clock time displayed 
	if is_set (hf) then
		df = df:match ('(%l%ly)12');											-- extract df
	end

	if is_set (args._TEST_TIME_) then											-- typically used to test the code at a specific utc time
		local test_time = get_test_time (args._TEST_TIME_);
		if not test_time then
			return '<span style="font-size:100%" class="error">{{time}} – malformed or incomplete _TEST_TIME_ ([[Template:Time#Error messages|help]])</span>';
		end

--		utc_timestamp = os.time(get_test_time (args._TEST_TIME_));
		utc_timestamp = os.time(test_time);
	else
		utc_timestamp = os.time ();												-- get current server time (UTC)
	end
	utc_offset = get_utc_offset (args[1]);										-- utc offset for specified timezone
	timestamp = utc_timestamp + utc_offset;										-- make local time timestamp

	if 'no' == args.dst then													-- for timezones that DO observe dst but for this ___location ...
		tz_abbr = tz[args[1]].abbr;												-- ... dst is not observed (|dst=no) show time as standard time
	else
		if is_set (tz[args[1]].dst_begins) and is_set (tz[args[1]].dst_ends) and is_set (tz[args[1]].dst_time) then		-- make sure we have all of the parts
			dst_begin_ts, dst_end_ts, invert = make_dst_timestamps (timestamp, args[1]);	-- get begin and end dst timestamps and invert flag

			if nil == dst_begin_ts or nil == dst_end_ts then
				return '<span style="font-size:100%" class="error">{{time}} – error calculating dst timestamps ([[Template:Time#Error messages|help]])</span>';
			end
	
			if invert then														-- southern hemisphere; use beginning and ending of standard time in the comparison
				if utc_timestamp >= dst_end_ts and utc_timestamp < dst_begin_ts then	-- is current date time standard time?
					tz_abbr = tz[args[1]].abbr;									-- standard time abbreviation
				else		
					timestamp = timestamp + 3600;								-- add an hour for 
					tz_abbr = tz[args[1]].dst_abbr;								-- dst abbreviation
				end
			else																-- northern hemisphere
				if utc_timestamp >= dst_begin_ts and utc_timestamp < dst_end_ts then	-- all timestamps are UTC
					timestamp = timestamp + 3600;								-- add an hour
					tz_abbr = tz[args[1]].dst_abbr;
				else
					tz_abbr = tz[args[1]].abbr;
				end
			end
		elseif is_set (tz[args[1]].dst_begins) or is_set (tz[args[1]].dst_ends) or is_set (tz[args[1]].dst_time) then	-- if some but not all not all parts then emit error message
			return '<span style="font-size:100%" class="error">{{time}} – incomplete definition for ' .. args[1]:upper() .. ' ([[Template:Time#Error messages|help]])</span>';
		else
			tz_abbr = tz[args[1]].abbr;											-- dst not observed for this timezone
		end
	end
	
	if 'yes' == timeonly then
		if '12' == hf then
			tz_string = mw.text.trim (os.date ('%l:%M %p'));
		else
			tz_string = os.date ('%R');	
		end
	elseif 'yes' == dateonly then
		if 'dmy' == hf or 'y' == df then
			tz_string = mw.text.trim (os.date ('%e %B %Y', timestamp));
		else
			tz_string = os.date ('%B %e %Y', timestamp);	
		end
	else
		if 'y' == df or 'dmy' == df then											-- format the output (|df=y is legacy from original template)
			if '12' == hf then
				tz_string = mw.text.trim (os.date ('%l:%M %p, %e %B %Y', timestamp));	-- dmy, 12 hour am/pm
			else
				tz_string = os.date ('%R, %e %B %Y', timestamp);					-- dmy
			end
		elseif 'iso' == df then
			tz_string = os.date ('%FT%R', timestamp);								-- iso
		else
			if '12' == hf then
				tz_string = mw.text.trim (os.date ('%l:%M %p, %B %e, %Y', timestamp));	-- mdy (legacy default)
			else
				tz_string = os.date ('%R, %B %e, %Y', timestamp);					-- mdy (legacy default)
			end
		end
	end

	if not is_set (tz[args[1]].article) then									-- if some but not all not all parts then emit error message
		return '<span style="font-size:100%" class="error">{{time}} – incomplete definition for ' .. args[1]:upper() .. ' ([[Template:Time#Error messages|help]])</span>';
	end
	
	local refreshLink = mw.title.getCurrentTitle():fullUrl{action = 'purge'}	-- create a refresh link
	return string.format ('%s [[%s|%s]] <span class="plainlinks" style="font-size:80%%;">[[%s refresh]]</span>', tz_string, tz[args[1]].article, tz_abbr, refreshLink);
end

What it does is add parameters timeonly and dateonly, which allows the module to output the time or date of an timezone. This would be very helpful in the userspace and in some templates. —  BrandonXLF   (t@lk) (ping back) 20:46, 9 August 2018 (UTC)Reply

Not ready, methinks:
  • {{#invoke:time/sandbox|time|dateonly=yes}} → 30 August 2025 UTC [refresh]
  • {{#invoke:time/sandbox|time|dateonly=yes|df=dmy}} → 30 August 2025 UTC [refresh]
  • {{#invoke:time/sandbox|time|dateonly=yes|df=mdy}} → August 30, 2025 UTC [refresh]
  • {{#invoke:time/sandbox|time|dateonly=yes|df=y}} → 30 August 2025 UTC [refresh]
  • {{#invoke:time/sandbox|time|dateonly=yes|df=iso}} → 2025-08-30 UTC [refresh]
Trappist the monk (talk) 21:13, 9 August 2018 (UTC)Reply
@Trappist the monk: Fixed the issues from above:
Extended content
function p.time (frame)
	local args = getArgs(frame);
	local utc_timestamp, timestamp;												-- current or _TEST_TIME_ timestamps; timestamp is local ST or DST time used in output
	local dst_begin_ts, dst_end_ts;												-- DST begin and end timestamps in UTC
	local tz_abbr;																-- select ST or DST timezone abbreviaion used in output 
	local tz_string;															-- output time in |df= format
	local utc_offset;
	local invert;																-- true when southern hemisphere
	local df;																	-- date format flag; the |df= parameter
	local hf;                                                                   -- hour format flag; derived from the |df=dmy12 and |df=mdy12 parameters
	local timeonly;
	local dateonly;
	
	if args[1] then
		args[1] = args[1]:lower();												-- make lower case because tz table member indexes are lower case

		if mw.ustring.match (args[1], 'utc[%+%-±−]?%d%d:%d%d') then				-- if rendering time for a UTC offset timezone
			tz['utc_offsets'].abbr = args[1]:upper():gsub('%-', '−');			-- set the link label to upper case and replace hyphen with a minus character (U+2212)
			tz['utc_offsets'].article = tz['utc_offsets'].abbr;					-- article title same as abbreviation
			tz['utc_offsets'].utc_offset = mw.ustring.match (args[1], 'utc([%+%-±−]?%d%d:%d%d)'):gsub('−', '%-');	-- extract the offset value; replace minus character with hyphen
			args[1] = 'utc_offsets';											-- point to the generic utc offsets table 
		end
		if not is_set (tz[args[1]]) then
			return '<span style="font-size:100%" class="error">{{time}} – unknown timezone ([[Template:Time#Error messages|help]])</span>';
		end
	else
		args[1] = 'utc';														-- default to utc
	end
	
	timeonly = args.timeonly;
	dateonly = args.dateonly;
	
	df = args.df or args[2] or tz[args[1]].df or '';							-- template |df= overrides typical df from tz properties TODO: error check these values?
	if is_set (df) then
		df = df:lower();														-- lower case because we will compare to lower case values later
	end

	hf = df:match ('%l%ly(12)');												-- hf == '12' selects 12-hour AM/PM display; other values ignored and 24 hour clock time displayed 
	if is_set (hf) then
		df = df:match ('(%l%ly)12');											-- extract df
	end

	if is_set (args._TEST_TIME_) then											-- typically used to test the code at a specific utc time
		local test_time = get_test_time (args._TEST_TIME_);
		if not test_time then
			return '<span style="font-size:100%" class="error">{{time}} – malformed or incomplete _TEST_TIME_ ([[Template:Time#Error messages|help]])</span>';
		end

--		utc_timestamp = os.time(get_test_time (args._TEST_TIME_));
		utc_timestamp = os.time(test_time);
	else
		utc_timestamp = os.time ();												-- get current server time (UTC)
	end
	utc_offset = get_utc_offset (args[1]);										-- utc offset for specified timezone
	timestamp = utc_timestamp + utc_offset;										-- make local time timestamp

	if 'no' == args.dst then													-- for timezones that DO observe dst but for this ___location ...
		tz_abbr = tz[args[1]].abbr;												-- ... dst is not observed (|dst=no) show time as standard time
	else
		if is_set (tz[args[1]].dst_begins) and is_set (tz[args[1]].dst_ends) and is_set (tz[args[1]].dst_time) then		-- make sure we have all of the parts
			dst_begin_ts, dst_end_ts, invert = make_dst_timestamps (timestamp, args[1]);	-- get begin and end dst timestamps and invert flag

			if nil == dst_begin_ts or nil == dst_end_ts then
				return '<span style="font-size:100%" class="error">{{time}} – error calculating dst timestamps ([[Template:Time#Error messages|help]])</span>';
			end
	
			if invert then														-- southern hemisphere; use beginning and ending of standard time in the comparison
				if utc_timestamp >= dst_end_ts and utc_timestamp < dst_begin_ts then	-- is current date time standard time?
					tz_abbr = tz[args[1]].abbr;									-- standard time abbreviation
				else		
					timestamp = timestamp + 3600;								-- add an hour for 
					tz_abbr = tz[args[1]].dst_abbr;								-- dst abbreviation
				end
			else																-- northern hemisphere
				if utc_timestamp >= dst_begin_ts and utc_timestamp < dst_end_ts then	-- all timestamps are UTC
					timestamp = timestamp + 3600;								-- add an hour
					tz_abbr = tz[args[1]].dst_abbr;
				else
					tz_abbr = tz[args[1]].abbr;
				end
			end
		elseif is_set (tz[args[1]].dst_begins) or is_set (tz[args[1]].dst_ends) or is_set (tz[args[1]].dst_time) then	-- if some but not all not all parts then emit error message
			return '<span style="font-size:100%" class="error">{{time}} – incomplete definition for ' .. args[1]:upper() .. ' ([[Template:Time#Error messages|help]])</span>';
		else
			tz_abbr = tz[args[1]].abbr;											-- dst not observed for this timezone
		end
	end
	
	if 'yes' == timeonly then
		if '12' == hf then
			tz_string = mw.text.trim (os.date ('%l:%M %p'));
		else
			tz_string = os.date ('%R');	
		end
	elseif 'yes' == dateonly then
		if 'dmy' == df or 'y' == df then
			tz_string = mw.text.trim (os.date ('%e %B %Y'));
		elseif 'iso' == df then
			tz_string = mw.text.trim (os.date ('%F'));
		else
			tz_string = os.date ('%B %e %Y');	
		end
	else
		if 'y' == df or 'dmy' == df then											-- format the output (|df=y is legacy from original template)
			if '12' == hf then
				tz_string = mw.text.trim (os.date ('%l:%M %p, %e %B %Y', timestamp));	-- dmy, 12 hour am/pm
			else
				tz_string = os.date ('%R, %e %B %Y', timestamp);					-- dmy
			end
		elseif 'iso' == df then
			tz_string = os.date ('%FT', timestamp);								-- iso
		else
			if '12' == hf then
				tz_string = mw.text.trim (os.date ('%l:%M %p, %B %e, %Y', timestamp));	-- mdy (legacy default)
			else
				tz_string = os.date ('%R, %B %e, %Y', timestamp);					-- mdy (legacy default)
			end
		end
	end

	if not is_set (tz[args[1]].article) then									-- if some but not all not all parts then emit error message
		return '<span style="font-size:100%" class="error">{{time}} – incomplete definition for ' .. args[1]:upper() .. ' ([[Template:Time#Error messages|help]])</span>';
	end
	
	local refreshLink = mw.title.getCurrentTitle():fullUrl{action = 'purge'}	-- create a refresh link
	if dateonly == 'yes' or timeonly == 'yes' then
		return string.format ('%s <span class="plainlinks" style="font-size:80%%;">[[%s refresh]]</span>', tz_string, refreshLink);
	else
		return string.format ('%s [[%s|%s]] <span class="plainlinks" style="font-size:80%%;">[[%s refresh]]</span>', tz_string, tz[args[1]].article, tz_abbr, refreshLink);
	end
end

 BrandonXLF   (t@lk) (ping back) 01:12, 10 August 2018 (UTC)Reply

You didn't actually. I've rewritten that section of the code so that it is simpler. Here are some results:
time & date:
time only:
date only:
Trappist the monk (talk) 12:43, 10 August 2018 (UTC)Reply
@Trappist the monk: That works too. I think that refresh link can be annoying as some need it in different places so I added |refresh= to the sandbox
 BrandonXLF   (t@lk) (ping back) 13:37, 10 August 2018 (UTC)Reply
Tweaked that a bit. Why have you chosen to omitted the timezone abbreviation when |dateonly=yes and |timeonly=yes? It seems to me that the default rendering must include the timezone abbreviation else readers don't know where the time/date applies.
Trappist the monk (talk) 15:08, 10 August 2018 (UTC)Reply
@Trappist the monk: I've chosen to ommit time timezone abbreviation because some templates are like "It's 21:30 where this user lives" If you want to include the abbreviation you can add a parameter like |abbrev= to include it or not. —  BrandonXLF   (t@lk) (ping back) 19:39, 10 August 2018 (UTC)Reply
I added |show_tz=