]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/time.rb
time: add timestamp parser as a fallback to the default functionality
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / time.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Time Zone Plugin for rbot
5 #
6 # Author:: Ian Monroe <ian@monroe.nu>
7 # Copyright:: (C) 2006 Ian Monroe
8 # License:: MIT license
9
10 require 'tzinfo'
11
12 class TimePlugin < Plugin
13
14   def help(plugin, topic="")
15   "time <time zone> to get the local time of a certain location. <time zone> can be <Continent/City> or <two character country code>. time <nick> to see the local time of that person if their time zone is set. time admin set <nick> <time zone> to set the time zone for another user. time [admin] reset [nick] to let the bot forget about the tzinfo about someone"
16   end
17
18   def initialize
19     super
20     # this plugin only wants to store strings
21     class << @registry
22       def store(val)
23         val
24       end
25       def restore(val)
26         val
27       end
28     end
29   end
30
31   def getTime(m, zone )
32     if zone.length == 2 then #country code
33       zone.upcase!
34       zone = 'GB' if zone == 'UK' #country doesn't know its own name
35       begin
36         nationZones = TZInfo::Country.get(zone).zone_identifiers
37         if nationZones.size == 1 then
38           zone = nationZones[0]
39         else
40           m.reply "#{zone} has the cities of #{nationZones.join( ', ' )}."
41         end
42       rescue TZInfo::InvalidCountryCode
43         m.reply "#{zone} is not a valid country code."
44       end
45     end
46     ['/', '_'].each { |sp|
47         arr = Array.new
48         zone.split(sp).each{ |s|
49             s[0] = s[0,1].upcase
50             s[1, s.length] = s[1, s.length].downcase if sp == '/'
51             arr.push(s) }
52             zone = arr.join( sp )
53         }
54
55     tz = TZInfo::Timezone.get( zone )
56     "#{tz.friendly_identifier} - #{tz.now.strftime( '%a %b %d %H:%M' )} #{tz.current_period.abbreviation}"
57   end
58
59   def showTime(m, params)
60     zone = params[:where].join('_')
61     if params[:where].size > 0 then
62       begin
63         m.reply getTime( m,  zone )
64       rescue TZInfo::InvalidTimezoneIdentifier
65         if @registry.has_key?( zone ) then
66           zone =  @registry[ zone ]
67           m.reply getTime( m,  zone )
68         else
69           parse(m, params)
70         end
71       end
72     else
73       if @registry.has_key?( m.sourcenick) then
74         zone = @registry[ m.sourcenick ]
75         m.reply "#{m.sourcenick}: #{getTime( m,  zone )}"
76       else
77         m.reply "#{m.sourcenick}: use time set <Continent/City> to set your timezone."
78       end
79     end
80   end
81
82   def setUserZone( m, params )
83     if params[:where].size > 0 then
84       s = setZone( m, m.sourcenick, params[:where].join('_') )
85     else
86       m.reply "Requires Continent/City or country code"
87     end
88   end
89
90   def resetUserZone( m, params )
91     s = resetZone( m, m.sourcenick)
92   end
93
94   def setAdminZone( m, params )
95     if params[:who] and params[:where].size > 0 then
96       s = setZone( m, params[:who], params[:where].join('_') )
97     else
98       m.reply "Requires a nick and the Continent/City or country code"
99     end
100   end
101
102   def resetAdminZone( m, params )
103     if params[:who]
104       s = resetZone( m, params[:who])
105     else
106       m.reply "Requires a nick"
107     end
108   end
109
110   def setZone( m, user, zone )
111     begin
112       getTime( m,  zone )
113     rescue TZInfo::InvalidTimezoneIdentifier
114       m.reply "#{zone} is an invalid timezone. Format is Continent/City or a two character country code."
115       return
116     end
117     @registry[ user ] = zone
118     m.reply "Ok, I'll remember that #{user} is on the #{zone} timezone"
119   end
120
121   def resetZone( m, user )
122     @registry.delete(user)
123     m.reply "Ok, I've forgotten #{user}'s timezone"
124   end
125
126   def parse(m, params)
127     require 'time'
128     str = params[:where].to_s
129     now = Time.now
130
131     begin
132       time = begin
133         Time.parse str
134       rescue ArgumentError => e
135         # Handle 28/9/1978, which is a valid date representation at least in Italy
136         if e.message == 'argument out of range'
137           str.tr!('/', '-')
138           Time.parse str
139         else
140           raise
141         end
142       end
143
144       offset = (time - now).abs
145       raise if offset < 0.1
146     rescue => e
147       m.reply _("unintelligible time")
148       return
149     end
150
151     if zone = @registry[m.sourcenick]
152       time = time.convert_zone(zone)
153     end
154
155     m.reply _("%{time} %{w} %{str}") % {
156       :time => time.strftime(_("%a, %d %b %Y %H:%M:%S %Z %z")),
157       :str  => Utils.timeago(time),
158       :w    => time >= now ? _("is") : _("was")
159     }
160   end
161 end
162
163 class ::Time
164   def convert_zone(to_zone)
165     original_zone = ENV["TZ"]
166     utc_time = dup.gmtime
167     ENV["TZ"] = to_zone
168     to_zone_time = utc_time.localtime
169     ENV["TZ"] = original_zone
170     return to_zone_time
171   end
172 end
173
174 plugin = TimePlugin.new
175
176 plugin.default_auth('admin', false)
177
178 plugin.map 'time set [time][zone] [to] *where', :action=> 'setUserZone', :defaults => {:where => false}
179 plugin.map 'time reset [time][zone]', :action=> 'resetUserZone'
180 plugin.map 'time admin set [time][zone] [for] :who [to] *where', :action=> 'setAdminZone', :defaults => {:who => false, :where => false}
181 plugin.map 'time admin reset [time][zone] [for] :who', :action=> 'resetAdminZone', :defaults => {:who => false}
182 plugin.map 'time *where', :action => 'showTime', :defaults => {:where => false}