daytime.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 
------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand        --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute  and/or modify it under the terms of the GNU Library General --
-- Public  License (LGPL)  as published  by the  Free  Software  Foundation; --
-- either version 2 of the license, or (at your option) any later version.   --
-- This  library  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details.       --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------


immutable class CAL_DISPLAY_ORDERS < $ENUMS{CAL_DISPLAY_ORDERS}

immutable class CAL_DISPLAY_ORDERS < $ENUMS{CAL_DISPLAY_ORDERS} is -- This class captures the notion of a suffix appended to a time to -- indicate what kind of time -- morning or afternoon it is. -- The corresponding strings are captured from the locale spec. -- Version 1.0 Jun 97. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 8 Jun 97 kh Original from ISO/IEC 14652 include EXACT_ENUM{CAL_DISPLAY_ORDERS} ; private const val_count : CARD := 4 ; -- The following constant 'routines' specify the enumeration values. LR_TD : SAME is return enum(1) end ; TD_LR : SAME is return enum(2) end ; RL_TD : SAME is return enum(3) end ; TD_RL : SAME is return enum(4) end ; end ; -- CAL_DISPLAY_ORDERS

immutable class TIME_SUFFIX < $ENUMS{TIME_SUFFIX}

immutable class TIME_SUFFIX < $ENUMS{TIME_SUFFIX} is -- This class captures the notion of a suffix appended to a time to -- indicate what kind of time -- morning or afternoon it is. -- The corresponding strings are captured from the locale spec. -- Version 1.0 Jun 97. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 8 Jun 97 kh Original from ISO/IEC 14652 include EXACT_ENUM{TIME_SUFFIX} ; private const val_count : CARD := 2 ; -- The following constant 'routines' specify the enumeration values. Morning : SAME is return enum(1) end ; Afternoon : SAME is return enum(2) end ; end ; -- TIME_SUFFIX

immutable class DT_CODES < $ENUMS{DT_CODES}

immutable class DT_CODES < $ENUMS{DT_CODES} is -- This class is an enumeration of all the date and time component -- format values which are defined in the LC_TIME component of the POSIX -- standard ISO/IEC 9945-2. Note that these are NOT culture-dependent -- but ARE character encoding dependent! -- -- The corresponding names in the common resources file -- should be the ISO/IEC 9945-2 names specified for the indicated formats. -- Note that these will be encoding dependent by the very bature or -- the existence of that file produced on the computer system reading it. -- -- The table in ISO/IEC 14652 gives the text string format codes and -- a description of the semantics to be ascribed to that code in a date/time -- formatting class. The prefix letters for some of these codes have the -- following meanings -- -- O - A numeric representation using non-Arabic glyphs -- May apply to - d, e, H, I, m, M, U, w, W, y -- -- E - A year property based on a non-Gregorian calendar base -- May apply to - c, C, x, y, Y -- -- Version 1.0 May 97. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 8 May 97 kh Original from ISO/IEC 14652 include EXACT_ENUM{DT_CODES} ; private const val_count : CARD := 34 ; -- The following constant 'routines' specify the enumeration values. ADay_Name : SAME is return enum(1) end ; -- a Day_Name : SAME is return enum(2) end ; -- A AMonth_Name : SAME is return enum(3) end ; -- b Month_Name : SAME is return enum(4) end ; -- B Full_DT : SAME is return enum(5) end ; -- c Century : SAME is return enum(6) end ; -- C Month_Day : SAME is return enum(7) end ; -- d Numeric_Date : SAME is return enum(8) end ; -- D Filled_Month_Day : SAME is return enum(9) end ; -- e Weekday_Num : SAME is return enum(10) end ; -- f ISO_Date : SAME is return enum(11) end ; -- F Alt_AMonth_Name : SAME is return enum(12) end ; -- h Hour : SAME is return enum(13) end ; -- H Rel_Hour : SAME is return enum(14) end ; -- I Year_Day : SAME is return enum(15) end ; -- j Year_Month : SAME is return enum(16) end ; -- m Minutes : SAME is return enum(17) end ; -- M New_Line : SAME is return enum(18) end ; -- n Am_Pm : SAME is return enum(19) end ; -- p Rel_Time : SAME is return enum(20) end ; -- r Seconds : SAME is return enum(21) end ; -- S Tab : SAME is return enum(22) end ; -- t Time : SAME is return enum(23) end ; -- T Year_Sun_Week : SAME is return enum(24) end ; -- U Week_Day : SAME is return enum(25) end ; -- w Year_Mon_Week : SAME is return enum(26) end ; -- W Local_Date : SAME is return enum(27) end ; -- x Local_Time : SAME is return enum(28) end ; -- X Century_Year : SAME is return enum(29) end ; -- y Year : SAME is return enum(30) end ; -- Y Time_Zone : SAME is return enum(31) end ; -- Z Percent : SAME is return enum(32) end ; -- % Era_Prefix : SAME is return enum(33) end ; -- E Alternate_Prefix : SAME is return enum(34) end ; -- O end ; -- DT_CODES

class DT_FMT < $BINARY

class DT_FMT < $BINARY is -- This class is the descriptor to be used when converting and -- formatting a date and/or a time value to a textual representation. -- The format descriptor provides for an optional prefix string and then -- pairs of component/string pairs for as many components as needed. Any of -- the 'component' strings may be empty where two or more value components -- are to be formatted adjacent to each other (without any space!). -- Version 1.2 Nov 99. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 22 May 97 kh Original design using ISO/IEC 14652 spec. -- 22 Jul 98 kh Updated ISO standard and added $BINARY -- 5 Nov 99 kh Made ISO I/O generic. include ISO_FORMAT{SAME,DT_CODES} ; private const Decimal_Chars : CARD := 10 ; private us_date pre ~ void(self) post ((initial(modifiers.size) + 3) = modifiers.size) and (modifiers.size = components.size) and (separators.size + 1 = components.size) is -- This routine transforms a single format code into its individual -- components for the US date kind of component. sep : CODE_STR := CODE_STR::create(lib.Solidus) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Year_Month) ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Month_Day) ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Century_Year) end ; private iso_date pre ~ void(self) and ~void(lib) post ((initial(modifiers.size) + 3) = modifiers.size) and (modifiers.size = components.size) and (separators.size + 1 = components.size) is -- This routine transforms a single format code into its individual -- components for the date kind of component as defined in ISO 8601. sep : CODE_STR := CODE_STR::create(lib.Minus_Sign) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Year) ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Year_Month) ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Month_Day) end ; private iso_time( relative : BOOL ) pre ~ void(self) and ~void(lib) post ((relative and ((initial(modifiers.size) + 4) = modifiers.size))) or (~relative and ((initial(modifiers.size) + 3) = modifiers.size) and (modifiers.size = components.size) and ((separators.size + 1) = components.size)) is -- This routine transforms a single format code into its individual -- components for the international standard time component. sep : CODE_STR := CODE_STR::create(lib.Colon) ; modifiers := modifiers.push(void) ; if relative then components := components.push(DT_CODES::Rel_Hour) else components := components.push(DT_CODES::Hour) end ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Minutes) ; separators := separators.push(sep) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Seconds) ; if relative then loc_space : CODE_STR := CODE_STR::create(lib.Space) ; separators := separators.push(loc_space) ; modifiers := modifiers.push(void) ; components := components.push(DT_CODES::Am_Pm) end end ; private do_special( code : DT_CODES, inout sep_str : CODE_STR, out modifier : DT_CODES, inout pushed : BOOL ) : BOOL is -- This routine returns true if and only if the code argument has resulted -- in any special action being taken, otherwise nothing has been done and -- the creation routine below sets the appropriate list components. modifier := void ; -- usually! case code when DT_CODES::Alternate_Prefix, DT_CODES::Era_Prefix then modifier := code ; when DT_CODES::Numeric_Date then if pushed then separators := separators.push(sep_str) ; sep_str := CODE_STR::create(lib) end ; us_date ; pushed := true when DT_CODES::ISO_Date then if pushed then separators := separators.push(sep_str) ; sep_str := CODE_STR::create(lib) end ; iso_date ; pushed := true when DT_CODES::Local_Time, DT_CODES::Rel_Time, DT_CODES::Time then if pushed then separators := separators.push(sep_str) ; sep_str := CODE_STR::create(lib) end ; iso_time(code = DT_CODES::Rel_Time) ; pushed := true when DT_CODES::Tab then sep_str := sep_str.push(CHAR_CODE::create( CONTROL_CODES::HORIZONTAL_TAB.card,lib)) when DT_CODES::New_Line then sep_str := sep_str + lib.Line_Mark else -- an ordinary formatting code! return false end ; return true end ; private do_number( num : CARD, min_width : CARD, lib : LIBCHARS, alternate : BOOL, zero_fill : BOOL ) : CODE_STR pre ~void(self) and ~void(lib) and (min_width > 0) post (result.size >= min_width) is -- This private routine converts a number to the appropriate -- representation. If alternate is true then the characters come from -- the cultural alternate digits, otherwise arabic digits. If zero_fill -- is false then space-filling is done. digit_cnt : CARD := Decimal_Chars ; -- default of ten! filler : CHAR_CODE ; cnt : CARD := min_width ; val : CARD := num ; res : CODE_STR := CODE_STR::create(lib) ; if alternate then digit_cnt := lib.alt_digits end ; if zero_fill then if alternate then filler := lib.alt_digit(0)[0].code else filler := lib.digit(0) end else filler := lib.Space end ; if num >= digit_cnt then if (digit_cnt > Decimal_Chars) then -- but is it 100? if digit_cnt < 100 then -- use decimal placing digit_cnt := 10 end end end ; loop -- the digit string itself if alternate then res := res + lib.alt_digit(val % digit_cnt)[0].code else res := res + lib.digit(val % digit_cnt) end ; val := val / digit_cnt ; if cnt > 0 then -- still less than given min width! cnt := cnt - 1 end ; until!(val = 0) end ; loop -- the fillers (cnt / filler.lib.my_size).times! ; res := res + filler end ; return res.reverse end ; private do_format( date : DATES, time : TIMES, lib : LIBCHARS ) : CODE_STR pre ~void(self) and ~void(lib) post ~void(result) -- and it is a valid date representation! is -- This private routine does formatting for all of the variant routines -- which follow. Fundamentally it merely loops through all of the -- components adding to the output string the relevant item and separator. res : CODE_STR := CODE_STR::create(lib) ; loop modified : BOOL := ~modifiers.elt!.is_nil ; loc_code : DT_CODES := components.elt! ; case loc_code when DT_CODES::ADay_Name then res := res + CODE_STR::create(date.weekday.short_str) when DT_CODES::Day_Name then res := res + CODE_STR::create(date.weekday.str) when DT_CODES::AMonth_Name then res := res + CODE_STR::create(date.month.short_str) when DT_CODES::Month_Name then res := res + CODE_STR::create(date.month.str) -- when DT_CODES::Full_DT then -- also Ec ????? when DT_CODES::Century then --NOTE In future has two digits! res := res + do_number(date.century,2,lib,modified,true) when DT_CODES::Month_Day then res := res + do_number(date.date,1,lib,modified,true) -- when DT_CODES::Numeric_Date then -- Handled during building when DT_CODES::Filled_Month_Day then res := res + do_number(date.date,2,lib,modified,false) when DT_CODES::Weekday_Num then res := res + do_number(date.day_of_week,1,lib,modified,false) -- when DT_CODES::ISO_Date then -- Handled during building when DT_CODES::Alt_AMonth_Name then res := res + CODE_STR::create(date.month.short_str) when DT_CODES::Hour then res := res + do_number(time.hour,2,lib,modified,true) when DT_CODES::Rel_Hour then loc_hour : CARD := time.hour ; if loc_hour > 12 then loc_hour := loc_hour - 12 end ; res := res + do_number(loc_hour,2,lib,modified,false) when DT_CODES::Year_Day then res := res + do_number(date.day_in_year,3,lib,modified,true) when DT_CODES::Year_Month then res := res + do_number(date.month_number,2,lib,modified,true) when DT_CODES::Minutes then res := res + do_number(time.minute,2,lib,modified,true) when DT_CODES::New_Line then res := res + lib.Line_Mark when DT_CODES::Am_Pm then if time.hour >= 12 then res := res + CODE_STR::create(TIME_SUFFIX::Afternoon.str) else res := res + CODE_STR::create(TIME_SUFFIX::Morning.str) end -- when DT_CODES::Rel_Time then -- Handled during building when DT_CODES::Seconds then res := res + do_number(time.second,2,lib,modified,true) when DT_CODES::Tab then res := res + CHAR_CODE::create( CONTROL_CODES::HORIZONTAL_TAB.card,lib) -- when DT_CODES::Time then -- Handled during building when DT_CODES::Year_Sun_Week then loc_week : CARD := date.week_in_year ; if date.year_start_day = WEEKDAYS::Sunday then loc_week := loc_week + 1 end ; res := res + do_number(loc_week,2,lib,modified,true) when DT_CODES::Week_Day then res := res + CODE_STR::create(date.day_of_week.str) when DT_CODES::Year_Mon_Week then loc_week : CARD := date.week_in_year ; if date.year_start_day = WEEKDAYS::Monday then loc_week := loc_week + 1 end ; res := res + do_number(loc_week,2,lib,modified,true) -- when DT_CODES::Local_Date then -- when DT_CODES::Local_Time then -- Handled during building when DT_CODES::Century_Year then res := res + do_number(date.year_this_century,2, lib,modified,true) when DT_CODES::Year then res := res + do_number(date.year,4,lib,modified,true) when DT_CODES::Time_Zone then loc_stamp : TIME_STAMP := TIME_STAMP::create(date,time) ; res := res + CODE_STR::create( lib.culture.date_time.time_zone.str(loc_stamp,lib)) when DT_CODES::Percent then res := res + lib.Percent else -- error in cultural spec! SYS_ERROR::create.error(self, SYS_EXCEPT::Bad_Format,loc_code.card.str) end ; loc_str : CODE_STR := separators.elt! ; if ~void(loc_str) then res := res + loc_str end end ; return res end ; fmt( val : DATES, lib : LIBCHARS ) : STR pre ~void(self) and ~void(lib) and ~(val = DATES::null) post ~void(result) -- and it is a valid date representation! is -- This routine produces a formatted version of the given date as a text -- string representation. loc_res : CODE_STR := do_format(val,TIMES::null,lib) ; if void(prefix) then return loc_res.tgt_str else return prefix.tgt_str + loc_res.tgt_str end end ; fmt( val : TIMES, lib : LIBCHARS ) : STR pre ~void(self) and ~void(lib) -- could be 'zero' and ~void(val) post ~void(result) -- and it is a valid time representation! is -- This routine produces a formatted version of the given time as a text -- string representation. loc_res : CODE_STR := do_format(DATES::null,val,lib) ; if void(prefix) then return loc_res.tgt_str else return prefix.tgt_str + loc_res.tgt_str end end ; fmt( stamp : TIME_STAMP, lib : LIBCHARS ) : STR pre ~void(self) and ~void(lib) and ~(stamp = TIME_STAMP::create(0,0)) post ~void(result) -- and it is a valid date representation! is -- This routine produces a formatted version of the given date/time as -- a text string representation. loc_date : DATES := DATES::create(stamp) ; loc_time : TIMES := TIMES::create(stamp) ; loc_res : CODE_STR := do_format(loc_date,loc_time,lib) ; if void(prefix) then return loc_res.tgt_str else return prefix.tgt_str + loc_res.tgt_str end end ; end ; -- DATE_FMT

class TEMPORAL

class TEMPORAL is -- This class contains the numeric components of the cultural -- description as specified in ISO/IEC 14652 (as amended). -- -- WARNING READ THE FOLLOWING NOTE -- -- Note that the alternate digits component of the ISO/IEC LC_TIME -- specification is NOT included in this as it is/may be also used for -- numbers and is therefore included in the class NUMBERS. -- Version 1.0 Jun 98. Copyright K Hopper, U of Waikato -- Development History -- ------------------- -- Date Who By Detail -- ---- ------ ------ -- 26 Jun 98 kh Original design from cultural compiler readonly attr date : DT_FMT ; readonly attr time : DT_FMT ; readonly attr date_time : DT_FMT ; readonly attr era_date : DT_FMT ; readonly attr era : DT_FMT ; readonly attr era_year : DT_FMT ; readonly attr relative_time : DT_FMT ; readonly attr week_day_count : CARD ; -- three values for 'week' readonly attr first_day_in_week : WEEKDAYS ; readonly attr first_week_contains : WEEKDAYS ; readonly attr first_day_display : WEEKDAYS ; readonly attr first_work_day : WEEKDAYS ; readonly attr cal_dir : CAL_DISPLAY_ORDERS ; private attr time_zones : FLIST{TIME_ZONE} ; private attr current_zone : TIME_ZONE ; build( index : BIN_CURSOR, lib : LIBCHARS ) : SAME pre ~void(index) and ~index.is_done and ~void(lib) post (void(result) and index.is_done) or ~void(result) is -- This routine creates an object of this kind from the binary string -- attached to the given cursor providing that the string is long enough! -- If not long enough then void is returned. res : SAME := new ; res.date := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.time := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.date_time := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.era_date := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.era := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.era_year := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.relative_time := DT_FMT::read(index,lib) ; if index.is_done then return void end ; res.week_day_count := index.get_item.card ; if index.is_done then return void end ; res.first_day_in_week := WEEKDAYS::build(index) ; if index.is_done then return void end ; res.first_week_contains := WEEKDAYS::build(index) ; if index.is_done then return void end ; res.first_day_display := WEEKDAYS::build(index) ; if index.is_done then return void end ; res.first_work_day := WEEKDAYS::build(index) ; if index.is_done then return void end ; res.cal_dir := CAL_DISPLAY_ORDERS::build(index) ; if index.is_done then return void end ; if BOOL::build(index) then loc_cnt : CARD := index.get_item.card ; if loc_cnt > 0 then res.time_zones := FLIST{TIME_ZONE}::create ; loop loc_cnt.times! ; res.time_zones := res.time_zones.push( TIME_ZONE::build(index,lib)) ; if index.is_done then return void end end ; res.current_zone := res.time_zones[0] end end ; return res end ; build( index : BIN_CURSOR ) : SAME pre ~void(index) and ~index.is_done post (void(result) and index.is_done) or ~void(result) is -- This routine creates an object of this kind from the binary string -- attached to the given cursor providing that the string is long enough! -- If not long enough then void is returned. return build(index,LIBCHARS::default) end ; time_zone : TIME_ZONE is -- This routine returns the current time zone in use by this program. -- Note that this may be void if no zones have been specified. return current_zone end ; time_zone( index : CARD ) pre ~void(current_zone) and (index < time_zones.size) post true is -- This is the writer routine to set the indexed time zone as current -- which will be returned by the corresponding reader routine until a -- further change is made. Note that if no zones are specified then calls -- to time_zone will result in no action being taken. current_zone := time_zones[index] end ; binstr : BINSTR pre ~void(self) post ~void(result) is -- This routine returns a binary string representation of self. res : BINSTR := BINSTR::create ; if void(date) then res := res + false.binstr else res := res + true.binstr + date.binstr end ; if void(time) then res := res + false.binstr else res := res + true.binstr + time.binstr end ; if void(date_time) then res := res + false.binstr else res := res + true.binstr + date_time.binstr end ; if void(era_date) then res := res + false.binstr else res := res + true.binstr + era_date.binstr end ; if void(era) then res := res + false.binstr else res := res + true.binstr + era.binstr end ; if void(era_year) then res := res + false.binstr else res := res + true.binstr + era_year.binstr end ; if void(relative_time) then res := res + false.binstr else res := res + true.binstr + relative_time.binstr end ; res := res + week_day_count.binstr + first_day_in_week.binstr + first_week_contains.binstr + first_day_display.binstr + first_work_day.binstr + cal_dir.binstr ; if void(time_zones) then res := res + false.binstr else res := res + true.binstr + OCTET::create(time_zones.size) ; loop res := res + time_zones.elt!.binstr end end ; return res end ; end ; -- TEMPORAL