ACC SHELL
/**
* File: modules/Timezone.ycp
* Package: Country settings
* Summary: Timezone related stuff
* Authors: Klaus Kaempf <kkaempf@suse.de>
* Thomas Roelz <tom@suse.de>
*
* $Id: Timezone.ycp 62459 2010-08-31 09:54:14Z jsuchome $
*/
{
module "Timezone";
textdomain "country";
import "Arch";
import "Language";
import "Misc";
import "Mode";
import "Stage";
import "String";
import "ProductFeatures";
// --------------------------------------------------------------
// START: Globally defined data to be accessed via Timezone::<variable>
// --------------------------------------------------------------
global string timezone = ""; // e.g. "Europe/Berlin"
// hwclock parameter
// possible values:
// "" dont change timezone
// "-u" system clock runs UTC
// "--localtime" system clock runs localtime
global string hwclock = "";
// The default timezone if set.
//
global string default_timezone = "";
// Flag indicating if the user has chosen a timezone.
// To be set from outside.
//
global boolean user_decision = false;
global boolean user_hwclock = false;
// If NTP is configured
global boolean ntp_used = false;
global integer diff = 0;
/**
* if anyuthing was modified (currently for auto client only)
*/
global boolean modified = false;
/**
* If there is windows partition, assume that local time is used
*/
global boolean windows_partition = false;
// if mkinitrd should be called at the end
global boolean call_mkinitrd = false;
// translation of correct timezone to the one that could be shown in map widget
global map <string,string> yast2zonetab = $[
"Mideast/Riyadh87" : "Asia/Riyadh",
"Mideast/Riyadh88" : "Asia/Riyadh",
"Mideast/Riyadh89" : "Asia/Riyadh",
];
// on init, translate these to correct ones
global map<string,string> obsoleted_zones = $[
"Iceland" : "Atlantic/Reykjavik",
"Europe/Belfast" : "Europe/London",
"Australia/South" : "Australia/Adelaide",
"Australia/North" : "Australia/Darwin",
"Australia/NSW" : "Australia/Sydney",
"Australia/ACT" : "Australia/Canberra",
"Australia/Queensland" : "Australia/Brisbane",
"Australia/Tasmania" : "Australia/Hobart",
"Australia/Victoria" : "Australia/Melbourne",
"Australia/West" : "Australia/Perth",
"US/Alaska" : "America/Anchorage",
"US/Aleutian" : "America/Adak",
"US/Arizona" : "America/Phoenix",
"US/Central" : "America/Chicago",
"US/East-Indiana" : "America/Indiana/Indianapolis",
"US/Hawaii" : "Pacific/Honolulu",
"US/Indiana-Starke" : "America/Indiana/Knox",
"US/Michigan" : "America/Detroit",
"US/Mountain" : "America/Denver",
"US/Pacific" : "America/Los_Angeles",
"US/Samoa" : "Pacific/Pago_Pago",
"US/Eastern" : "America/New_York",
"Canada/Atlantic" : "America/Halifax",
"Canada/Central" : "America/Winnipeg",
"Canada/Eastern" : "America/Toronto",
"Canada/Saskatchewan" : "America/Regina",
"Canada/East-Saskatchewan" : "America/Regina",
"Canada/Mountain" : "America/Edmonton",
"Canada/Newfoundland" : "America/St_Johns",
"Canada/Pacific" : "America/Vancouver",
"Canada/Yukon" : "America/Whitehorse",
"America/Buenos_Aires" : "America/Argentina/Buenos_Aires",
"America/Virgin" : "America/St_Thomas",
"Brazil/Acre" : "America/Rio_Branco",
"Brazil/East" : "America/Sao_Paulo",
"Brazil/West" : "America/Manaus",
"Chile/Continental" : "America/Santiago",
"Chile/EasterIsland" : "Pacific/Easter",
"Mexico/BajaNorte" : "America/Tijuana",
"Mexico/BajaSur" : "America/Mazatlan",
"Mexico/General" : "America/Mexico_City",
"Jamaica" : "America/Jamaica",
"Asia/Macao" : "Asia/Macau",
"Israel" : "Asia/Jerusalem",
"Asia/Tel_Aviv" : "Asia/Jerusalem",
"Hongkong" : "Asia/Hong_Kong",
"Japan" : "Asia/Tokyo",
"ROK" : "Asia/Seoul",
"Africa/Timbuktu" : "Africa/Bamako",
"Egypt" : "Africa/Cairo",
];
// ------------------------------------------------------------------
// END: Globally defined data to be accessed via Timezone::<variable>
// ------------------------------------------------------------------
// ------------------------------------------------------------------
// START: Locally defined data
// ------------------------------------------------------------------
// internal map used to store initial data
map push = $[];
string name = "";
// list with maps, each map provides time zone information about one region
list < map < string, any> > zonemap = [];
// 'language --> default timezone' conversion map
map<string, string> lang2tz = $[];
// remember if /sbin/hwclock --hctosys was called, it can be done only once (bnc#584484)
boolean systz_called = false;
// ------------------------------------------------------------------
// END: Locally defined data
// ------------------------------------------------------------------
// -----------------------------------------------------------------------------
// START: Globally defined functions
// -----------------------------------------------------------------------------
/**
* get_lang2tz()
*
* Get the language --> timezone conversion map.
*
* @return conversion map
*
* @see get_zonemap()
*/
define map<string, string> get_lang2tz () {
if (size (lang2tz) == 0)
{
map base_lang2tz = (map) SCR::Read (.target.yast2, "lang2tz.ycp");
if (base_lang2tz == nil) base_lang2tz = $[];
lang2tz = (map<string,string>) union (
base_lang2tz,
Language::GetLang2TimezoneMap (true)
);
}
return lang2tz;
}
/**
* get_zonemap()
*
* Get the timezone database.
*
* @return timezone DB (map)
*
* @see get_lang2tz()
*/
global define list<map<string,any> > get_zonemap() {
if (size(zonemap) == 0)
{
list<map<string,any> > zmap = (list<map<string,any> >)
eval (SCR::Read (.target.yast2, "timezone_raw.ycp"));
if (zmap == nil) zmap = [];
zonemap = sort (map<string,any> a, map<string,any> b, zmap, {
// [ "USA", "Canada" ] -> [ "Canada", "USA" ]
// bnc#385172: must use < instead of <=, the following means:
// strcoll(x) <= strcoll(y) && strcoll(x) != strcoll(y)
list lsorted = lsort ([a["name"]:"", b["name"]:""]);
list lsorted_r = lsort ([b["name"]:"", a["name"]:""]);
return lsorted[0]:"" == a["name"]:"" && lsorted == lsorted_r;
});
}
return zonemap;
}
// ------------------------------------------------------------------
// END: Locally defined functions
// ------------------------------------------------------------------
/**
* Set()
*
* Set system to selected timezone.
*
* @param string timezone to select, e.g. "Europe/Berlin"
*
* @return the number of the region that contains the timezone
*
*/
global define integer Set (string zone, boolean really) {
list <map <string, any> > zmap = get_zonemap();
// Set the new timezone internally
timezone = zone;
integer sel = 0;
while (sel<size (zmap) && !haskey (zmap[sel,"entries"]:$[], zone))
{
sel = sel + 1;
}
name = zmap [sel,"name"]:"" + " / " + zmap[sel,"entries",zone]:zone;
// Adjust system to the new timezone.
//
if (!Mode::config () && really )
{
boolean textmode = Language::GetTextMode ();
// turn off the screensaver when clock can change radically (bnc#455771)
// (in non-firstboot cases, installation process handles it)
if (Stage::firstboot() && !textmode)
{
SCR::Execute ( .target.bash, "/usr/bin/xset -dpms");
SCR::Execute ( .target.bash, "/usr/bin/xset s reset");
SCR::Execute ( .target.bash, "/usr/bin/xset s off");
}
string cmd = "/usr/sbin/zic -l " + timezone;
y2milestone( "Set cmd %1", cmd );
y2milestone( "Set ret %1", SCR::Execute( .target.bash_output, cmd ));
if (!Arch::s390 ())
{
cmd = "/sbin/hwclock --hctosys " + hwclock;
if (Stage::initial () && hwclock == "--localtime")
{
if (!systz_called)
{
cmd = "/sbin/hwclock --systz --localtime --noadjfile && touch /dev/shm/warpclock";
systz_called = true;
}
}
y2milestone( "Set cmd %1", cmd );
y2milestone( "Set ret %1", SCR::Execute(.target.bash_output, cmd ));
}
if (Stage::firstboot() && !textmode)
{
SCR::Execute (.target.bash, "/usr/bin/xset s on");
SCR::Execute ( .target.bash, "/usr/bin/xset +dpms");
}
}
// On first assignment store default timezone.
//
if (default_timezone == "")
{
default_timezone = timezone;
y2milestone( "Set default timezone: <%1>", timezone );
}
y2milestone( "Set timezone:%1 sel:%2 name:%3", timezone, sel, name );
return sel;
}
/**
* Convert the duplicated timezone to the only one supported
* Temporary solution - a result of discussion of bug #47472
* @param tmz current timezone
*/
global define string UpdateTimezone (string tmz) {
string updated_tmz = tmz;
if (haskey (obsoleted_zones, tmz))
{
updated_tmz = obsoleted_zones[tmz]:tmz;
y2milestone ("updating timezone from %1 to %2", tmz, updated_tmz);
}
return updated_tmz;
}
/**
* Read timezone settings from sysconfig
*/
global define void Read () {
hwclock = Misc::SysconfigRead(.sysconfig.clock.HWCLOCK, hwclock);
timezone = Misc::SysconfigRead (.sysconfig.clock.TIMEZONE, timezone);
default_timezone =
Misc::SysconfigRead(.sysconfig.clock.DEFAULT_TIMEZONE, default_timezone);
// get name for cloning purposes
if (Mode::config ())
{
list <map <string, any> > zmap = get_zonemap();
integer sel = 0;
while (sel<size (zmap) && !haskey (zmap[sel,"entries"]:$[], timezone))
{
sel = sel + 1;
}
name = zmap [sel,"name"]:"" + " / " + zmap[sel,"entries",timezone]:timezone;
}
}
/**
* Timezone()
*
* The module constructor.
* Sets the proprietary module data defined globally for public access.
* This is done only once (and automatically) when the module is loaded for the first time.
* Calls Set() in initial mode.
* Reads current timezone from sysconfig in normal mode.
*
* @see Set()
*/
global define void Timezone() {
// Set default values.
//
hwclock = "-u";
if (Stage::initial () && !Mode::live_installation ())
{
// language --> timezone database, e.g. "de_DE" : "Europe/Berlin"
map<string, string> lang2tz = get_lang2tz();
string new_timezone = lang2tz[Language::language]:"";
y2milestone( "Timezone new_timezone %1", new_timezone );
if (new_timezone != "")
{
Set (new_timezone, true);
}
}
else if (!Mode::config ())
{
Read ();
}
return;
}
global boolean CallMkinitrd () {
y2milestone ("calling mkinitrd...");
SCR::Execute (.target.bash, "/sbin/mkinitrd >> /var/log/YaST2/y2logmkinitrd 2>> /var/log/YaST2/y2logmkinitrd");
y2milestone ("... done");
return true;
}
/**
* Set the new time and date given by user
*/
global define void SetTime (string year, string month, string day,
string hour, string minute, string second ) {
if (!Arch::s390 ())
{
string date = sformat( " --date=\"%1/%2/%3 %4:%5:%6\" ", month, day,
year, hour, minute, second );
string cmd = "";
if (size (timezone) >0 && hwclock != "--localtime")
{
cmd = "TZ=" + timezone + " ";
}
cmd = cmd + "/sbin/hwclock --set " + hwclock + date;
y2milestone( "SetTime cmd %1", cmd );
SCR::Execute(.target.bash, cmd );
cmd = "/sbin/hwclock --hctosys " + hwclock;
y2milestone( "SetTime cmd %1", cmd );
SCR::Execute(.target.bash, cmd );
// actually, it was probably not called, but do not let it change the time again after manual change
systz_called = true;
}
};
/**
* Set the Hardware Clock to the current System Time.
*/
global define void SystemTime2HWClock () {
if (!Arch::s390 ())
{
string cmd = "";
if (size (timezone) >0 && hwclock != "--localtime")
{
cmd = "TZ=" + timezone + " ";
}
cmd = "/sbin/hwclock --systohc " + hwclock;
y2milestone ("cmd %1", cmd);
SCR::Execute(.target.bash, cmd);
}
}
/**
* GetTimezoneForLanguage()
*
* Get the timezone for the given system language.
*
* @param System language code, e.g. "en_US".
* Default timezone to be returned if nothing found.
*
* @return The timezone for this language, e.g. "US/Eastern"
* or the default value if nothing found.
*
* @see -
*/
global define string GetTimezoneForLanguage (string sys_language,
string default_timezone)
{
// The system_language --> timezone conversion map.
//
map<string, string> lang2timezone = get_lang2tz();
string ret = lang2timezone[sys_language]:default_timezone;
y2milestone ("language %1 default timezone %2 returned timezone %3",
sys_language, default_timezone, ret);
return ret;
}
/**
* Set the timezone for the given system language.
* @param System language code, e.g. "en_US".
* @return the number of the region that contains the timezone
*/
global define void SetTimezoneForLanguage (string sys_language) {
string tmz = GetTimezoneForLanguage (sys_language, "US/Eastern");
y2debug ("language %1 proposed timezone %2", sys_language, tmz);
if (tmz != "")
{
Set (tmz, true);
}
}
/**
* Return the language code for given timezone (by reverse searching the
* "language -> timezone" map)
* @param timezone, if empty the current one is used
*/
global define string GetLanguageForTimezone (string tz)
{
if (tz == "" || tz == nil)
tz = timezone;
string lang = "";
foreach (string code, string tmz, get_lang2tz(), {
if (tmz == tz && (lang == "" || !issubstring (lang, "_")))
lang = code;
});
return lang;
}
/**
* Return the country part of language code for given timezone
* @param timezone, if empty the current one is used
*/
global define string GetCountryForTimezone (string tz)
{
return Language::GetGivenLanguageCountry (GetLanguageForTimezone(tz));
}
/**
* Return translated country name of given timezone
* @param timezone value (as saved in sysconfig/clock)
*/
global define string GetTimezoneCountry (string zone) {
list zmap = (list) eval (SCR::Read (.target.yast2, "timezone_raw.ycp"));
integer sel = 0;
while (sel<size (zmap) && !haskey (zmap[sel,"entries"]:$[], zone))
{
sel = sel + 1;
}
return zmap [sel,"name"]:"" + " / " + zmap[sel,"entries",zone]:zone;
}
/**
* GetDateTime()
*
* Get the output of date "+%H:%M:%S - %Y-%m-%d" or in locale defined format
*
* @param flag if to get real system time or if to simulate changed
* timezone settings with TZ=
* @param if the date and time should be returned in locale defined format
*
* @return The string output.
*
*/
global define string GetDateTime (boolean real_time, boolean locale_format) {
string cmd = "";
string date_format = (locale_format && Mode::normal ())
? "+%c" : "+%Y-%m-%d - %H:%M:%S";
y2milestone( "GetDateTime hwclock %1 real:%2", hwclock, real_time );
if (!real_time && !Mode::config ())
{
integer ds = 0;
if (diff!=0)
{
map out = (map) SCR::Execute (.target.bash_output, "date +%z");
string tzd = out["stdout"]:"";
y2milestone( "GetDateTime tcd=%1", tzd );
integer t = tointeger( String::CutZeros( substring( tzd, 1, 2 )));
if (t != nil)
{
ds = ds + t * 3600;
t = tointeger( String::CutZeros( substring( tzd, 3, 2 )));
ds = ds + t * 60;
if (substring (tzd, 0, 1) == "-")
ds = -ds;
y2milestone( "GetDateTime ds %1 diff %2", ds, diff );
}
}
cmd = "";
if (hwclock != "--localtime")
{
cmd = sformat( "TZ=%1 ", timezone );
}
cmd = cmd + sformat( "/bin/date \"%1\" \"--date=now %2sec\"",
date_format, ds*diff );
}
else
{
cmd = sformat( "/bin/date \"%1\"", date_format );
}
y2milestone( "GetDateTime cmd=%1", cmd );
map out = (map) SCR::Execute (.target.bash_output, cmd);
string local_date = deletechars (out["stdout"]:"", "\n");
y2milestone( "GetDateTime local_date='%1'", local_date );
return( local_date );
}
/**
* Clear the internal map with timezones, so the timezone data could be
* retranslated next time when they are needed
*/
global define void ResetZonemap() {
zonemap = [];
}
/**
* Return true if localtime should be proposed as default
* Based on current hardware configuration:
* Win partitions present or 32bit Mac
*/
global define boolean ProposeLocaltime () {
return windows_partition || (Arch::board_mac() && Arch::ppc32());
}
/**
* Return proposal list of strings.
*
* @param boolean force_reset
* boolean language_changed
*
* @return list user readable description.
*
* If force_reset is true reset the module to the timezone
* stored in default_timezone.
*/
global define list<string> MakeProposal (boolean force_reset,
boolean language_changed )
{
y2milestone ("force_reset: %1", force_reset);
y2milestone ("language_changed: %1 user_decision %2 user_hwclock %3",
language_changed, user_decision, user_hwclock);
if (language_changed)
ResetZonemap();
if (!user_hwclock || force_reset)
{
hwclock = "-u";
if (ProposeLocaltime ())
{
hwclock = "--localtime";
}
}
if (force_reset)
{
// If user wants to reset do it if a default is available.
//
if( default_timezone != "" )
{
Set( default_timezone, true ); // reset
}
// Reset user_decision flag.
//
user_decision = false;
}
else // no reset
{
// Only follow the language if the user has never actively chosen
// a timezone. The indicator for this is user_decision which is
// set from outside the module.
//
if (user_decision || Mode::autoinst () ||
ProductFeatures::GetStringFeature ("globals", "timezone") != "")
{
if( language_changed )
{
y2milestone("User has chosen a timezone; not following language - only retranslation.");
Set( timezone, true );
}
}
else
{
// User has not yet chosen a timezone ==> follow language.
//
string local_timezone =
GetTimezoneForLanguage( Language::language, "US/Eastern");
if( local_timezone != "" )
{
Set( local_timezone, true );
default_timezone = local_timezone;
}
else
{
if( language_changed )
{
y2error("Can't follow language - only retranslation");
Set( timezone, true );
}
}
}
}
// label text (Clock setting)
string clock_setting = _("UTC");
if (hwclock == "--localtime")
// label text, Clock setting: local time (not UTC)
clock_setting = _("Local Time");
// label text
clock_setting = _("Hardware Clock Set To") + " " + clock_setting;
string date = GetDateTime (true, true);
y2milestone( "MakeProposal hwclock %1", hwclock );
list<string> ret = [ name + " - " + clock_setting + " " + date ];
if (ntp_used)
// summary label
ret = add (ret, _("NTP configured"));
return ret;
}
/**
* Selection()
*
* Return a map of ids and names to build up a selection list
* for the user. The key is used later in the Set function
* to select this timezone. The name is a translated string.
*
* @param -
*
* @return map map for timezones
* 'timezone_id' is used internally in Set and Probe
* functions. 'timezone_name' is a user-readable string.
* Uses Language::language for translation.
* @see Set()
*/
global define list Selection (integer num) {
list<map<string,any> > zmap = get_zonemap();
list<list<string> > trl = maplist (
string key, string name, zmap[num,"entries"]:$[], ``([ name, key ]));
trl = sort (list<string> a, list<string> b, trl, {
// bnc#385172: must use < instead of <=, the following means:
// strcoll(x) <= strcoll(y) && strcoll(x) != strcoll(y)
list lsorted = lsort ([a[0]:"", b[0]:""]);
list lsorted_r = lsort ([b[0]:"", a[0]:""]);
return (lsorted[0]:"" == a[0]:"" && lsorted == lsorted_r);
});
y2debug ("trl = %1", trl);
return maplist (list e, trl, ``(`item (`id(e[1]:""), e[0]:"", false)));
}
/**
* Return list of regions for timezone selection list
*/
global define list Region() {
integer num = -1;
return maplist (map entry, get_zonemap (), {
num = num + 1;
return (`item (`id(num), entry["name"]:"", false ));
});
}
/**
* Save()
*
* Save timezone to target sysconfig.
*/
global define void Save() {
if ( Mode::update () )
{
return;
}
SCR::Write(.sysconfig.clock.TIMEZONE, timezone);
SCR::Write(.sysconfig.clock.DEFAULT_TIMEZONE, default_timezone);
SCR::Write(.sysconfig.clock.HWCLOCK, hwclock);
SCR::Write(.sysconfig.clock, nil); // flush
y2milestone( "Save Saved data for timezone: <%1>", timezone );
if (call_mkinitrd && !Stage::initial ())
{
CallMkinitrd ();
}
return;
}
/**
* Return current date and time in the map
*/
global define map GetDateTimeMap() {
map ret = $[];
list dparts = filter (
string v,splitstring (GetDateTime (false,false), " -:" ),``(size(v)>0));
ret["year"] = dparts[0]:"";
ret["month"] = dparts[1]:"";
ret["day"] = dparts[2]:"";
ret["hour"] = dparts[3]:"";
ret["minute"] = dparts[4]:"";
ret["second"] = dparts[5]:"";
y2milestone( "GetDateTimeMap dparts %1 ret %2", dparts, ret );
return( ret );
}
global define boolean CheckTime( string hour, string minute, string second )
``{
boolean ret = true;
integer tmp = tointeger( String::CutZeros(hour) );
if (tmp == nil) return false;
ret = ret && tmp>=0 && tmp<24;
tmp = tointeger( String::CutZeros(minute) );
if (tmp == nil) return false;
ret = ret && tmp>=0 && tmp<60;
tmp = tointeger( String::CutZeros(second) );
if (tmp == nil) return false;
ret = ret && tmp>=0 && tmp<60;
return( ret );
}
global define boolean CheckDate( string day, string month, string year )
``{
list mdays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
boolean ret = true;
integer yea = tointeger( String::CutZeros(year) );
integer mon = tointeger( String::CutZeros(month) );
integer da = tointeger( String::CutZeros(day) );
if (yea == nil || mon == nil || da == nil)
return false;
ret = ret && mon>=1 && mon<=12;
if( yea%4==0 && (yea%100!=0 || yea%400==0))
{
mdays[1] = 29;
}
ret = ret && da>=1 && da<=mdays[mon-1]:0;
ret = ret && yea>=1970 && yea<2032;
return( ret );
}
// does the hwclock run on UTC only ? -> skip asking
global define boolean utc_only () {
y2milestone( "Arch::sparc () %1 Arch::board_iseries () %2 Arch::board_chrp () %3 Arch::board_prep () %4", Arch::sparc (), Arch::board_iseries (), Arch::board_chrp (), Arch::board_prep () );
return (Arch::sparc () || Arch::board_iseries () ||
Arch::board_chrp () || Arch::board_prep ());
}
/**
* save the initial data
*/
global define void PushVal () {
push = $[ "hwclock" : hwclock, "timezone" : timezone ];
y2milestone ( "PushVal map %1", push );
}
/**
* restore the original data from internal map
*/
global define void PopVal() {
y2milestone ("before Pop: timezone %1 hwclock %2", timezone, hwclock );
if ( haskey( push, "hwclock" ))
hwclock = push["hwclock"]:hwclock;
if( haskey( push, "timezone" ))
timezone = push["timezone"]:timezone;
push = $[];
y2milestone ("after Pop: timezone %1 hwclock %2", timezone, hwclock );
}
/**
* was anything modified?
*/
global define boolean Modified () {
return modified ||
timezone != push["timezone"]:timezone || hwclock != push["hwclock"]:hwclock;
}
/**
* AutoYaST interface function: Get the Timezone configuration from a map.
* @param settings imported map
* @return success
*/
global define boolean Import (map settings) {
// Read was not called -> do the init
if (push == $[])
PushVal ();
if (haskey (settings, "hwclock"))
{
hwclock = settings["hwclock"]:"UTC" == "UTC" ? "-u" : "--localtime";
user_hwclock = true;
}
Set (settings["timezone"]:timezone, true);
return true;
}
/**
* AutoYaST interface function: Return the Timezone configuration as a map.
* @return map with the settings
*/
global define map Export () {
map ret = $[
"timezone" : timezone,
"hwclock" : hwclock == "-u" ? "UTC" : "localtime",
];
return ret;
}
/**
* AutoYaST interface function: Return the summary of Timezone configuration as a map.
* @return summary string (html)
*/
global define string Summary () {
import "HTML";
string clock_setting = _("UTC");
if (hwclock == "--localtime")
// label text, Clock setting: local time (not UTC)
clock_setting = _("Local Time");
// label text
clock_setting = _("Hardware Clock Set To") + " " + clock_setting;
list<string> ret = [
// summary label
sformat (_("Current Time Zone: %1"), name),
clock_setting
];
return HTML::List (ret);
}
} // -EOF-
ACC SHELL 2018