diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-02-23 12:56:16 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-02-23 12:56:16 +0000 |
commit | 6329daf5acc8f5f2f040cf46f33098fb21a622b5 (patch) | |
tree | 18a283acc12de9931c7f487e5afcfd5e7a71822d /activerecord/lib | |
parent | 2bf29b3485151f819318437561bea8abebe9427b (diff) | |
download | rails-6329daf5acc8f5f2f040cf46f33098fb21a622b5.tar.gz rails-6329daf5acc8f5f2f040cf46f33098fb21a622b5.tar.bz2 rails-6329daf5acc8f5f2f040cf46f33098fb21a622b5.zip |
Added TimeZone as the first of a number of value objects that Active Record will start shipping to provide incentatives to use rich value objects using composed_of #688 [Jamis Buck]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@760 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'activerecord/lib')
-rwxr-xr-x | activerecord/lib/active_record.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/values/time_zone.rb | 155 |
2 files changed, 156 insertions, 0 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index 04d16b41f3..682fec2b4a 100755 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -47,6 +47,7 @@ require 'active_record/timestamp' require 'active_record/acts/list' require 'active_record/acts/tree' require 'active_record/locking' +require 'active_record/values/time_zone' ActiveRecord::Base.class_eval do include ActiveRecord::Validations diff --git a/activerecord/lib/active_record/values/time_zone.rb b/activerecord/lib/active_record/values/time_zone.rb new file mode 100644 index 0000000000..7766727a40 --- /dev/null +++ b/activerecord/lib/active_record/values/time_zone.rb @@ -0,0 +1,155 @@ +# A value object representing a time zone. A time zone is simply a named +# offset (in seconds) from GMT. Note that two time zone objects are only +# equivalent if they have both the same offset, and the same name. +# +# A TimeZone instance may be used to convert a Time value to the corresponding +# time zone. +# +# The class also includes #all, which returns a list of all TimeZone objects. +class TimeZone + include Comparable + + attr_reader :name, :utc_offset + + # Create a new TimeZone object with the given name and offset. The offset is + # the number of seconds that this time zone is offset from UTC (GMT). Seconds + # were chosen as the offset unit because that is the unit that Ruby uses + # to represent time zone offsets (see Time#utc_offset). + def initialize(name, utc_offset) + @name = name + @utc_offset = utc_offset + end + + # Returns the offset of this time zone as a formatted string, of the + # format "+HH:MM". If the offset is zero, this returns the empty + # string. + def formatted_offset + return "" if utc_offset == 0 + sign = (utc_offset < 0 ? -1 : 1) + hours = utc_offset.abs / 3600 + minutes = (utc_offset.abs % 3600) / 60 + "%+03d:%02d" % [ hours * sign, minutes ] + end + + # Compute and return the current time, in the time zone represented by + # +self+. + def now + adjust(Time.now) + end + + # Adjust the given time to the time zone represented by +self+. + def adjust(time) + offset = time.utc_offset + time + utc_offset - offset + end + + # Compare this time zone to the parameter. The two are comapred first on + # their offsets, and then by name. + def <=>(zone) + result = (utc_offset <=> zone.utc_offset) + result = (name <=> zone.name) if result == 0 + result + end + + # Returns a textual representation of this time zone. + def to_s + "(GMT#{formatted_offset}) #{name}" + end + + @@zones = nil + + class << self + # Create a new TimeZone instance with the given name and offset. + def create(name, offset) + zone = allocate + zone.send :initialize, name, offset + zone + end + + # Return a TimeZone instance with the given name, or +nil+ if no + # such TimeZone instance exists. (This exists to support the use of + # this class with the #composed_of macro.) + def new(name) + self[name] + end + + # Return an array of all TimeZone objects. There are multiple TimeZone + # objects per time zone, in many cases, to make it easier for users to + # find their own time zone. + def all + unless @@zones + @@zones = [] + [[-43_200, "International Date Line West" ], + [-39_600, "Midway Island", "Samoa" ], + [-36_000, "Hawaii" ], + [-32_400, "Alaska" ], + [-28_800, "Pacific Time (US & Canada)", "Tijuana" ], + [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "La Paz", + "Mazatlan", "Arizona" ], + [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara", + "Mexico City", "Monterrey", "Central America" ], + [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota", + "Lima", "Quito" ], + [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ], + [-12_600, "Newfoundland" ], + [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ], + [ -7_200, "Mid-Atlantic" ], + [ -3_600, "Azores", "Cape Verde Is." ], + [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca", + "Monrovia" ], + [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague", + "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels", + "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin", + "Bern", "Rome", "Stockholm", "Vienna", + "West Central Africa" ], + [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia", + "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk", + "Jerusalem", "Harare", "Pretoria" ], + [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh", + "Nairobi", "Baghdad" ], + [ 12_600, "Tehran" ], + [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ], + [ 16_200, "Kabul" ], + [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ], + [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ], + [ 20_700, "Kathmandu" ], + [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty", + "Novosibirsk" ], + [ 23_400, "Rangoon" ], + [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ], + [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi", + "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk", + "Ulaan Bataar" ], + [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ], + [ 34_200, "Darwin", "Adelaide" ], + [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart", + "Vladivostok", "Guam", "Port Moresby" ], + [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ], + [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland", + "Wellington" ], + [ 46_800, "Nuku'alofa" ]]. + each do |offset, *places| + places.each { |place| @@zones << create(place, offset).freeze } + end + @@zones.sort! + end + @@zones + end + + # Locate a specific time zone object by the name it was given. Returns + # +nil+ if no such time zone is known to the system. + def [](name) + all.find { |z| z.name == name } + end + + # A regular expression that matches the names of all time zones in + # the USA. + US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/ + + # A convenience method for returning a collection of TimeZone objects + # for time zones in the USA. + def us_zones + all.find_all { |z| z.name =~ US_ZONES } + end + end +end
\ No newline at end of file |