note description: "[ Summary description for {HTTP_DATE}. HTTP-date = rfc1123-date | rfc850-date | asctime-date rfc1123-date = wkday "," SP date1 SP time SP "GMT" rfc850-date = weekday "," SP date2 SP time SP "GMT" asctime-date = wkday SP date3 SP time SP 4DIGIT date1 = 2DIGIT SP month SP 4DIGIT ; day month year (e.g., 02 Jun 1982) date2 = 2DIGIT "-" month "-" 2DIGIT ; day-month-year (e.g., 02-Jun-82) date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) ; month day (e.g., Jun 2) time = 2DIGIT ":" 2DIGIT ":" 2DIGIT ; 00:00:00 - 23:59:59 wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun" weekday = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday" month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec" Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format ]" date: "$Date$" revision: "$Revision$" EIS: "name=RFC2616", "protocol=URI", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html" class HTTP_DATE inherit DEBUG_OUTPUT create make_now_utc, make_from_timestamp, make_from_string, make_from_date_time feature {NONE} -- Initialization make_from_timestamp (n: INTEGER_64) -- Build from unix timestamp `n' do internal_timestamp := n --| FIXME: find workaround when `n' is not INTEGER_32 create date_time.make_from_epoch (n.as_integer_32) end make_from_string (s: READABLE_STRING_8) -- Create from string representation `s' -- Supports: RFC 1123 and RFC 850 -- Tolerant with: GMT+offset and GMT-offset --| Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 --| Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 do if attached string_to_date_time (s) as dt then date_time := dt elseif attached ansi_c_string_to_date_time (s) as dt then date_time := dt else has_error := True date_time := epoch end end make_from_date_time (dt: DATE_TIME) -- Build from date `dt' do date_time := dt end make_now_utc -- Build from current utc date time. do create date_time.make_now_utc end feature -- Access has_error: BOOLEAN -- Error occurred during creation with `make_from_string'? date_time: DATE_TIME -- Associated Date time. string: STRING -- String representation recommended for HTTP date. --| Sun, 06 Nov 1994 08:49:37 GMT do Result := rfc1123_string end timestamp: INTEGER_64 -- Unix timestamp. do Result := internal_timestamp if Result = 0 then Result := date_time.definite_duration (epoch).seconds_count internal_timestamp := Result end end feature {NONE} -- Internal epoch: DATE_TIME once ("THREAD") create Result.make_from_epoch (0) end internal_timestamp: like timestamp internal_rfc1123_string: detachable STRING feature -- Conversion to string yyyy_mmm_dd_string: STRING -- String representation YYYY mmm dd -- 2012 Dec 25 do create Result.make (11) append_date_time_to_yyyy_mmm_dd_string (date_time, Result) end rfc1123_string: STRING -- String representation following RFC 1123. --| Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 local s: like internal_rfc1123_string do s := internal_rfc1123_string if s = Void then create s.make (32) append_date_time_to_rfc1123_string (date_time, s) internal_rfc1123_string := s end Result := s end rfc850_string: STRING -- String representation following RFC 850 do create Result.make (32) append_date_time_to_rfc850_string (date_time, Result) end ansi_c_string: STRING -- ANSI C's asctime() format do create Result.make (32) append_date_time_to_ansi_c_string (date_time, Result) end feature -- Conversion into string append_to_yyyy_mmm_dd_string (s: STRING_GENERAL) local dt: DATE_TIME do dt := date_time append_integer_to (dt.year, s) -- yyyy s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd end append_to_rfc1123_string (s: STRING_GENERAL) local dt: DATE_TIME do dt := date_time append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd s.append_code (44) -- 44 ',' -- ',' s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.year, s) -- YYYY s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append (" GMT") -- SPace + GMT end append_rfc850_string (s: STRING_GENERAL) local dt: DATE_TIME do dt := date_time append_day_name_to (dt.date.day_of_the_week, s) -- mmm s.append_code (44) -- 44 ',' -- ',' s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd s.append_code (45) -- 45 '-' -- '-' append_month_mmm_to (dt.month, s) -- mmm s.append_code (45) -- 45 '-' -- '-' append_integer_to (dt.year \\ 100, s) -- yy s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append (" GMT") -- SPace + GMT end append_to_ansi_c_string (s: STRING_GENERAL) --| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format local dt: DATE_TIME do dt := date_time append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.day, s) -- d s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.year, s) -- yyyy end feature -- Conversion into string append_date_time_to_yyyy_mmm_dd_string (dt: DATE_TIME; s: STRING_GENERAL) do append_integer_to (dt.year, s) -- yyyy s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd end append_date_time_to_rfc1123_string (dt: DATE_TIME; s: STRING_GENERAL) do append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd s.append_code (44) -- 44 ',' -- ',' s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.year, s) -- yyyy s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append (" GMT") -- SPace + GMT end append_date_time_to_rfc850_string (dt: DATE_TIME; s: STRING_GENERAL) do append_day_name_to (dt.date.day_of_the_week, s) -- mmm s.append_code (44) -- 44 ',' -- ',' s.append_code (32) -- 32 ' ' -- SPace append_2_digits_integer_to (dt.day, s) -- dd s.append_code (45) -- 45 '-' -- '-' append_month_mmm_to (dt.month, s) -- mmm s.append_code (45) -- 45 '-' -- '-' append_integer_to (dt.year \\ 100, s) -- yy s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append (" GMT") -- SPace + GMT end append_date_time_to_ansi_c_string (dt: DATE_TIME; s: STRING_GENERAL) --| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format do append_day_ddd_to (dt.date.day_of_the_week, s) -- ddd s.append_code (32) -- 32 ' ' -- SPace append_month_mmm_to (dt.month, s) -- mmm s.append_code (32) -- 32 ' ' -- SPace s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.day, s) -- d s.append_code (32) -- 32 ' ' -- SPace append_2_digits_time_to (dt.time, s) -- hh:mi:ss s.append_code (32) -- 32 ' ' -- SPace append_integer_to (dt.year, s) -- yyyy end feature -- Status report debug_output: STRING do if attached internal_rfc1123_string as st then Result := st.string else create Result.make (32) append_date_time_to_rfc1123_string (date_time, Result) end end feature {NONE} -- Implementation append_2_digits_integer_to (i: INTEGER; s: STRING_GENERAL) require is_not_negative: i >= 0 do if i <= 9 then s.append_code (48) -- 48 '0' end append_integer_to (i, s) end append_2_digits_time_to (t: TIME; s: STRING_GENERAL) do append_2_digits_integer_to (t.hour, s) -- hh s.append_code (58) -- 58 ':' -- : append_2_digits_integer_to (t.minute, s) -- mi s.append_code (58) -- 58 ':' -- : append_2_digits_integer_to (t.second, s) -- ss end append_day_ddd_to (d: INTEGER; s: STRING_GENERAL) require 1 <= d and d <= 7 do inspect d when 1 then s.append ("Sun") when 2 then s.append ("Mon") when 3 then s.append ("Tue") when 4 then s.append ("Wed") when 5 then s.append ("Thu") when 6 then s.append ("Fri") when 7 then s.append ("Sat") else -- Error end end append_day_name_to (d: INTEGER; s: STRING_GENERAL) require 1 <= d and d <= 7 do inspect d when 1 then s.append ("Sunday") when 2 then s.append ("Monday") when 3 then s.append ("Tuesday") when 4 then s.append ("Wednesday") when 5 then s.append ("Thursday") when 6 then s.append ("Friday") when 7 then s.append ("Saturday") else -- Error end end append_month_mmm_to (m: INTEGER; s: STRING_GENERAL) require 1 <= m and m <= 12 do inspect m when 1 then s.append ("Jan") when 2 then s.append ("Feb") when 3 then s.append ("Mar") when 4 then s.append ("Apr") when 5 then s.append ("May") when 6 then s.append ("Jun") when 7 then s.append ("Jul") when 8 then s.append ("Aou") when 9 then s.append ("Sep") when 10 then s.append ("Oct") when 11 then s.append ("Nov") when 12 then s.append ("Dec") else -- Error end end append_integer_to (i: INTEGER; s: STRING_GENERAL) do if attached {STRING_32} s as s32 then s32.append_integer (i) elseif attached {STRING_8} s as s8 then s8.append_integer (i) else s.append (i.out) end end feature {NONE} -- Implementation string_to_date_time (s: READABLE_STRING_8): detachable DATE_TIME -- String representation of `dt' using the RFC 1123 -- HTTP-date = rfc1123-date | rfc850-date | asctime-date -- rfc1123-date = wkday "," SP date1 SP time SP "GMT" -- rfc850-date = weekday "," SP date2 SP time SP "GMT" -- asctime-date = wkday SP date3 SP time SP 4DIGIT -- date1 = 2DIGIT SP month SP 4DIGIT -- ; day month year (e.g., 02 Jun 1982) -- date2 = 2DIGIT "-" month "-" 2DIGIT -- ; day-month-year (e.g., 02-Jun-82) -- date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) -- ; month day (e.g., Jun 2) -- time = 2DIGIT ":" 2DIGIT ":" 2DIGIT -- ; 00:00:00 - 23:59:59 -- wkday = "Mon" | "Tue" | "Wed" -- | "Thu" | "Fri" | "Sat" | "Sun" -- weekday = "Monday" | "Tuesday" | "Wednesday" -- | "Thursday" | "Friday" | "Saturday" | "Sunday" -- month = "Jan" | "Feb" | "Mar" | "Apr" -- | "May" | "Jun" | "Jul" | "Aug" -- | "Sep" | "Oct" | "Nov" | "Dec" --| Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 --| Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 --| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format note EIS: "name=RFC2616", "protocol=URI", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html" local t: STRING_8 l_ddd, l_mmm: detachable STRING_8 l_dd, l_yyyy, l_hh, l_mi, l_ss, l_ff2: INTEGER l_mo: INTEGER l_gmt_offset: INTEGER -- minutes i, n: INTEGER err: BOOLEAN do i := 1 n := s.count create t.make (4) -- Skip blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| ddd t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i]) i := i + 1 end if i <= n and t.count >= 3 then -- Accept full day string l_ddd := t.as_lower else err := True end --| blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| ,[0]dd if not err and i <= n and s[i] = ',' then i := i + 1 from until i > n or else not s[i].is_space loop i := i + 1 end t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.is_integer end l_dd := t.to_integer else err := True end else err := True end --| blanks or '-' if s[i] = '-' then i := i + 1 else from until i > n or else not s[i].is_space loop i := i + 1 end end --| mmm if not err then t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i]) i := i + 1 end if i <= n and t.count >= 3 then l_mmm := t.as_upper if l_mmm.count > 3 then -- Tolerant to full month name .. l_mmm.keep_head (3) end if l_mmm.same_string ("JAN") then l_mo := 01 elseif l_mmm.same_string ("FEB") then l_mo := 02 elseif l_mmm.same_string ("MAR") then l_mo := 03 elseif l_mmm.same_string ("APR") then l_mo := 04 elseif l_mmm.same_string ("MAY") then l_mo := 05 elseif l_mmm.same_string ("JUN") then l_mo := 06 elseif l_mmm.same_string ("JUL") then l_mo := 07 elseif l_mmm.same_string ("AOU") then l_mo := 08 elseif l_mmm.same_string ("SEP") then l_mo := 09 elseif l_mmm.same_string ("OCT") then l_mo := 10 elseif l_mmm.same_string ("NOV") then l_mo := 11 elseif l_mmm.same_string ("DEC") then l_mo := 12 else err := True end else err := True end end --| blanks or '-' if s[i] = '-' then i := i + 1 else from until i > n or else not s[i].is_space loop i := i + 1 end end --| yyyy if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.count = 4 or t.count = 2 and t.is_integer end l_yyyy := t.to_integer if t.count = 2 then -- RFC 850 l_yyyy := 1900 + l_yyyy end else err := True end end --| blank from until i > n or else not s[i].is_space loop i := i + 1 end --| [0]hh: if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 and s[i] = ':' then check t.count = 2 and t.is_integer end l_hh := t.to_integer i := i + 1 else err := True end end --| [0]mi: if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 and s[i] = ':' then check t.count = 2 and t.is_integer end l_mi := t.to_integer i := i + 1 else err := True end end --| [0]ss if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.count = 2 and t.is_integer end l_ss := t.to_integer else err := True end end --| .ff2 if not err and s[i] = '.' then --| .ff2 i := i + 1 t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.is_integer end l_ff2 := t.to_integer else err := True end end if not err then from until i > n or else not s[i].is_space loop i := i + 1 end t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i].as_upper) i := i + 1 end if t.same_string ("GMT") or t.same_string ("UTC") then from until i > n or else not s[i].is_space loop i := i + 1 end if i <= n then t.wipe_out if s[i] = '+' then t.extend (s[i]) elseif s[i] = '-' then t.extend (s[i]) else err := True end if not err then i := i + 1 from until i > n or else not s[i].is_space loop i := i + 1 end from until i > n or else not s[i].is_digit loop t.extend (s[i].as_upper) i := i + 1 end l_gmt_offset := t.to_integer * 60 if i <= n and s[i] = ':' then i := i + 1 t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i].as_upper) i := i + 1 end l_gmt_offset := l_gmt_offset + l_gmt_offset.sign * t.to_integer end end end else err := True end end if not err then check valid_yyyy: 0 < l_yyyy valid_dd: 0 < l_dd and l_dd <= 31 valid_mo: 0 < l_mo and l_mo <= 12 valid_hh: 0 <= l_hh and l_hh <= 23 valid_mi: 0 <= l_mi and l_mi <= 59 valid_ss: 0 <= l_ss and l_ss <= 59 end create Result.make (l_yyyy, l_mo, l_dd, l_hh, l_mi, l_ss) if l_gmt_offset /= 0 then Result.minute_add (- l_gmt_offset) end else -- Void is better than wrong date. end end ansi_c_string_to_date_time (s: READABLE_STRING_8): detachable DATE_TIME -- String representation of `dt' using the RFC 1123 -- asctime-date = wkday SP date3 SP time SP 4DIGIT -- date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) -- ; month day (e.g., Jun 2) -- time = 2DIGIT ":" 2DIGIT ":" 2DIGIT -- ; 00:00:00 - 23:59:59 -- wkday = "Mon" | "Tue" | "Wed" -- | "Thu" | "Fri" | "Sat" | "Sun" -- month = "Jan" | "Feb" | "Mar" | "Apr" -- | "May" | "Jun" | "Jul" | "Aug" -- | "Sep" | "Oct" | "Nov" | "Dec" --| Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format note EIS: "name=RFC2616", "protocol=URI", "src=http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html" local t: STRING_8 l_ddd, l_mmm: detachable STRING_8 l_dd, l_yyyy, l_hh, l_mi, l_ss, l_ff2: INTEGER l_mo: INTEGER l_gmt_offset: INTEGER -- minutes i, n: INTEGER err: BOOLEAN do i := 1 n := s.count create t.make (4) -- Skip blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| ddd t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i]) i := i + 1 end if i <= n and t.count >= 3 then -- Accept full day string l_ddd := t.as_lower else err := True end --| blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| mmm if not err then t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i]) i := i + 1 end if i <= n and t.count >= 3 then l_mmm := t.as_upper if l_mmm.count > 3 then -- Tolerant to full month name .. l_mmm.keep_head (3) end if l_mmm.same_string ("JAN") then l_mo := 01 elseif l_mmm.same_string ("FEB") then l_mo := 02 elseif l_mmm.same_string ("MAR") then l_mo := 03 elseif l_mmm.same_string ("APR") then l_mo := 04 elseif l_mmm.same_string ("MAY") then l_mo := 05 elseif l_mmm.same_string ("JUN") then l_mo := 06 elseif l_mmm.same_string ("JUL") then l_mo := 07 elseif l_mmm.same_string ("AOU") then l_mo := 08 elseif l_mmm.same_string ("SEP") then l_mo := 09 elseif l_mmm.same_string ("OCT") then l_mo := 10 elseif l_mmm.same_string ("NOV") then l_mo := 11 elseif l_mmm.same_string ("DEC") then l_mo := 12 else err := True end else err := True end end --| blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| dd if not err and i <= n then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.is_integer end l_dd := t.to_integer else err := True end else err := True end --| blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| [0]hh: if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 and s[i] = ':' then check t.count = 2 and t.is_integer end l_hh := t.to_integer i := i + 1 else err := True end end --| [0]mi: if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 and s[i] = ':' then check t.count = 2 and t.is_integer end l_mi := t.to_integer i := i + 1 else err := True end end --| [0]ss if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.count = 2 and t.is_integer end l_ss := t.to_integer else err := True end end --| .ff2 if not err and s[i] = '.' then --| .ff2 i := i + 1 t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if i <= n and t.count > 0 then check t.is_integer end l_ff2 := t.to_integer else err := True end end --| blanks from until i > n or else not s[i].is_space loop i := i + 1 end --| yyyy if not err then t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i]) i := i + 1 end if t.count > 0 then check t.count = 4 or t.count = 2 and t.is_integer end l_yyyy := t.to_integer if t.count = 2 then -- RFC 850 l_yyyy := 1900 + l_yyyy end else err := True end end --| blank from until i > n or else not s[i].is_space loop i := i + 1 end if i <= n and not err then from until i > n or else not s[i].is_space loop i := i + 1 end t.wipe_out from until i > n or else not s[i].is_alpha loop t.extend (s[i].as_upper) i := i + 1 end if t.same_string ("GMT") or t.same_string ("UTC") then from until i > n or else not s[i].is_space loop i := i + 1 end if i <= n then t.wipe_out if s[i] = '+' then t.extend (s[i]) elseif s[i] = '-' then t.extend (s[i]) else err := True end if not err then i := i + 1 from until i > n or else not s[i].is_space loop i := i + 1 end from until i > n or else not s[i].is_digit loop t.extend (s[i].as_upper) i := i + 1 end l_gmt_offset := t.to_integer * 60 if i <= n and s[i] = ':' then i := i + 1 t.wipe_out from until i > n or else not s[i].is_digit loop t.extend (s[i].as_upper) i := i + 1 end l_gmt_offset := l_gmt_offset + l_gmt_offset.sign * t.to_integer end end end else err := True end end if not err then check valid_yyyy: 0 < l_yyyy valid_dd: 0 < l_dd and l_dd <= 31 valid_mo: 0 < l_mo and l_mo <= 12 valid_hh: 0 <= l_hh and l_hh <= 23 valid_mi: 0 <= l_mi and l_mi <= 59 valid_ss: 0 <= l_ss and l_ss <= 59 end create Result.make (l_yyyy, l_mo, l_dd, l_hh, l_mi, l_ss) if l_gmt_offset /= 0 then Result.minute_add (- l_gmt_offset) end else -- Void is better than wrong date. end end invariant note copyright: "2011-2013, Jocelyn Fiat, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 5949 Hollister Ave., Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end