Skip to content

Instantly share code, notes, and snippets.

@agius
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save agius/7d630e21e18a6b6dc5cb to your computer and use it in GitHub Desktop.
Save agius/7d630e21e18a6b6dc5cb to your computer and use it in GitHub Desktop.
Output timezone select in Rails with some data attrs for JS
var d = new Date();
var tz_offset = d.getTimezoneOffset(); // seconds, not ms, because Javascript
var tz_select = $('#tz-select');
var abbr = tz_select.find("option[data-offset='" + tz_offset + "']").data('abbreviation');
# Usage
# validates :event_time, time_is: { after_now: true }
# validates :last_event, time_is: { before_now: true }
# validates :event_time, time_is: { before: Time.zone.now - 5.days }
# validates :event_time, time_is: { after: Time.zone.now + 5.days }
class TimeIsValidator < ActiveModel::EachValidator
# ignore time differences smaller than one second
def compare(time_1, time_2)
return -1 if time_1 - time_2 < -1
return 1 if time_1 - time_2 > 1
return 0
end
def validate_each(record, attribute, value)
return unless value.present?
raise ArgumentError.new("No options specified for time_is: on #{record.class.name}") unless options.is_a?(Hash)
# use integers; otherwise Time tracks to the nanosecond, which can easily mess up tests
now = Time.zone.now
time_value = value
if options[:before_now] && time_value - now >= 1
record.errors[attribute] << "is not before now"
end
if options[:after_now] && time_value - now <= 1
record.errors[attribute] << "is not afer now"
end
if options[:now_or_earlier] && time_value - now >= 1
record.errors[attribute] << "is later than now"
end
if options[:now_or_later] && time_value - now <= -1
record.errors[attribute] << "is earlier than now"
end
if options[:before]
compare_to = options[:before]
compare_to = record.send(compare_to) if compare_to.is_a?(Symbol)
compare_to = compare_to.to_time
if time_value - compare_to >= -1
record.errors[attribute] << "is not before #{options[:before]}"
end
end
if options[:at_or_before]
compare_to = options[:at_or_before]
compare_to = record.send(compare_to) if compare_to.is_a?(Symbol)
compare_to = compare_to.to_time
if time_value - compare_to <= 1
record.errors[attribute] << "is not on or before #{options[:before]}"
end
end
if options[:after]
compare_to = options[:after]
compare_to = record.send(compare_to) if compare_to.is_a?(Symbol)
compare_to = compare_to.to_time
if time_value - compare_to <= 1
record.errors[attribute] << "is not after #{options[:before]}"
end
end
if options[:at_or_after]
compare_to = options[:at_or_after]
compare_to = record.send(compare_to) if compare_to.is_a?(Symbol)
compare_to = compare_to.to_time
if time_value - compare_to >= -1
record.errors[attribute] << "is not on or after #{options[:at_or_after]}"
end
end
end
end
# Usage
# expect(time_instance).to be_time(Time.zone.now)
# match times, but ignore differences smaller than one second.
# prevents race conditions in validation, expect() etc with times
# handy with TimeCop - https://github.com/travisjeffery/timecop
RSpec::Matchers.define :be_time do |expected|
match do |actual|
expected == actual || ((expected - actual) < 1 && (expected - actual) > -1)
end
failure_message do |actual|
format = '%b %-d, %Y %H:%M:%S %N %z'
"expected #{actual.strftime(format)} would be #{expected.strftime(format)}"
end
end
def time_zones_for_js(selected)
prev_offsets = []
html = ""
time_zones = ActiveSupport::TimeZone.us_zones.reverse
time_zones.each do |zone|
next if prev_offsets.include?(zone.utc_offset)
next unless zone.to_s =~ /Time/
html << "<option value='#{zone.name}'
data-abbreviation='#{zone.now.zone}'
data-offset='#{zone.tzinfo.period_for_utc(Time.now).utc_total_offset}'
{zone.name == selected ? 'selected=\'selected\'' : ''}>"
html << "(GMT#{zone.formatted_offset}) #{zone.tzinfo.friendly_identifier}"
html << "</option>"
prev_offsets << zone.utc_offset
end
html << "<option disabled='disabled'>--------------</option>"
ActiveSupport::TimeZone.all.each do |zone|
next if prev_offsets.include?(zone.name)
html << "<option value='#{zone.name}'
data-abbreviation='#{zone.now.zone}'
data-offset='#{zone.tzinfo.period_for_utc(Time.now).utc_total_offset}'
#{zone.to_s == selected ? 'selected=\'selected\'' : ''}>"
html << "(GMT#{zone.formatted_offset}) #{zone.tzinfo.friendly_identifier}"
html << "</option>"
prev_offsets << zone.utc_offset
end
end
@loopj
Copy link

loopj commented Jul 11, 2014

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment