#
# $Id: timezone.icn,v 1.1 2004/02/12 17:07:57 rparlett Exp $
#
# This file is in the public domain.
#
# Author: Robert Parlett (parlett@dial.pipex.com)
#

package util

global known_timezones, system_timezone, utc_timezone

class Timezone(offset, id)
   method get_id()
      return id
   end

   method get_offset()
      return offset
   end

   initially(a[])
      initial {
         init_timezone()
      }
      if *a = 0 then {
         id := "UTC"
         offset := 0
      }
      else if *a = 1 then {
         if type(a[1]) == "integer" then {
            offset := a[1]
            id := (if offset < 0 then "-" else "+") ||
               right(abs(offset) / 3600, 2, "0") || 
               right((abs(offset) % 3600) / 60, 2, "0") 
         } else {
            id := a[1]
            offset := get_known_timezone(id).get_offset() | fail
         }
      } else {
         offset := a[1]
         id := a[2]
      }
end

procedure init_timezone()
   known_timezones := table()

   utc_timezone := Timezone(0, "UTC")
   insert(known_timezones, "GMT", Timezone(0, "GMT"))
   insert(known_timezones, "UTC", utc_timezone)
   insert(known_timezones, "UT", Timezone(0, "UT"))
   insert(known_timezones, "BST", Timezone(3600, "BST"))
   insert(known_timezones, "EST", Timezone(-18000, "EST"))
   insert(known_timezones, "EDT", Timezone(-14400, "EDT"))
   insert(known_timezones, "CST", Timezone(-21600, "CST"))
   insert(known_timezones, "CDT", Timezone(-18000, "CDT"))
   insert(known_timezones, "MST", Timezone(-25200, "MST"))
   insert(known_timezones, "MDT", Timezone(-21600, "MDT"))
   insert(known_timezones, "PST", Timezone(-28800, "PST"))
   insert(known_timezones, "PDT", Timezone(-25200, "PDT"))

   #
   # Set the system timezone
   #
   s := gettimeofday()[1]
   t1 := util::Time()
   pat := "E MMM dd hh:mm:ss yyyy zzzz"
   t1.parse(ctime(s) || " +0000", pat) | stop("Couldn't parse ctime")
   t2 := util::Time()
   t2.parse(gtime(s) || " +0000", pat) | stop("Couldn't parse gtime")
   system_timezone := Timezone(t1.get_seconds() - t2.get_seconds())
   # If possible, use a symbolic representation, eg "EST" instead of -0500
   if &features == "UNIX" then {
      if f := open("date +%Z", "p") then {
         t := read(f)
         close(f)
      }
      # Only use a known symbol, whose offset agrees with the one just calculated
      if (\known_timezones[\t]).get_offset() = system_timezone.get_offset() then
         system_timezone := known_timezones[t]
   }
end

procedure get_system_timezone()
   initial {
      init_timezone()
   }
   return system_timezone
end

procedure get_utc_timezone()
   initial {
      init_timezone()
   }
   return utc_timezone
end

#
# Convert a zone id into a Timezone
#
procedure get_known_timezone(id)
   initial {
      init_timezone()
   }
   if member(known_timezones, id) then
      return known_timezones[id]

   id ? {
      if any('+-') then {
         if any('-') then 
            sign := -1
         else
            sign := 1
         move(1)
         s := tab(many(&digits)) | fail
         return Timezone(sign * 3600 * integer(s[1:3]) + 60 * integer(s[3:5]), id) | fail
      }
   }
end