diff --git a/README.md b/README.md index a7b7bdc..b1ce0b7 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ The most important option is the `:safe` option (default: `true`), which control - `:raise_on_unknown_tag` (default: `false`): Represents the highest possible level of paranoia. If the YAML engine encounters any tag other than ones that are automatically trusted by SafeYAML or that you've explicitly whitelisted, it will raise an exception. This may be a good choice if you expect to always be dealing with perfectly safe YAML and want your application to fail loudly upon encountering questionable data. +- `:preserve_timezone` (default: `false`): By default, all dates are converted to the local timezone. If this is set to `true`, dates with timezone data attached retain that information. + All of the above options can be set at the global level via `SafeYAML::OPTIONS`. You can also set each one individually per call to `YAML.load`; an option explicitly passed to `load` will take precedence over an option specified globally. What if I don't *want* to patch `YAML`? diff --git a/lib/safe_yaml/load.rb b/lib/safe_yaml/load.rb index 5ea0f60..eba27f5 100644 --- a/lib/safe_yaml/load.rb +++ b/lib/safe_yaml/load.rb @@ -32,7 +32,8 @@ module SafeYAML :deserialize_symbols => false, :whitelisted_tags => [], :custom_initializers => {}, - :raise_on_unknown_tag => false + :raise_on_unknown_tag => false, + :preserve_timezone => false }) OPTIONS = Deep.copy(DEFAULT_OPTIONS) diff --git a/lib/safe_yaml/parse/date.rb b/lib/safe_yaml/parse/date.rb index cd3c62a..4ce8a28 100644 --- a/lib/safe_yaml/parse/date.rb +++ b/lib/safe_yaml/parse/date.rb @@ -21,14 +21,16 @@ class Date # Before that we'll just need to convert DateTime to Time ourselves. TO_TIME_AVAILABLE = DateTime.instance_methods.include?(:to_time) - def self.value(value) + def self.value(value, preserve_timezone) d = DateTime.parse(value) - return d.to_time if TO_TIME_AVAILABLE + if TO_TIME_AVAILABLE + return preserve_timezone ? d.to_time.localtime(d.zone) : d.to_time + end usec = d.sec_fraction * SEC_FRACTION_MULTIPLIER time = Time.utc(d.year, d.month, d.day, d.hour, d.min, d.sec, usec) - (d.offset * SECONDS_PER_DAY) - time.getlocal + return preserve_timezone ? time : time.getlocal end end end diff --git a/lib/safe_yaml/transform/to_date.rb b/lib/safe_yaml/transform/to_date.rb index 4bfe552..d0f6d7d 100644 --- a/lib/safe_yaml/transform/to_date.rb +++ b/lib/safe_yaml/transform/to_date.rb @@ -1,9 +1,9 @@ module SafeYAML class Transform class ToDate - def transform?(value) + def transform?(value, options=SafeYAML::OPTIONS) return true, Date.parse(value) if Parse::Date::DATE_MATCHER.match(value) - return true, Parse::Date.value(value) if Parse::Date::TIME_MATCHER.match(value) + return true, Parse::Date.value(value, options[:preserve_timezone]) if Parse::Date::TIME_MATCHER.match(value) false rescue ArgumentError return true, value