Jump to content
Wikipedia The Free Encyclopedia

Module:Time

From Wikipedia, the free encyclopedia
Module documentationview edit history purge
This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing.
Page extended-confirmed-protected This module is currently under extended confirmed protection.
Extended confirmed protection prevents edits from all unregistered editors and registered users with fewer than 30 days tenure and 500 edits. The policy on community use specifies that extended confirmed protection can be applied to combat disruption, if semi-protection has proven to be ineffective. Extended confirmed protection may also be applied to enforce arbitration sanctions. Please discuss any changes on the talk page; you may submit an edit request to ask for uncontroversial changes supported by consensus.
Warning This Lua module is used on approximately 3,500 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them.
This module depends on the following other modules:

Implements {{time}} and {{UTC offset}}.

The above documentation is transcluded from Module:Time/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.

 require('strict')
 localyesno=require('Module:Yesno')
 localgetArgs=require('Module:Arguments').getArgs
 localdata=mw.loadData('Module:Time/data'..(mw.getCurrentFrame():getTitle():match('/sandbox')or''));-- load the data module
 localcfg=data.cfg;-- for internationalization 

 localtz={};-- holds local copy of the specified timezone table from tz_data{}


 --[[--------------------------< I S _ S E T >------------------------------------------------------------------

 Whether variable is set or not. A variable is set when it is not nil and not empty.

 ]]

 localfunctionis_set(var)
 returnnot(nil==varor''==var);
 end


 --[[--------------------------< S U B S T I T U T E >----------------------------------------------------------

 Populates numbered arguments in a message string using an argument table.

 ]]

 localfunctionsubstitute(msg,args_t)
 returnargs_tandmw.message.newRawMessage(msg,args_t):plain()ormsg;
 end


 --[[--------------------------< E R R O R _ M S G >------------------------------------------------------------

 create an error message
 <args_t> is a sequence where [1] is template name and [2] is substituted error message
 ]]

 localfunctionerror_msg(args_t)
 returnsubstitute(cfg.err_msg,args_t);
 end


 --[[--------------------------< D E C O D E _ D S T _ E V E N T >----------------------------------------------

 extract ordinal, day-name, and month from daylight saving start/end definition string as digits:
 	Second Sunday in March
 returns
 	2 0 3

 Casing doesn't matter but the form of the string does:
 	<ordinal> <day> <any single word> <month> – all are separated by spaces

 ]]

 localfunctiondecode_dst_event(dst_event_string)
 localord,day,month;

 dst_event_string=dst_event_string:lower();-- force the string to lower case because that is how the tables above are indexed
 ord,day,month=dst_event_string:match('([%a%d]+)%s+(%a+)%s+%a+%s+(%a+)');

 ifnot(is_set(ord)andis_set(day)andis_set(month))then-- if one or more of these not set, then pattern didn't match
 returnnil;
 end

 returncfg.ordinals[ord],cfg.days[day],cfg.months[month];
 end


 --[[--------------------------< G E T _ D A Y S _ I N _ M O N T H >--------------------------------------------

 Returns the number of days in the month where month is a number 1–12 and year is four-digit Gregorian calendar.
 Accounts for leap year.

 ]]

 localfunctionget_days_in_month(year,month)
 localdays_in_month={31,28,31,30,31,30,31,31,30,31,30,31};

 year=tonumber(year);-- force these to be numbers just in case
 month=tonumber(month);

 if(2==month)then-- if February
 if(0==(year%4)and(0~=(year%100)or0==(year%400)))then-- is year a leap year?
 return29;-- if leap year then 29 days in February
 end
 end
 returndays_in_month[month];
 end


 --[[--------------------------< G E T _ D S T _ M O N T H _ D A Y >--------------------------------------------

 Return the date (month and day of the month) for the day that is the ordinal (nth) day-name in month (second
 Friday in June) of the current year

 timestamp is today's date-time number from os.time(); used to supply year
 timezone is the timezone parameter value from the template call

 Equations used in this function taken from Template:Weekday_in_month

 ]]

 localfunctionget_dst_month_day(timestamp,start)
 localord,weekday_num,month;
 localfirst_day_of_dst_month_num;
 locallast_day_of_dst_month_num;
 localdays_in_month;
 localyear;

 iftrue==startthen
 ord,weekday_num,month=decode_dst_event(tz.dst_begins);-- get start string and convert to digits
 else
 ord,weekday_num,month=decode_dst_event(tz.dst_ends);-- get end string and convert to digits
 end

 ifnot(is_set(ord)andis_set(weekday_num)andis_set(month))then
 returnnil;-- could not decode event string
 end

 year=os.date('%Y',timestamp);

 if-1==ordthen-- j = t + ×ばつ(n + 1) - (wt - w) mod 7				-- if event occurs on the last day-name of the month ('last Sunday of October')
 days_in_month=get_days_in_month(year,month);
 last_day_of_dst_month_num=os.date('%w',os.time({['year']=year,['month']=month,['day']=days_in_month}));
 returnmonth,days_in_month+7*(ord+1)-((last_day_of_dst_month_num-weekday_num)%7);
 else-- j = ×ばつn - 6 + (w - w1) mod 7
 first_day_of_dst_month_num=os.date('%w',os.time({['year']=year,['month']=month,['day']=1}))
 returnmonth,7*ord-6+(weekday_num-first_day_of_dst_month_num)%7;-- return month and calculated date
 end
 end


 --[[--------------------------< G E T _ U T C _ O F F S E T >--------------------------------------------------

 Get utc offset in hours and minutes, convert to seconds. If the offset can't be converted return nil.
 TODO: return error message?
 TODO: limit check this? +/-n hours?
 ]]

 localfunctionget_utc_offset()
 localsign;
 localhours;
 localminutes;

 sign,hours,minutes=mw.ustring.match(tz.utc_offset,'([%+%-±−]?)(%d%d):(%d%d)');

 if'-'==signthensign=-1;elsesign=1;end
 ifis_set(hours)andis_set(minutes)then
 returnsign*((hours*3600)+(minutes*60));
 else
 returnnil;-- we require that all timezone tables have what appears to be a valid offset
 end
 end


 --[[--------------------------< M A K E _ D S T _ T I M E S T A M P S >----------------------------------------

 Return UTC timestamps for the date/time of daylight saving time events (beginning and ending). These timestamps
 will be compared to current UTC time. A dst timestamp is the date/time in seconds UTC for the timezone at the
 hour of the dst event.

 For dst rules that specify local event times, the timestamp is the sum of:
 	timestamp = current year + dst_month + dst_day + dst_time (all in seconds) local time
 Adjust local time to UTC by subtracting utc_offset:
 	timestamp = timestamp - utc_offset (in seconds)
 For dst_end timestamp, subtract an hour for DST
 	timestamp = timestamp - 3600 (in seconds)

 For dst rules that specify utc event time the process is the same except that utc offset is not subtracted.

 ]]

 localfunctionmake_dst_timestamps(timestamp)
 localdst_begin,dst_end;-- dst begin and end time stamps 
 localyear;-- current year
 localdst_b_month,dst_e_month,dst_day;-- month and date of dst event
 localdst_hour,dst_minute;-- hour and minute of dst event on year-dst_month-dst_day
 localinvert=false;-- flag to pass on when dst_begin month is numerically larger than dst_end month (southern hemisphere)
 localutc_offset;
 localutc_flag;

 year=os.date('%Y',timestamp);-- current year
 utc_offset=get_utc_offset();-- in seconds
 ifnotis_set(utc_offset)then-- utc offset is a required timezone property
 returnnil;
 end

 dst_b_month,dst_day=get_dst_month_day(timestamp,true);-- month and day that dst begins
 ifnotis_set(dst_b_month)then
 returnnil;
 end

 dst_hour,dst_minute=tz.dst_time:match('(%d%d):(%d%d)');-- get dst time
 utc_flag=tz.dst_time:find('[Uu][Tt][Cc]%s*$');-- set flag when dst events occur at a specified utc time

 dst_begin=os.time({['year']=year,['month']=dst_b_month,['day']=dst_day,['hour']=dst_hour,['min']=dst_minute});-- form start timestamp
 ifnotis_set(utc_flag)then-- if dst events are specified to occur at local time
 dst_begin=dst_begin-utc_offset;-- adjust local time to utc by subtracting utc offset
 end

 dst_e_month,dst_day=get_dst_month_day(timestamp,false);-- month and day that dst ends
 ifnotis_set(dst_e_month)then
 returnnil;
 end

 ifis_set(tz.dst_e_time)then
 dst_hour,dst_minute=tz.dst_e_time:match('(%d%d):(%d%d)');-- get ending dst time; this one for those locales that use different start and end times
 utc_flag=tz.dst_e_time:find('[Uu][Tt][Cc]%s*$');-- set flag if dst is pegged to utc time
 end

 dst_end=os.time({['year']=year,['month']=dst_e_month,['day']=dst_day,['hour']=dst_hour,['min']=dst_minute});-- form end timestamp
 ifnotis_set(utc_flag)then-- if dst events are specified to occur at local time
 dst_end=dst_end-3600;-- assume that local end time is DST so adjust to local ST
 dst_end=dst_end-utc_offset;-- adjust local time to utc by subtracting utc offset
 end


 ifdst_b_month>dst_e_monththen
 invert=true;-- true for southern hemisphere eg: start September YYYY end April YYYY+1
 end

 returndst_begin,dst_end,invert;
 end


 --[[--------------------------< G E T _ T E S T _ T I M E >----------------------------------------------------

 decode ISO formatted date/time into a table suitable for os.time(). Fallback to {{Timestamp}} format.
 For testing, this time is UTC just as is returned by the os.time() function.

 ]]

 localfunctionget_test_time(iso_date)
 localyear,month,day,hour,minute,second;

 year,month,day,hour,minute,second=iso_date:match('(%d%d%d%d)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)');
 ifnotyearthen
 year,month,day,hour,minute,second=iso_date:match('^(%d%d%d%d)(%d%d)(%d%d)(%d%d)(%d%d)(%d%d)$');
 ifnotyearthen
 returnnil;-- test time did not match the specified patterns
 end
 end
 return{['year']=year,['month']=month,['day']=day,['hour']=hour,['min']=minute,['sec']=second};
 end

 --[[----------------------< G E T _ F U L L _ U T C _ O F F S E T >-----------------------------------------------

 Creates a standard UTC offset from numerical inputs, for function time to convert to a table. Expected inputs shall have the form:
 	<sign><hour><separator><portion>
 where:
 	<sign> – optional; one of the characters: '+', '-' (hyphen), '±', '−' (minus); defaults to '+'
 	<hour> - one or two digits
 	<separator> - one of the characters '.' or ':'; required when <portion> is included; ignored else
 	<portion> - optional; one or two digits when <separator> is '.'; two digits else

 returns correct utc offset string when input has a correct form; else returns the unmodified input

 ]]

 localfunctionget_full_utc_offset(utc_offset)
 localh,m,sep,sign;

 localpatterns={
 '^([%+%-±−]?)(%d%d?)(%.)(%d%d?)$',-- one or two fractional hour digits
 '^([%+%-±−]?)(%d%d?)(:)(%d%d)$',-- two minute digits
 '^([%+%-±−]?)(%d%d?)[%.:]?$',-- hours only; ignore trailing separator
 }

 for_,patterninipairs(patterns)do-- loop through the patterns
 sign,h,sep,m=mw.ustring.match(utc_offset,pattern);
 ifhthen
 break;-- if h is set then pattern matched
 end
 end

 ifnoththen
 returnutc_offset;-- did not match a pattern
 end

 sign=(''==sign)and'+'orsign;-- sign character is required; set to '+' if not specified

 m=('.'==sep)and((sep..m)*60)ormor0;-- fractional h to m

 returnstring.format('utc%s%02d:%02d',sign,h,m);
 end


 --[[--------------------------< T A B L E _ L E N >------------------------------------------------------------

 return number of elements in table

 ]]

 localfunctiontable_len(tbl)
 localcount=0;
 for_inpairs(tbl)do
 count=count+1;
 end
 returncount;
 end


 --[[--------------------------< F I R S T _ S E T >------------------------------------------------------------

 scans through a list of parameter names that are aliases of each other and returns the value assigned to the
 first args[alias] that has a set value; nil else. scan direction is right-to-left (top-to-bottom)

 ]]

 localfunctionfirst_set(list,args)
 locali=1;
 localcount=table_len(list);-- get count of items in list

 whilei<=countdo-- loop through all items in list
 ifis_set(args[list[i]])then-- if parameter name in list is set in args
 returnargs[list[i]];-- return the value assigned to the args parameter
 end
 i=i+1;-- point to next
 end
 end


 --[=[-------------------------< T I M E >----------------------------------------------------------------------

 This template takes several parameters (some positonal, some not); none are required:
 	1. the time zone abbreviation/UTC offset (positional, always the first unnamed parameter)
 	2. a date format flag; second positional parameter or |df=; can have one of several values
 	3. |dst= when set to 'no' disables dst calculations for locations that do not observe dst – Arizona in MST
 	4. |timeonly= when set to 'yes' only display the time
 	5. |dateonly= when set to 'yes' only display the date
 	6. |hide-refresh = when set to 'yes' removes the refresh link
 	7. |hide-tz = when set to 'yes' removes the timezone name
 	8. |unlink-tz = when set to 'yes' unlinks the timzone name
 	9. |_TEST_TIME_= a specific utc time in ISO date time format used for testing this code

 TODO: convert _TEST_TIME_ to |time=?

 Timezone abbreviations can be found here: [[List_of_time_zone_abbreviations]]

 For custom date format parameters |df-cust=, |df-cust-a=, |df-cust-p= use codes 
 described here: [[:mw:Help:Extension:ParserFunctions##time]]

 ]=]

 localfunctiontime(frame)
 localargs=getArgs(frame);
 localutc_timestamp,timestamp;-- current or _TEST_TIME_ timestamps; timestamp is local ST or DST time used in output
 localdst_begin_ts,dst_end_ts;-- DST begin and end timestamps in UTC
 localtz_abbr;-- select ST or DST timezone abbreviaion used in output 
 localtime_string;-- holds output time/date in |df= format
 localutc_offset;
 localinvert;-- true when southern hemisphere
 localDF;-- date format flag; the |df= parameter
 localis_dst_tz;

 localtz_aliases=data.tz_aliases;-- get the aliases table
 localtz_data=data.tz_data;-- get the tz data table

 localTimeonly=yesno(first_set(cfg.aliases['timeonly'],args));-- boolean
 localDateonly=yesno(first_set(cfg.aliases['dateonly'],args));-- boolean
 ifTimeonlyandDateonlythen-- invalid condition when both are set
 Timeonly,Dateonly=false;
 end

 localHide_refresh=yesno(first_set(cfg.aliases['hide-refresh'],args));-- boolean
 localHide_tz=yesno(first_set(cfg.aliases['hide-tz'],args));-- boolean
 localUnlink_tz=yesno(first_set(cfg.aliases['unlink-tz'],args));-- boolean
 localDST=first_set(cfg.aliases['dst'],args)ortrue;-- string 'always' or boolean

 localLang=first_set(cfg.aliases['lang'],args);-- to render in a language other than the local wiki's language

 localDF_cust=first_set(cfg.aliases['df-cust'],args);-- custom date/time formats

 localDF_cust_a=first_set(cfg.aliases['df-cust-a'],args);-- for am/pm sensitive formats
 localDF_cust_p=first_set(cfg.aliases['df-cust-p'],args);

 ifnot((DF_cust_aandDF_cust_p)or-- DF_cust_a xor DF_cust_p
 (notDF_cust_aandnotDF_cust_p))then
 returnerror_msg({'Time',cfg.err_text['bad_df_pair']});-- both are required
 end

 ifargs[1]then
 args[1]=get_full_utc_offset(args[1]):lower();-- make lower case because tz table member indexes are lower case
 else
 args[1]='utc';-- default to utc
 end

 ifmw.ustring.match(args[1],'utc[%+%-±−]%d%d:%d%d')then-- if rendering time for a UTC offset timezone
 tz.abbr=args[1]:upper():gsub('%-','−');-- set the link label to upper case and replace hyphen with a minus character (U+2212)
 tz.article=tz.abbr;-- article title same as abbreviation
 tz.utc_offset=mw.ustring.match(args[1],'utc([%+%-±−]?%d%d:%d%d)'):gsub('−','%-');-- extract the offset value; replace minus character with hyphen
 locals,t=mw.ustring.match(tz.utc_offset,'(±)(%d%d:%d%d)');-- ± only valid for offset 00:00
 ifsand'00:00'~=tthen
 returnerror_msg({'Time',cfg.err_text['bad_sign']});
 end
 tz.df='iso';
 args[1]='utc_offsets';-- spoof to show that we recognize this timezone
 else
 tz=tz_aliases[args[1]]andtz_data[tz_aliases[args[1]]]ortz_data[args[1]];-- make a local copy of the timezone table from tz_data{}
 ifnottzthen
 returnerror_msg({'Time',substitute(cfg.err_text['unknown_tz'],args[1])});-- if the timezone given isn't in module:time/data(/sandbox)
 end
 end

 DF=first_set(cfg.aliases['df'],args)orargs[2]ortz.dforcfg.default_df;-- template |df= overrides typical df from tz properties
 DF=DF:lower();-- normalize to lower case
 ifnotcfg.df_vals[DF]then
 returnerror_msg({'Time',substitute(cfg.err_text['bad_format'],DF)});
 end

 ifis_set(args._TEST_TIME_)then-- typically used to test the code at a specific utc time
 localtest_time=get_test_time(args._TEST_TIME_);
 ifnottest_timethen
 returnerror_msg({'Time',cfg.err_text['test_time']});
 end

 utc_timestamp=os.time(test_time);
 else
 utc_timestamp=os.time();-- get current server time (UTC)
 end
 utc_offset=get_utc_offset();-- utc offset for specified timezone in seconds
 timestamp=utc_timestamp+utc_offset;-- make local time timestamp

 if'always'==DSTandis_set(tz.dst_abbr)then-- if needed to always display dst time
 timestamp=timestamp+3600;-- add a hour for dst
 tz_abbr=tz.dst_abbr;-- dst abbreviation
 elseifnotyesno(DST)andis_set(tz.dst_abbr)then-- for timezones that DO observe dst but for this location ...
 tz_abbr=tz.abbr;-- ... dst is not observed (|dst=no) show time as standard time
 else
 ifis_set(tz.dst_begins)andis_set(tz.dst_ends)andis_set(tz.dst_time)then-- make sure we have all of the parts
 dst_begin_ts,dst_end_ts,invert=make_dst_timestamps(timestamp);-- get begin and end dst timestamps and invert flag

 ifnil==dst_begin_tsornil==dst_end_tsthen
 returnerror_msg({'Time',cfg.err_text['bad_dst']});
 end

 ifinvertthen-- southern hemisphere; use beginning and ending of standard time in the comparison
 ifutc_timestamp>=dst_end_tsandutc_timestamp<dst_begin_tsthen-- is current date time standard time?
 tz_abbr=tz.abbr;-- standard time abbreviation
 else
 timestamp=timestamp+3600;-- add an hour
 tz_abbr=tz.dst_abbr;-- dst abbreviation
 end
 else-- northern hemisphere
 ifutc_timestamp>=dst_begin_tsandutc_timestamp<dst_end_tsthen-- all timestamps are UTC
 timestamp=timestamp+3600;-- add an hour 
 tz_abbr=tz.dst_abbr;
 else
 tz_abbr=tz.abbr;
 end
 end
 elseifis_set(tz.dst_begins)oris_set(tz.dst_ends)oris_set(tz.dst_time)then-- if some but not all not all parts then emit error message
 returnerror_msg({'Time',substitute(cfg.err_text['bad_def'],args_t[1]:upper())});
 else
 tz_abbr=tz.abbr;-- dst not observed for this timezone
 end
 end

 ifDateonlythen
 if'iso'==DFthen-- |df=iso
 DF='iso_date';
 elseifDF:find('^dmy')or'y'==DFthen-- |df=dmy, |df=dmy12, |df=dmy24, |df=y
 DF='dmy_date';
 else
 DF='mdy_date';-- default
 end

 elseifTimeonlyorDF:match('^%d+$')then-- time only of |df= is just digits
 DF=table.concat({'t',DF:match('%l*(12)')or'24'});-- |df=12, |df=24, |df=dmy12, |df=dmy24, |df=mdy12, |df=mdy24; default to t24

 elseif'y'==DFor'dmy24'==DFthen
 DF='dmy';

 elseif'mdy24'==DFthen
 DF='mdy';
 end

 localdformat;
 ifis_set(DF_cust)then
 dformat=DF_cust;
 elseifis_set(DF_cust_a)then-- custom format is am/pm sensitive?
 if'am'==os.date('%P',timestamp)then-- if current time is am
 dformat=DF_cust_a;-- use custom am format
 else
 dformat=DF_cust_p;-- use custom pm format
 end
 else
 dformat=cfg.format[DF];-- use format from tables or from |df=
 end

 time_string=frame:callParserFunction({name='#time',args={dformat,'@'..timestamp,Lang}});
 ifLangthen
 time_string=table.concat({-- bidirectional isolation of non-local language; yeah, rather brute force but simple
 '<bdi lang="',-- start of opening bdi tag
 Lang,-- insert rendered language code
 '">',-- end of opening tag
 time_string,-- insert the time string
 '</bdi>'-- and close the tag
 });
 end

 ifnotis_set(tz.article)then-- if some but not all not all parts then emit error message
 returnerror_msg({'Time',substitute(cfg.err_text['bad_def'],args_t[1]:upper())});
 end

 localrefresh_link=(Hide_refreshand'')or
 table.concat({
 ' <span class="plainlinks" style="font-size:85%;">[[',-- open span
 mw.title.getCurrentTitle():fullUrl({action='purge'}),-- add the a refresh link url
 ' ',
 cfg['refresh-label'],-- add the label
 ']]</span>',-- close the span
 });

 localtz_tag=(Hide_tzand'')or
 ((Unlink_tzandtable.concat({' ',tz_abbr}))or-- unlinked
 table.concat({' [[',tz.article,'|',tz_abbr,']]'}));-- linked

 returntable.concat({time_string,tz_tag,refresh_link});

 end


 --[[--------------------------< U T C _ O F F S E T >----------------------------------------------------------

 implements {{UTC offset}}

 mimics templates {{Time/GMT offset}}, {{Time/EST offset}}, etc.

 	{{#invoke:Time|utc_offset|<tz>}} – for a stand-alone invoke
 	{{#invoke:Time|utc_offset}} – for an invoke in a template (<tz> is first positional parameter in the template call)

 where <tz> is a timezone abbreviation known to Module:Time/data

 returns a UTC offset string suitable for use with the {{#time:}} parser function:
 	{{#time:H:i | {{#invoke:Time|utc_offset|MST}} }}
 	{{#time:H:i | {{UTC_offset|MST}} }}

 ]]

 localfunctionutc_offset(frame)
 localfunctionapply_dst_ajdust(offset)-- local function to adjust standard time to daylight time; called when adjustment is needed
 localhours,minutes=offset:match('^(%-?%d%d):(%d%d)');-- extract signed hours and minutes from specified offset
 returnstring.format('%s:%s',tonumber(hours)+1,minutes);-- return optional sign hh:mm string
 end

 localargs_t=getArgs(frame);-- fetch arguments; only {{{1}}}, timesone specifier is used

 ifnotargs_t[1]then-- no timezone specifier
 returnerror_msg({'UTC offset',cfg.err_text['missing_tz']});-- abandon with error message
 end

 localtimezone=args_t[1]:lower();-- lowercase for indexing into tz data tables
 timezone=data.tz_aliases[timezone]ortimezone;-- if <timezone> is an alias, map to its canonical value

 ifnotdata.tz_data[timezone]then-- timezone specifier not known
 returnerror_msg({'UTC offset',substitute(cfg.err_text['unknown_tz'],{timezone})});-- abandon with error message
 end

 tz=data.tz_aliases[timezone]anddata.tz_data[data.tz_aliases[timezone]]ordata.tz_data[timezone];-- fetch a copy of this timezone's data; <tz> is a page-global table used by functions called from this function
 localutc_timestamp=os.time();-- get current server time (UTC) in seconds; used to determine when dst adjustment should be applied

 localtimestamp=utc_timestamp+get_utc_offset();-- make local time timestamp (in seconds)
 localutc_offset;

 localDST=first_set(cfg.aliases['dst'],args_t)ortrue;-- string 'always' or boolean
 if'always'==DSTthen-- if needed to always display dst time
 utc_offset=apply_dst_ajdust(tz.utc_offset);-- return dst-adjusted timezone-offset from utc
 elseifnotyesno(DST)then-- for timezones that DO observe dst but for this location ...
 utc_offset=tz.utc_offset;-- ... dst is not observed (|dst=no) show time as standard time
 else
 ifis_set(tz.dst_begins)andis_set(tz.dst_ends)andis_set(tz.dst_time)then-- make sure we have all of the parts
 localdst_begin_ts,dst_end_ts,invert=make_dst_timestamps(timestamp);-- get begin and end dst timestamps and <invert> flag

 ifnil==dst_begin_tsornil==dst_end_tsthen-- if either of these are nil
 returnerror_msg({'UTC offset',cfg.err_text['bad_dst']});-- abandon with error message
 end

 ifinvertthen-- southern hemisphere; use beginning and ending of standard time in the comparison
 ifutc_timestamp>=dst_end_tsandutc_timestamp<dst_begin_tsthen-- is current date time standard time?
 utc_offset=tz.utc_offset;-- return timezone-offset from utc
 else
 utc_offset=apply_dst_ajdust(tz.utc_offset);-- return dst-adjusted timezone-offset from utc
 end
 else-- northern hemisphere
 ifutc_timestamp>=dst_begin_tsandutc_timestamp<dst_end_tsthen-- is current date time daylight time?
 utc_offset=apply_dst_ajdust(tz.utc_offset);-- return dst-adjusted timezone-offset from utc
 else
 utc_offset=tz.utc_offset;-- return timezone-offset from utc
 end
 end

 elseifis_set(tz.dst_begins)oris_set(tz.dst_ends)oris_set(tz.dst_time)then-- if some but not all not all parts then emit error message
 returnerror_msg({'UTC offset',substitute(cfg.err_text['bad_def'],args_t[1]:upper())});

 else-- timezone does not use dst
 utc_offset=tz.utc_offset;-- return timezone-offset from utc
 end
 end

 localsign,hours,minutes=utc_offset:match('^([%-%+]?)(%d%d?):(%d%d)')
 if''==signthen
 sign='+';
 end

 if0~=tonumber(minutes)then
 returnstring.format('%s%s %s %s%s minutes',sign,tonumber(hours),('1'==hours)and'hour'or'hours',sign,tonumber(minutes));
 else
 returnstring.format('%s%s %s',sign,tonumber(hours),('1'==hours)and'hour'or'hours');
 end
 end


 --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
 ]]

 return{
 time=time,
 utc_offset=utc_offset,
 }

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