diff --git a/activesupport/build_marshalled_tzinfo_data.rb b/activesupport/build_marshalled_tzinfo_data.rb new file mode 100644 index 0000000000000000000000000000000000000000..1ff328755d559e6d9390800cfed6e4d7b9e9403a --- /dev/null +++ b/activesupport/build_marshalled_tzinfo_data.rb @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby +Dir.chdir(File.expand_path("..", __FILE__)) +$: << File.expand_path("../lib", __FILE__) +require "active_support" + +ActiveSupport::TimeZone.all + +def flatten_constants(mod, ary = []) + ary << mod + mod.constants.each do |const| + flatten_constants(mod.const_get(const), ary) + end + ary +end + +defns = flatten_constants(TZInfo::Definitions).select { |mod| + defined?(mod.get) +}.map { |tz| + tz.get +} + +file = "lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.dump" +data = Marshal.dump(defns) +Marshal.load(data) +File.open(file, "wb") do |f| + require "pry" + pry binding + f.write(data) +end +puts "Wrote #{data.size} bytes to #{file}" diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb index c8bdbeec5d4659cb4d2eeb8133be916e493a303e..dffc4bb59c36bd27a635c7de9dd8bd2e2aac5bee 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo.rb @@ -1,13 +1,13 @@ #-- # Copyright (c) 2005-2006 Philip Ross -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # @@ -30,4 +30,5 @@ # require 'tzinfo/tzdataparser' # require 'tzinfo/timezone_proxy' require 'tzinfo/data_timezone' -require 'tzinfo/linked_timezone' \ No newline at end of file +require 'tzinfo/linked_timezone' +require 'tzinfo/definitions' diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.dump b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.dump new file mode 100644 index 0000000000000000000000000000000000000000..98a966a9fc840611631d84d0c96c6efaf9917295 Binary files /dev/null and b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.dump differ diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.rb new file mode 100644 index 0000000000000000000000000000000000000000..1d75991648caf306dac3c63486aee631ce37be33 --- /dev/null +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/definitions.rb @@ -0,0 +1,30 @@ +require "tzinfo/data_timezone_info" +require "tzinfo/linked_timezone_info" +require "tzinfo/timezone_definition" + +module TZInfo + module Definitions + def self.load_all! + return true if @loaded + @loaded = true + + defns = Marshal.load(File.read(File.expand_path("../definitions.dump", __FILE__))) + + defns.each do |defn| + tz_mod = defn.instance_variable_get(:@identifier).split("/").reduce(TZInfo::Definitions) { |mod, name| + if mod.const_defined?(name) + mod.const_get(name) + else + mod.const_set(name, Module.new) + end + } + + def tz_mod.get + @timezone + end + + tz_mod.instance_variable_set(:@timezone, defn) + end + end + end +end diff --git a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb index f87fb6fb7025ab4f4857f8e363089fc26dd61557..b38fb54c3f44a1d6cdaf44ba62b325f9654088a5 100644 --- a/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb +++ b/activesupport/lib/active_support/vendor/tzinfo-0.3.12/tzinfo/timezone.rb @@ -1,13 +1,13 @@ #-- # Copyright (c) 2005-2006 Philip Ross -# +# # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: -# +# # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # @@ -24,31 +24,32 @@ # require 'tzinfo/country' require 'tzinfo/time_or_datetime' require 'tzinfo/timezone_period' +require 'tzinfo/definitions' module TZInfo # Indicate a specified time in a local timezone has more than one - # possible time in UTC. This happens when switching from daylight savings time + # possible time in UTC. This happens when switching from daylight savings time # to normal time where the clocks are rolled back. Thrown by period_for_local - # and local_to_utc when using an ambiguous time and not specifying any + # and local_to_utc when using an ambiguous time and not specifying any # means to resolve the ambiguity. class AmbiguousTime < StandardError end - + # Thrown to indicate that no TimezonePeriod matching a given time could be found. class PeriodNotFound < StandardError end - + # Thrown by Timezone#get if the identifier given is not valid. class InvalidTimezoneIdentifier < StandardError end - + # Thrown if an attempt is made to use a timezone created with Timezone.new(nil). class UnknownTimezone < StandardError end - + # Timezone is the base class of all timezones. It provides a factory method # get to access timezones by identifier. Once a specific Timezone has been - # retrieved, DateTimes, Times and timestamps can be converted between the UTC + # retrieved, DateTimes, Times and timestamps can be converted between the UTC # and the local time for the zone. For example: # # tz = TZInfo::Timezone.get('America/New_York') @@ -56,42 +57,41 @@ class UnknownTimezone < StandardError # puts tz.local_to_utc(Time.utc(2005,8,29,11,35,0)).to_s # puts tz.utc_to_local(1125315300).to_s # - # Each time conversion method returns an object of the same type it was + # Each time conversion method returns an object of the same type it was # passed. # # The timezone information all comes from the tz database # (see http://www.twinsun.com/tz/tz-link.htm) class Timezone include Comparable - + # Cache of loaded zones by identifier to avoid using require if a zone # has already been loaded. @@loaded_zones = {} - + # Whether the timezones index has been loaded yet. @@index_loaded = false - - # Returns a timezone by its identifier (e.g. "Europe/London", + + # Returns a timezone by its identifier (e.g. "Europe/London", # "America/Chicago" or "UTC"). # # Raises InvalidTimezoneIdentifier if the timezone couldn't be found. def self.get(identifier) instance = @@loaded_zones[identifier] - unless instance + + unless instance raise InvalidTimezoneIdentifier, 'Invalid identifier' if identifier !~ /^[A-z0-9\+\-_]+(\/[A-z0-9\+\-_]+)*$/ identifier = identifier.gsub(/-/, '__m__').gsub(/\+/, '__p__') begin - # Use a temporary variable to avoid an rdoc warning - file = "tzinfo/definitions/#{identifier}" - require file - + TZInfo::Definitions.load_all! + m = Definitions identifier.split(/\//).each {|part| m = m.const_get(part) } - + info = m.get - + # Could make Timezone subclasses register an interest in an info # type. Since there are currently only two however, there isn't # much point. @@ -102,35 +102,35 @@ def self.get(identifier) else raise InvalidTimezoneIdentifier, "No handler for info type #{info.class}" end - - @@loaded_zones[instance.identifier] = instance + + @@loaded_zones[instance.identifier] = instance rescue LoadError, NameError => e raise InvalidTimezoneIdentifier, e.message end end - + instance end - + # Returns a proxy for the Timezone with the given identifier. The proxy - # will cause the real timezone to be loaded when an attempt is made to - # find a period or convert a time. get_proxy will not validate the - # identifier. If an invalid identifier is specified, no exception will be - # raised until the proxy is used. + # will cause the real timezone to be loaded when an attempt is made to + # find a period or convert a time. get_proxy will not validate the + # identifier. If an invalid identifier is specified, no exception will be + # raised until the proxy is used. def self.get_proxy(identifier) TimezoneProxy.new(identifier) end - - # If identifier is nil calls super(), otherwise calls get. An identfier + + # If identifier is nil calls super(), otherwise calls get. An identfier # should always be passed in when called externally. def self.new(identifier = nil) - if identifier + if identifier get(identifier) else super() end end - + # Returns an array containing all the available Timezones. # # Returns TimezoneProxy objects to avoid the overhead of loading Timezone @@ -138,14 +138,14 @@ def self.new(identifier = nil) def self.all get_proxies(all_identifiers) end - - # Returns an array containing the identifiers of all the available + + # Returns an array containing the identifiers of all the available # Timezones. def self.all_identifiers load_index Indexes::Timezones.timezones end - + # Returns an array containing all the available Timezones that are based # on data (are not links to other Timezones). # @@ -154,44 +154,44 @@ def self.all_identifiers def self.all_data_zones get_proxies(all_data_zone_identifiers) end - - # Returns an array containing the identifiers of all the available + + # Returns an array containing the identifiers of all the available # Timezones that are based on data (are not links to other Timezones).. def self.all_data_zone_identifiers load_index Indexes::Timezones.data_timezones end - + # Returns an array containing all the available Timezones that are links # to other Timezones. # # Returns TimezoneProxy objects to avoid the overhead of loading Timezone # definitions until a conversion is actually required. def self.all_linked_zones - get_proxies(all_linked_zone_identifiers) + get_proxies(all_linked_zone_identifiers) end - - # Returns an array containing the identifiers of all the available + + # Returns an array containing the identifiers of all the available # Timezones that are links to other Timezones. def self.all_linked_zone_identifiers load_index Indexes::Timezones.linked_timezones end - + # Returns all the Timezones defined for all Countries. This is not the - # complete set of Timezones as some are not country specific (e.g. + # complete set of Timezones as some are not country specific (e.g. # 'Etc/GMT'). - # + # # Returns TimezoneProxy objects to avoid the overhead of loading Timezone - # definitions until a conversion is actually required. + # definitions until a conversion is actually required. def self.all_country_zones Country.all_codes.inject([]) {|zones,country| zones += Country.get(country).zones } end - + # Returns all the zone identifiers defined for all Countries. This is not the - # complete set of zone identifiers as some are not country specific (e.g. + # complete set of zone identifiers as some are not country specific (e.g. # 'Etc/GMT'). You can obtain a Timezone instance for a given identifier # with the get method. def self.all_country_zone_identifiers @@ -199,8 +199,8 @@ def self.all_country_zone_identifiers zones += Country.get(country).zone_identifiers } end - - # Returns all US Timezone instances. A shortcut for + + # Returns all US Timezone instances. A shortcut for # TZInfo::Country.get('US').zones. # # Returns TimezoneProxy objects to avoid the overhead of loading Timezone @@ -208,35 +208,35 @@ def self.all_country_zone_identifiers def self.us_zones Country.get('US').zones end - - # Returns all US zone identifiers. A shortcut for + + # Returns all US zone identifiers. A shortcut for # TZInfo::Country.get('US').zone_identifiers. def self.us_zone_identifiers Country.get('US').zone_identifiers end - + # The identifier of the timezone, e.g. "Europe/Paris". def identifier raise UnknownTimezone, 'TZInfo::Timezone constructed directly' end - + # An alias for identifier. def name # Don't use alias, as identifier gets overridden. identifier end - + # Returns a friendlier version of the identifier. def to_s friendly_identifier end - + # Returns internal object state as a programmer-readable string. def inspect "#<#{self.class}: #{identifier}>" end - - # Returns a friendlier version of the identifier. Set skip_first_part to + + # Returns a friendlier version of the identifier. Set skip_first_part to # omit the first part of the identifier (typically a region name) where # there is more than one part. # @@ -245,13 +245,13 @@ def inspect # Timezone.get('Europe/Paris').friendly_identifier(false) #=> "Europe - Paris" # Timezone.get('Europe/Paris').friendly_identifier(true) #=> "Paris" # Timezone.get('America/Indiana/Knox').friendly_identifier(false) #=> "America - Knox, Indiana" - # Timezone.get('America/Indiana/Knox').friendly_identifier(true) #=> "Knox, Indiana" + # Timezone.get('America/Indiana/Knox').friendly_identifier(true) #=> "Knox, Indiana" def friendly_identifier(skip_first_part = false) parts = identifier.split('/') if parts.empty? # shouldn't happen identifier - elsif parts.length == 1 + elsif parts.length == 1 parts[0] else if skip_first_part @@ -259,47 +259,47 @@ def friendly_identifier(skip_first_part = false) else result = parts[0] + ' - ' end - + parts[1, parts.length - 1].reverse_each {|part| part.gsub!(/_/, ' ') - + if part.index(/[a-z]/) # Missing a space if a lower case followed by an upper case and the # name isn't McXxxx. part.gsub!(/([^M][a-z])([A-Z])/, '\1 \2') part.gsub!(/([M][a-bd-z])([A-Z])/, '\1 \2') - + # Missing an apostrophe if two consecutive upper case characters. part.gsub!(/([A-Z])([A-Z])/, '\1\'\2') end - + result << part result << ', ' } - + result.slice!(result.length - 2, 2) result end end - + # Returns the TimezonePeriod for the given UTC time. utc can either be - # a DateTime, Time or integer timestamp (Time.to_i). Any timezone - # information in utc is ignored (it is treated as a UTC time). - def period_for_utc(utc) - raise UnknownTimezone, 'TZInfo::Timezone constructed directly' + # a DateTime, Time or integer timestamp (Time.to_i). Any timezone + # information in utc is ignored (it is treated as a UTC time). + def period_for_utc(utc) + raise UnknownTimezone, 'TZInfo::Timezone constructed directly' end - + # Returns the set of TimezonePeriod instances that are valid for the given - # local time as an array. If you just want a single period, use + # local time as an array. If you just want a single period, use # period_for_local instead and specify how ambiguities should be resolved. # Returns an empty array if no periods are found for the given time. def periods_for_local(local) raise UnknownTimezone, 'TZInfo::Timezone constructed directly' end - + # Returns the TimezonePeriod for the given local time. local can either be - # a DateTime, Time or integer timestamp (Time.to_i). Any timezone - # information in local is ignored (it is treated as a time in the current + # a DateTime, Time or integer timestamp (Time.to_i). Any timezone + # information in local is ignored (it is treated as a time in the current # timezone). # # Warning: There are local times that have no equivalent UTC times (e.g. @@ -312,70 +312,70 @@ def periods_for_local(local) # # In the second case (more than one equivalent UTC time), an AmbiguousTime # exception will be raised unless the optional dst parameter or block - # handles the ambiguity. + # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to - # standard time, the dst parameter can be used to select whether the + # standard time, the dst parameter can be used to select whether the # daylight savings time or local time is used. For example, # # Timezone.get('America/New_York').period_for_local(DateTime.new(2004,10,31,1,30,0)) # # would raise an AmbiguousTime exception. # - # Specifying dst=true would the daylight savings period from April to + # Specifying dst=true would the daylight savings period from April to # October 2004. Specifying dst=false would return the standard period # from October 2004 to April 2005. # - # If the dst parameter does not resolve the ambiguity, and a block is + # If the dst parameter does not resolve the ambiguity, and a block is # specified, it is called. The block must take a single parameter - an # array of the periods that need to be resolved. The block can select and # return a single period or return nil or an empty array # to cause an AmbiguousTime exception to be raised. - def period_for_local(local, dst = nil) + def period_for_local(local, dst = nil) results = periods_for_local(local) - + if results.empty? raise PeriodNotFound elsif results.size < 2 results.first else # ambiguous result try to resolve - + if !dst.nil? matches = results.find_all {|period| period.dst? == dst} - results = matches if !matches.empty? + results = matches if !matches.empty? end - + if results.size < 2 results.first else # still ambiguous, try the block - + if block_given? results = yield results end - + if results.is_a?(TimezonePeriod) results elsif results && results.size == 1 results.first - else + else raise AmbiguousTime, "#{local} is an ambiguous local time." end end - end + end end - + # Converts a time in UTC to the local timezone. utc can either be # a DateTime, Time or timestamp (Time.to_i). The returned time has the same - # type as utc. Any timezone information in utc is ignored (it is treated as + # type as utc. Any timezone information in utc is ignored (it is treated as # a UTC time). def utc_to_local(utc) TimeOrDateTime.wrap(utc) {|wrapped| period_for_utc(wrapped).to_local(wrapped) } end - + # Converts a time in the local timezone to UTC. local can either be # a DateTime, Time or timestamp (Time.to_i). The returned time has the same # type as local. Any timezone information in local is ignored (it is treated @@ -391,10 +391,10 @@ def utc_to_local(utc) # # In the second case (more than one equivalent UTC time), an AmbiguousTime # exception will be raised unless the optional dst parameter or block - # handles the ambiguity. + # handles the ambiguity. # # If the ambiguity is due to a transition from daylight savings time to - # standard time, the dst parameter can be used to select whether the + # standard time, the dst parameter can be used to select whether the # daylight savings time or local time is used. For example, # # Timezone.get('America/New_York').local_to_utc(DateTime.new(2004,10,31,1,30,0)) @@ -404,7 +404,7 @@ def utc_to_local(utc) # Specifying dst=true would return 2004-10-31 5:30:00. Specifying dst=false # would return 2004-10-31 6:30:00. # - # If the dst parameter does not resolve the ambiguity, and a block is + # If the dst parameter does not resolve the ambiguity, and a block is # specified, it is called. The block must take a single parameter - an # array of the periods that need to be resolved. The block can return a # single period to use to convert the time or return nil or an empty array @@ -416,21 +416,21 @@ def local_to_utc(local, dst = nil) else period = period_for_local(wrapped, dst) end - + period.to_utc(wrapped) } end - + # Returns the current time in the timezone as a Time. def now utc_to_local(Time.now.utc) end - - # Returns the TimezonePeriod for the current time. + + # Returns the TimezonePeriod for the current time. def current_period period_for_utc(Time.now.utc) end - + # Returns the current Time and TimezonePeriod as an array. The first element # is the time, the second element is the period. def current_period_and_time @@ -438,19 +438,19 @@ def current_period_and_time period = period_for_utc(utc) [period.to_local(utc), period] end - + alias :current_time_and_period :current_period_and_time - # Converts a time in UTC to local time and returns it as a string - # according to the given format. The formatting is identical to + # Converts a time in UTC to local time and returns it as a string + # according to the given format. The formatting is identical to # Time.strftime and DateTime.strftime, except %Z is replaced with the - # timezone abbreviation for the specified time (for example, EST or EDT). - def strftime(format, utc = Time.now.utc) + # timezone abbreviation for the specified time (for example, EST or EDT). + def strftime(format, utc = Time.now.utc) period = period_for_utc(utc) - local = period.to_local(utc) + local = period.to_local(utc) local = Time.at(local).utc unless local.kind_of?(Time) || local.kind_of?(DateTime) abbreviation = period.abbreviation.to_s.gsub(/%/, '%%') - + format = format.gsub(/(.?)%Z/) do if $1 == '%' # return %%Z so the real strftime treats it as a literal %Z too @@ -459,50 +459,50 @@ def strftime(format, utc = Time.now.utc) "#$1#{abbreviation}" end end - + local.strftime(format) end - + # Compares two Timezones based on their identifier. Returns -1 if tz is less # than self, 0 if tz is equal to self and +1 if tz is greater than self. def <=>(tz) identifier <=> tz.identifier end - - # Returns true if and only if the identifier of tz is equal to the + + # Returns true if and only if the identifier of tz is equal to the # identifier of this Timezone. def eql?(tz) self == tz end - + # Returns a hash of this Timezone. def hash identifier.hash end - + # Dumps this Timezone for marshalling. def _dump(limit) identifier end - + # Loads a marshalled Timezone. def self._load(data) Timezone.get(data) end - + private # Loads in the index of timezones if it hasn't already been loaded. def self.load_index unless @@index_loaded require 'tzinfo/indexes/timezones' @@index_loaded = true - end + end end - - # Returns an array of proxies corresponding to the given array of + + # Returns an array of proxies corresponding to the given array of # identifiers. def self.get_proxies(identifiers) identifiers.collect {|identifier| get_proxy(identifier)} end - end + end end