lib/lazier/datetime.rb in lazier-2.4.0 vs lib/lazier/datetime.rb in lazier-2.5.0

- old
+ new

@@ -123,13 +123,15 @@ # @return [Date] The Easter date for the year. def easter(year = nil) year = ::Date.today.year if !year.is_integer? # Compute using Anonymouse Gregorian Algorithm: http://en.wikipedia.org/wiki/Computus#Anonymous_Gregorian_algorithm - a, b, c = easter_independent(year) - x, e, i, k = easter_dependent(b, c) - day, month = easter_summarize(easter_finalize(a, x, e, i, k)) + data = easter_start(year) + data = easter_part_1(data) + data = easter_part_2(year, data) + data = easter_part_3(year, data) + day, month = easter_end(data) ::Date.civil(year, month, day) end # Lookups a custom datetime format. @@ -163,50 +165,54 @@ private # Part one of Easter calculation. # # @param year [Fixnum] The year to compute the date for. - # @return [Array] Partial variables for calculus. - def easter_independent(year) + # @return [Array] Partial variables for #easter_part_1. + def easter_start(year) [year % 19, (year / 100.0).floor, year % 100] end # Part two of Easter calculation. - # - # @param b [Fixnum] Variable from #easter_independent. - # @param c [Fixnum] Variable from #easter_independent. - # @return [Array] Partial variables for calculus. - def easter_dependent(b, c) + # @param data [Fixnum] Partial variables from #easter_start. + # @return [Array] Partial variables for #easter_part_2. + def easter_part_1(data) + a, b, c = data [ b - (b / 4.0).floor - ((b - ((b + 8) / 25.0).floor + 1) / 3.0).floor, b % 4, (c / 4.0).floor, c % 4 ] end # Part three of Easter calculation. # - # @param a [Fixnum] Variable from #easter_independent. - # @param x [Fixnum] Variable from #easter_independent. - # @param e [Fixnum] Variable from #easter_dependent. - # @param i [Fixnum] Variable from #easter_dependent. - # @param k [Fixnum] Variable from #easter_dependent. - # @return [Array] Partial variables for calculus. - def easter_finalize(a, x, e, i, k) + # @param data [Fixnum] Partial variables from #easter_part_1. + # @return [Array] Partial variables for #easter_part_3. + def easter_part_2(year, data) + a = year % 19 + x, e, i, k = data h = ((19 * a) + x + 15) % 30 - l = (32 + (2 * e) + (2 * i) - h - k) % 7 + [h, (32 + (2 * e) + (2 * i) - h - k) % 7] + end + # Part four of Easter calculation + # @param data [Arrays] Partial variables from #easter_part_2. + # @return [Array] Partial variables for #easter_end. + def easter_part_3(year, data) + a = year % 19 + h, l = data [h, l, ((a + (11 * h) + (22 * l)) / 451.0).floor] end # Final part of Easter calculation. # - # @param prev [Fixnum] Variable from #easter_finalize. - # @return [Array] Day and month of Easter daye. - def easter_summarize(prev) - h, l, m = prev + # @param data [Fixnum] Variable from #easter_part_3. + # @return [Array] Day and month of Easter day. + def easter_end(data) + h, l, m = data [((h + l - (7 * m) + 114) % 31) + 1, ((h + l - (7 * m) + 114) / 31.0).floor] end end # Returns the UTC::Time representation of the current datetime. @@ -242,14 +248,11 @@ # @see Settings#setup_date_formats # # @param format [String] A format or a custom format name to use for formatting. # @return [String] The formatted date. def lstrftime(format = nil) - rv = nil - names = ::Lazier.settings.date_names - substitutions = {"%a" => names[:short_days][self.wday], "%A" => names[:long_days][self.wday], "%b" => names[:short_months][self.month - 1], "%B" => names[:long_months][self.month - 1]} - self.strftime(::DateTime.custom_format(format).ensure_string.gsub(/(?<!%)(%[ab])/i) {|mo| substitutions[mo] }) + self.strftime(::DateTime.custom_format(format).ensure_string.gsub(/(?<!%)(%[ab])/i) {|mo| localize_time_component(mo) }) end # Formats a datetime in the current timezone. # # @param format [String] The format to use for formatting. @@ -264,10 +267,21 @@ # @param format [String] A format or a custom format name. # @return [String] The formatted date. def local_lstrftime(format = nil) (self.respond_to?(:in_time_zone) ? self.in_time_zone : self).lstrftime(format) end + + private + # Returns a component of the date in the current locale. + # + # @param component [String] The component to localize. + # @return [String] The localized component. + def localize_time_component(component) + type = {"%a" => :short_days, "%A" => :long_days, "%b" => :short_months, "%B" => :long_months}.fetch(component, "") + index = component =~ /%a/i ? self.wday : self.month - 1 + ::Lazier.settings.date_names.fetch(type, [])[index] + end end # Extensions for timezone objects. module TimeZone extend ::ActiveSupport::Concern @@ -317,13 +331,11 @@ # @return [Array] A list of names of timezones. def list_all(with_dst = true, dst_label = nil) dst_label ||= "(DST)" @zones_names ||= { "STANDARD" => ::ActiveSupport::TimeZone.all.collect(&:to_s) } - @zones_names["DST[#{dst_label}]-STANDARD"] ||= ::ActiveSupport::TimeZone.all.collect { |zone| - zone.aliases.collect { |zone_alias| [zone.to_str(zone_alias), (zone.uses_dst? && zone_alias !~ /(#{Regexp.quote(dst_label)})$/) ? zone.to_str_with_dst(dst_label, nil, zone_alias) : nil] } - }.flatten.compact.uniq.sort { |a,b| ::ActiveSupport::TimeZone.compare(a, b) } # Sort by name + @zones_names["DST[#{dst_label}]-STANDARD"] ||= ::ActiveSupport::TimeZone.all.collect { |zone| fetch_aliases(zone, dst_label) }.flatten.compact.uniq.sort { |a,b| ::ActiveSupport::TimeZone.compare(a, b) } # Sort by name @zones_names["#{with_dst ? "DST[#{dst_label}]-" : ""}STANDARD"] end # Returns a string representation of a timezone. @@ -379,24 +391,28 @@ def compare(left, right) left = left.to_str if left.is_a?(::ActiveSupport::TimeZone) right = right.to_str if right.is_a?(::ActiveSupport::TimeZone) left.ensure_string.split(" ", 2)[1] <=> right.ensure_string.split(" ", 2)[1] end + + private + # Returns a list of aliases for a given time zone. + # + # @param zone [ActiveSupport::TimeZone] The zone. + # @param dst_label [String] Label for the DST indication. Defaults to `(DST)`. + def fetch_aliases(zone, dst_label = "(DST)") + zone.aliases.collect { |zone_alias| + [zone.to_str(zone_alias), (zone.uses_dst? && zone_alias !~ /(#{Regexp.quote(dst_label)})$/) ? zone.to_str_with_dst(dst_label, nil, zone_alias) : nil] + } + end end # Returns a list of valid aliases (city names) for this timezone (basing on offset). # @return [Array] A list of aliases for this timezone def aliases reference = self.class::MAPPING.fetch(self.name, self.name).gsub("_", " ") - - @aliases ||= ([reference] + self.class::MAPPING.collect { |name, zone| - if zone.gsub("_", " ") == reference then - (["International Date Line West", "UTC"].include?(name) || name.include?("(US & Canada)")) ? name : reference.gsub(/\/.*/, "/#{name}") - else - nil - end - }).uniq.compact.sort + @aliases ||= ([reference] + self.class::MAPPING.collect { |name, zone| format_alias(name, zone, reference) }).uniq.compact.sort end # Returns the current offset for this timezone, taking care of Daylight Saving Time (DST). # # @param rational [Boolean] If to return the offset as a Rational. @@ -541,7 +557,22 @@ # @return [String] The parametized string representation for this zone with DST or `nil`, if the timezone doesn't use DST for that year. def to_str_with_dst_parameterized(dst_label = nil, with_offset = true, year = nil, name = nil) rv = self.to_str_with_dst(dst_label, year, name) rv ? ::ActiveSupport::TimeZone.parameterize_zone(rv) : nil end + + private + # Formats a time zone alias. + # + # @param name [String] The zone name. + # @param zone [String] The zone. + # @param reference [String] The main name for the zone. + # @return [String|nil] The formatted alias. + def format_alias(name, zone, reference) + if zone.gsub("_", " ") == reference then + (["International Date Line West", "UTC"].include?(name) || name.include?("(US & Canada)")) ? name : reference.gsub(/\/.*/, "/#{name}") + else + nil + end + end end end \ No newline at end of file