Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally preserve timezone of parsed dates. #87

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`?
Expand Down
3 changes: 2 additions & 1 deletion lib/safe_yaml/load.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions lib/safe_yaml/parse/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions lib/safe_yaml/transform/to_date.rb
Original file line number Diff line number Diff line change
@@ -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
Expand Down