pax_global_header 0000666 0000000 0000000 00000000064 13426410207 0014511 g ustar 00root root 0000000 0000000 52 comment=23dd2ad90aa3968728339470d5196931b3cd21a8
timeliness-0.3.10/ 0000775 0000000 0000000 00000000000 13426410207 0013746 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/.gitignore 0000664 0000000 0000000 00000000072 13426410207 0015735 0 ustar 00root root 0000000 0000000 pkg/*
.bundle/
vendor/bundle
Gemfile.lock
.byebug_history
timeliness-0.3.10/.rspec 0000664 0000000 0000000 00000000113 13426410207 0015056 0 ustar 00root root 0000000 0000000 --color
--require byebug
--require spec_helper
--require timeliness_helper
timeliness-0.3.10/.travis.yml 0000664 0000000 0000000 00000000150 13426410207 0016053 0 ustar 00root root 0000000 0000000 language: ruby
rvm:
- 1.9.3
- ruby-head
- jruby-19mode
- rbx-19mode
script: 'bundle exec rspec'
timeliness-0.3.10/CHANGELOG.rdoc 0000664 0000000 0000000 00000003076 13426410207 0016114 0 ustar 00root root 0000000 0000000 = 0.3.7 - 2012-10-03
* Change to a hot switch between US and Euro formats without a compile.
* Fix date parsing with bad month name defaulting to 1 if year and day present.
* Fix date parsing with nil month.
= 0.3.6 - 2012-03-29
* Fix bug with month_index using Integer method and leading zeroes treated as octal.
= 0.3.5 - 2012-03-29
* Correctly handle month value of 0. Fixes issue#4.
= 0.3.4 - 2011-05-26
* Compact time array when creating time in zone so that invalid time handling works properly. Fixes issue#3.
= 0.3.3 - 2011-01-02
* Add String core extension for to_time, to_date and to_datetime methods, like ActiveSupport
* Allow arbitrary format string as :format option and it will be compiled, if not found.
= 0.3.2 - 2010-11-26
* Catch all errors for ActiveSupport not being loaded for more helpful error
= 0.3.1 - 2010-11-27
* Fix issue with 2nd argument options being overidden
= 0.3.0 - 2010-11-27
* Support for parsed timezone offset or abbreviation being used in creating time value
* Added timezone abbreviation mapping config option
* Allow 2nd argument for parse method to be the type, :now value, or options hash.
* Refactoring
= 0.2.0 - 2010-10-27
* Allow a lambda for date_for_time_type which is evaluated on parse
* Return the offset or zone in array from _parse
* Give a nicer error message if use a zone and ActiveSupport is not loaded.
* Removed some aliases used in validates_timeliness and are no longer needed.
* Some minor spec fixes
= 0.1.1 - 2010-10-14
* Alias for validates_timeliness compatibility
* Tiny cleanup
= 0.1.0 - 2010-10-14
* Initial release
timeliness-0.3.10/Gemfile 0000664 0000000 0000000 00000000124 13426410207 0015236 0 ustar 00root root 0000000 0000000 source 'http://rubygems.org'
gemspec
gem 'activesupport', '~> 4.2.0'
gem 'byebug'
timeliness-0.3.10/LICENSE 0000664 0000000 0000000 00000002037 13426410207 0014755 0 ustar 00root root 0000000 0000000 Copyright (c) 2010 Adam Meehan
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.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
timeliness-0.3.10/README.rdoc 0000664 0000000 0000000 00000024353 13426410207 0015563 0 ustar 00root root 0000000 0000000 = Timeliness
* Source: http://github.com/adzap/timeliness
* Bugs: http://github.com/adzap/timeliness/issues
== Description
Date/time parser for Ruby with the following features:
* Extensible with custom formats and tokens.
* It's pretty fast. Up to 60% faster than Time/Date parse method.
* Control the parser strictness.
* Control behaviour of ambiguous date formats (US vs European e.g. mm/dd/yy, dd/mm/yy).
* I18n support (for months), if I18n gem loaded.
* Fewer WTFs than Time/Date parse method.
* Has no dependencies.
* Works with Ruby MRI 1.8.*, 1.9.2, Rubinius and JRuby.
Extracted from the {validates_timeliness gem}[http://github.com/adzap/validates_timeliness], it has been rewritten cleaner and much faster. It's most suitable for when
you need to control the parsing behaviour. It's faster than the Time/Date class parse methods, so it
has general appeal.
== Usage
The simplest example is just a straight forward string parse:
Timeliness.parse('2010-09-08 12:13:14') #=> Wed Sep 08 12:13:14 1000 2010
Timeliness.parse('2010-09-08') #=> Wed Sep 08 00:00:00 1000 2010
Timeliness.parse('12:13:14') #=> Sat Jan 01 12:13:14 1100 2000
=== Specify a Type
You can provide a type which will tell the parser that you are only interested in the part of
the value for that type.
Timeliness.parse('2010-09-08 12:13:14', :date) #=> Wed Sep 08 00:00:00 1000 2010
Timeliness.parse('2010-09-08 12:13:14', :time) #=> Sat Jan 01 12:13:14 1100 2000
Timeliness.parse('2010-09-08 12:13:14', :datetime) #=> Wed Sep 08 12:13:14 1000 2010 i.e. the whole string is used
Now let's get strict. Pass the :strict option with true and things get finicky
Timeliness.parse('2010-09-08 12:13:14', :date, :strict => true) #=> nil
Timeliness.parse('2010-09-08 12:13:14', :time, :strict => true) #=> nil
Timeliness.parse('2010-09-08 12:13:14', :datetime, :strict => true) #=> Wed Sep 08 12:13:14 1000 2010 i.e. the whole string is used
The date and time strings are not accepted for a datetime type. The strict option without a type is
ignored.
=== Specify the Current Date
Notice a time only string will return with a date value. The date value can be configured globally
with this setting:
Timeliness.date_for_time_type = [2010, 1, 1]
or using a lambda thats evaluated when parsed
Timeliness.date_for_time_type = lambda { Time.now }
It can also be specified with :now option:
Timeliness.parse('12:13:14', :now => Time.mktime(2010,9,8)) #=> Wed Sep 08 12:13:14 1000 2010
As well conforming to the Ruby Time class style.
Timeliness.parse('12:13:14', Time.mktime(2010,9,8)) #=> Wed Sep 08 12:13:14 1000 2010
=== Timezone
To control what zone the time object is returned in, you have two options. Firstly you can set the
default zone. Below is the list of options with their effective time creation method call
Timeliness.default_timezone = :local # Time.local(...)
Timeliness.default_timezone = :utc # Time.utc(...)
Timeliness.default_timezone = :current # Time.zone.local(...). Use current zone.
Timeliness.default_timezone = 'Melbourne' # Time.use_zone('Melbourne') { Time.zone.local(...) }. Doesn't change Time.zone.
The last two options require that you have ActiveSupport timezone extension loaded.
You can also use the :zone option to control it for a single parse call:
Timeliness.parse('2010-09-08 12:13:14', :zone => :utc) #=> Wed Sep 08 12:13:14 UTC 2010
Timeliness.parse('2010-09-08 12:13:14', :zone => :local) #=> Wed Sep 08 12:13:14 1000 2010
Timeliness.parse('2010-09-08 12:13:14', :zone => :current) #=> Wed Sep 08 12:13:14 1000 2010, with Time.zone = 'Melbourne'
Timeliness.parse('2010-09-08 12:13:14', :zone => 'Melbourne') #=> Wed Sep 08 12:13:14 1000 2010
Remember, you must have ActiveSupport timezone extension loaded to use the last two examples.
=== Restrict to Format
To get super finicky, you can restrict the parsing to a single format with the :format option
Timeliness.parse('2010-09-08 12:13:14', :format => 'yyyy-mm-dd hh:nn:ss') #=> Wed Sep 08 12:13:14 UTC 2010
Timeliness.parse('08/09/2010 12:13:14', :format => 'yyyy-mm-dd hh:nn:ss') #=> nil
=== String with Offset or Zone Abbreviations
Sometimes you may want to parse a string with a zone abbreviation (e.g. MST) or the zone offset (e.g. +1000).
These values are supported by the parser and will be used when creating the time object. The return value
will be in the default timezone or the zone specified with the :zone option.
Timeliness.parse('Wed, 08 Sep 2010 12:13:14 MST') => Thu, 09 Sep 2010 05:13:14 EST 10:00
Timeliness.parse('2010-09-08T12:13:14-06:00') => Thu, 09 Sep 2010 05:13:14 EST 10:00
To enable zone abbreviations to work you must have loaded ActiveSupport.
The zone abbreviations supported are those defined in the TzInfo gem, used by ActiveSupport. If you find some
that are missing you can add more:
Timeliness.timezone_mapping.update(
'ZZZ' => 'Sleepy Town'
)
Where 'Sleepy Town' is a valid zone name supported by ActiveSupport/TzInfo.
=== Raw Parsed Values
If you would like to get the raw array of values before the time object is created, you can with
Timeliness._parse('2010-09-08 12:13:14.123456 MST') # => [2010, 9, 8, 12, 13, 14, 123456, 'MST']
The last two value are the microseconds, and zone abbreviation or offset.
Note: The format for this value is not defined. You can add it yourself, easily.
=== ActiveSupport Core Extensions
To make it easier to use the parser in Rails or an app using ActiveSupport, you can add/override the methods
for to_time, to_date and to_datetime on a string value. These methods will then use
the Timeliness parser for converting a string, instead of the default.
You just need to add this line to an initializer or other application file:
require 'timeliness/core_ext'
== Formats
The gem has default formats included which can be easily added to using the format syntax. Also
formats can be easily removed so that they are no longer considered valid.
Below are the default formats. If you think they are easy to read then you will be happy to know
that is exactly the same format syntax you can use to define your own. No complex regular
expressions are needed.
=== Datetime formats
m/d/yy h:nn:ss OR d/m/yy hh:nn:ss
m/d/yy h:nn OR d/m/yy h:nn
m/d/yy h:nn_ampm OR d/m/yy h:nn_ampm
yyyy-mm-dd hh:nn:ss
yyyy-mm-dd h:nn
ddd mmm d hh:nn:ss zo yyyy # Ruby time string
yyyy-mm-ddThh:nn:ssZ # ISO 8601 without zone offset
yyyy-mm-ddThh:nn:sszo # ISO 8601 with zone offset
NOTE: To use non-US date formats see US/Euro Formats section
=== Date formats
yyyy/mm/dd
yyyy-mm-dd
yyyy.mm.dd
m/d/yy OR d/m/yy
m\d\yy OR d\m\yy
d-m-yy
dd-mm-yyyy
d.m.yy
d mmm yy
NOTE: To use non-US date formats see US/Euro Formats section
=== Time formats
hh:nn:ss
hh-nn-ss
h:nn
h.nn
h nn
h-nn
h:nn_ampm
h.nn_ampm
h nn_ampm
h-nn_ampm
h_ampm
NOTE: Any time format without a meridian token (the 'ampm' token) is considered in 24 hour time.
=== Format Tokens
Here is what each format token means:
Format tokens:
y = year
m = month
d = day
h = hour
n = minute
s = second
u = micro-seconds
ampm = meridian (am or pm) with or without dots (e.g. am, a.m, or a.m.)
_ = optional space
tz = Timezone abbreviation (e.g. UTC, GMT, PST, EST)
zo = Timezone offset (e.g. +10:00, -08:00, +1000)
Repeating tokens:
x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
Special Cases:
yy = 2 or 4 digit year
yyyy = exactly 4 digit year
mmm = month long name (e.g. 'Jul' or 'July')
ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
u = microseconds matches 1 to 3 digits
All other characters are considered literal. For the technically minded, these formats are compiled
into a single regular expression
To see all defined formats look at the {source code}[http://github.com/adzap/timeliness/tree/master/lib/timeliness/formats.rb].
== Settings
=== US/Euro Formats
The perennial problem for non-US developers or applications not primarily for the US, is the US date
format of m/d/yy. This is ambiguous with the European format of d/m/yy. By default the gem uses the
US formats as this is the Ruby default
when it does date interpretation.
To switch to using the European (or Rest of The World) formats use this setting
Timeliness.use_euro_formats
Now '01/02/2000' will be parsed as 1st February 2000, instead of 2nd January 2000.
You can switch back to US formats with
Timeliness.use_us_formats
=== Customising Formats
Sometimes you may not want certain formats to be valid. You can remove formats for each type and the
parser will then not consider that a valid format. To remove a format
Timeliness.remove_formats(:date, 'm\d\yy')
Adding new formats is also simple
Timeliness.add_formats(:time, "h o'clock")
Now "10 o'clock" will be a valid value.
You can embed regular expressions in the format but no guarantees that it will remain intact. If
you avoid the use of any token characters, and regexp dots or backslashes as special characters in
the regexp, it may work as expected. For special characters use POSIX character classes for safety.
See the ISO 8601 datetime for an example of an embedded regular expression.
Because formats are evaluated in order, adding a format which may be ambiguous with an existing
format, will mean your format is ignored. If you need to make your new format higher precedence than
an existing format, you can include the before option like so
Timeliness.add_formats(:time, 'ss:nn:hh', :before => 'hh:nn:ss')
Now a time of '59:30:23' will be interpreted as 11:30:59 pm. This option saves you adding a new one
and deleting an old one to get it to work.
=== Ambiguous Year
When dealing with 2 digit year values, by default a year is interpreted as being in the last century
when at or above 30. You can customize this however
Timeliness.ambiguous_year_threshold = 20
Now you get:
year of 19 is considered 2019
year of 20 is considered 1920
== Credits
* Adam Meehan (adam.meehan@gmail.com, http://github.com/adzap)
== License
Copyright (c) 2010 Adam Meehan, released under the MIT license
timeliness-0.3.10/Rakefile 0000664 0000000 0000000 00000001142 13426410207 0015411 0 ustar 00root root 0000000 0000000 require 'bundler'
Bundler::GemHelper.install_tasks
require 'rdoc/task'
require 'rspec/core/rake_task'
desc "Run specs"
RSpec::Core::RakeTask.new(:spec)
desc "Generate code coverage"
RSpec::Core::RakeTask.new(:coverage) do |t|
t.rcov = true
t.rcov_opts = ['--exclude', 'spec']
end
desc 'Generate documentation for plugin.'
Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Timeliness'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
desc 'Default: run specs.'
task :default => :spec
timeliness-0.3.10/benchmark.rb 0000664 0000000 0000000 00000007173 13426410207 0016235 0 ustar 00root root 0000000 0000000 $:.unshift(File.expand_path('lib'))
require 'benchmark'
require 'time'
require 'parsedate' unless RUBY_VERSION =~ /^1\.9\./
require 'timeliness'
if defined?(JRUBY_VERSION)
# Warm up JRuby
20_000.times do
Time.parse("2000-01-04 12:12:12")
Timeliness::Parser.parse("2000-01-04 12:12:12", :datetime)
end
end
n = 10_000
Benchmark.bm do |x|
x.report('timeliness - datetime') {
n.times do
Timeliness::Parser.parse("2000-01-04 12:12:12", :datetime)
end
}
x.report('timeliness - datetime with :format') {
n.times do
Timeliness::Parser.parse("2000-01-04 12:12:12", :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
end
}
x.report('timeliness - date') {
n.times do
Timeliness::Parser.parse("2000-01-04", :date)
end
}
x.report('timeliness - date as datetime') {
n.times do
Timeliness::Parser.parse("2000-01-04", :datetime)
end
}
x.report('timeliness - time') {
n.times do
Timeliness::Parser.parse("12:01:02", :time)
end
}
x.report('timeliness - no type with datetime value') {
n.times do
Timeliness::Parser.parse("2000-01-04 12:12:12")
end
}
x.report('timeliness - no type with date value') {
n.times do
Timeliness::Parser.parse("2000-01-04")
end
}
x.report('timeliness - no type with time value') {
n.times do
Timeliness::Parser.parse("12:01:02")
end
}
x.report('timeliness - invalid format datetime') {
n.times do
Timeliness::Parser.parse("20xx-01-04 12:12:12", :datetime)
end
}
x.report('timeliness - invalid format date') {
n.times do
Timeliness::Parser.parse("20xx-01-04", :date)
end
}
x.report('timeliness - invalid format time') {
n.times do
Timeliness::Parser.parse("12:xx:02", :time)
end
}
x.report('timeliness - invalid value datetime') {
n.times do
Timeliness::Parser.parse("2000-01-32 12:12:12", :datetime)
end
}
x.report('timeliness - invalid value date') {
n.times do
Timeliness::Parser.parse("2000-01-32", :date)
end
}
x.report('timeliness - invalid value time') {
n.times do
Timeliness::Parser.parse("12:61:02", :time)
end
}
x.report('ISO regexp for datetime') {
n.times do
"2000-01-04 12:12:12" =~ /\A(\d{4})-(\d{2})-(\d{2}) (\d{2})[\. :](\d{2})([\. :](\d{2}))?\Z/
Time.mktime($1.to_i, $2.to_i, $3.to_i, $3.to_i, $5.to_i, $6.to_i)
end
}
x.report('Time.parse - valid') {
n.times do
Time.parse("2000-01-04 12:12:12")
end
}
x.report('Time.parse - invalid ') {
n.times do
Time.parse("2000-01-32 12:12:12") rescue nil
end
}
x.report('Date._parse - valid') {
n.times do
hash = Date._parse("2000-01-04 12:12:12")
Time.mktime(hash[:year], hash[:mon], hash[:mday], hash[:hour], hash[:min], hash[:sec])
end
}
x.report('Date._parse - invalid ') {
n.times do
hash = Date._parse("2000-01-32 12:12:12")
Time.mktime(hash[:year], hash[:mon], hash[:mday], hash[:hour], hash[:min], hash[:sex]) rescue nil
end
}
if defined?(ParseDate)
x.report('parsedate - valid') {
n.times do
arr = ParseDate.parsedate("2000-01-04 12:12:12")
Date.new(*arr[0..2])
Time.mktime(*arr)
end
}
x.report('parsedate - invalid ') {
n.times do
arr = ParseDate.parsedate("2000-00-04 12:12:12")
end
}
end
x.report('strptime - valid') {
n.times do
DateTime.strptime("2000-01-04 12:12:12", '%Y-%m-%d %H:%M:%s')
end
}
x.report('strptime - invalid') {
n.times do
DateTime.strptime("2000-00-04 12:12:12", '%Y-%m-%d %H:%M:%s') rescue nil
end
}
end
timeliness-0.3.10/lib/ 0000775 0000000 0000000 00000000000 13426410207 0014514 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/lib/timeliness.rb 0000664 0000000 0000000 00000002073 13426410207 0017217 0 ustar 00root root 0000000 0000000 require 'date'
require 'forwardable'
require 'timeliness/helpers'
require 'timeliness/definitions'
require 'timeliness/format'
require 'timeliness/format_set'
require 'timeliness/parser'
require 'timeliness/version'
module Timeliness
class << self
extend Forwardable
def_delegators Parser, :parse, :_parse
def_delegators Definitions, :add_formats, :remove_formats, :use_us_formats, :use_euro_formats
attr_accessor :default_timezone, :date_for_time_type, :ambiguous_year_threshold
end
# Default timezone. Options:
# - :local (default)
# - :utc
#
# If ActiveSupport loaded, also
# - :current
# - 'Zone name'
#
self.default_timezone = :local
# Set the default date part for a time type values.
#
self.date_for_time_type = lambda { Time.now }
# Set the threshold value for a two digit year to be considered last century
#
# Default: 30
#
# Example:
# year = '29' is considered 2029
# year = '30' is considered 1930
#
self.ambiguous_year_threshold = 30
end
Timeliness::Definitions.compile_formats
timeliness-0.3.10/lib/timeliness/ 0000775 0000000 0000000 00000000000 13426410207 0016670 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/lib/timeliness/core_ext.rb 0000664 0000000 0000000 00000000123 13426410207 0021021 0 ustar 00root root 0000000 0000000 require 'timeliness/core_ext/string'
module Timeliness
module CoreExt
end
end
timeliness-0.3.10/lib/timeliness/core_ext/ 0000775 0000000 0000000 00000000000 13426410207 0020500 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/lib/timeliness/core_ext/string.rb 0000664 0000000 0000000 00000001161 13426410207 0022332 0 ustar 00root root 0000000 0000000 class String
# Form can be either :utc (default) or :local.
def to_time(form = :utc)
return nil if self.blank?
Timeliness::Parser.parse(self, :datetime, :zone => form)
end
def to_date
return nil if self.blank?
values = Timeliness::Parser._parse(self, :date).map { |arg| arg || 0 }
::Date.new(*values[0..2])
end
def to_datetime
return nil if self.blank?
values = Timeliness::Parser._parse(self, :datetime).map { |arg| arg || 0 }
values[7] = values[7]/24.hours.to_f if values[7] != 0
values[5] += Rational(values.delete_at(6), 1000000)
::DateTime.civil(*values)
end
end
timeliness-0.3.10/lib/timeliness/definitions.rb 0000664 0000000 0000000 00000020676 13426410207 0021543 0 ustar 00root root 0000000 0000000 module Timeliness
module Definitions
# Format tokens:
# y = year
# m = month
# d = day
# h = hour
# n = minute
# s = second
# u = micro-seconds
# ampm = meridian (am or pm) with or without dots (e.g. am, a.m, or a.m.)
# _ = optional space
# tz = Timezone abbreviation (e.g. UTC, GMT, PST, EST)
# zo = Timezone offset (e.g. +10:00, -08:00, +1000)
#
# All other characters are considered literal. You can embed regexp in the
# format but no guarantees that it will remain intact. If you don't use capture
# groups, dots or backslashes in the regexp, it may well work as expected.
# For special characters, use POSIX character classes for safety.
#
# Repeating tokens:
# x = 1 or 2 digits for unit (e.g. 'h' means an hour can be '9' or '09')
# xx = 2 digits exactly for unit (e.g. 'hh' means an hour can only be '09')
#
# Special Cases:
# yy = 2 or 4 digit year
# yyyy = exactly 4 digit year
# mmm = month long name (e.g. 'Jul' or 'July')
# ddd = Day name of 3 to 9 letters (e.g. Wed or Wednesday)
# u = microseconds matches 1 to 6 digits
@time_formats = [
'hh:nn:ss',
'hh-nn-ss',
'h:nn',
'h.nn',
'h nn',
'h-nn',
'h:nn_ampm',
'h.nn_ampm',
'h nn_ampm',
'h-nn_ampm',
'h_ampm'
]
@date_formats = [
'yyyy-mm-dd',
'yyyy/mm/dd',
'yyyy.mm.dd',
'm/d/yy',
'd/m/yy',
'm\d\yy',
'd\m\yy',
'd-m-yy',
'dd-mm-yyyy',
'd.m.yy',
'd mmm yy'
]
@datetime_formats = [
'yyyy-mm-dd hh:nn:ss.u',
'yyyy-mm-dd hh:nn:ss',
'yyyy-mm-dd h:nn',
'yyyy-mm-dd h:nn_ampm',
'm/d/yy h:nn:ss',
'm/d/yy h:nn_ampm',
'm/d/yy h:nn',
'd/m/yy hh:nn:ss',
'd/m/yy h:nn_ampm',
'd/m/yy h:nn',
'dd-mm-yyyy hh:nn:ss',
'dd-mm-yyyy h:nn_ampm',
'dd-mm-yyyy h:nn',
'ddd, dd mmm yyyy hh:nn:ss tz', # RFC 822
'ddd, dd mmm yyyy hh:nn:ss zo', # RFC 822
'ddd mmm d hh:nn:ss zo yyyy', # Ruby time string
'yyyy-mm-ddThh:nn:ssZ', # ISO 8601 without zone offset
'yyyy-mm-ddThh:nn:sszo', # ISO 8601 with zone offset
'yyyy-mm-ddThh:nn:ss.u', # ISO 8601 with usec
'yyyy-mm-ddThh:nn:ss.uzo', # ISO 8601 with usec and offset
'yyyy-mm-dd hh:nn:ss zo', # Ruby time string in later versions
'yyyy-mm-dd hh:nn:ss tz', # Ruby time string for UTC in later versions
]
# All tokens available for format construction. The token array is made of
# regexp and key for format component mapping, if any.
#
@format_tokens = {
'ddd' => [ '\w{3,9}' ],
'dd' => [ '\d{2}', :day ],
'd' => [ '\d{1,2}', :day ],
'mmm' => [ '\w{3,9}', :month ],
'mm' => [ '\d{2}', :month ],
'm' => [ '\d{1,2}', :month ],
'yyyy' => [ '\d{4}', :year ],
'yy' => [ '\d{4}|\d{2}', :year ],
'hh' => [ '\d{2}', :hour ],
'h' => [ '\d{1,2}', :hour ],
'nn' => [ '\d{2}', :min ],
'n' => [ '\d{1,2}', :min ],
'ss' => [ '\d{2}', :sec ],
's' => [ '\d{1,2}', :sec ],
'u' => [ '\d{1,6}', :usec ],
'ampm' => [ '[aApP]\.?[mM]\.?', :meridian ],
'zo' => [ '[+-]\d{2}:?\d{2}', :offset ],
'tz' => [ '[A-Z]{1,5}', :zone ],
'_' => [ '\s?' ]
}
# Component argument values will be passed to the format method if matched in
# the time string. The key should match the key defined in the format tokens.
#
# The array consists of the position the value should be inserted in
# the time array, and the code to place in the time array.
#
# If the position is nil, then the value won't be put in the time array. If the
# code is nil, then just the raw value is used.
#
@format_components = {
:year => [ 0, 'unambiguous_year(year)'],
:month => [ 1, 'month_index(month)'],
:day => [ 2 ],
:hour => [ 3, 'full_hour(hour, meridian ||= nil)'],
:min => [ 4 ],
:sec => [ 5 ],
:usec => [ 6, 'microseconds(usec)'],
:offset => [ 7, 'offset_in_seconds(offset)'],
:zone => [ 7, 'zone'],
:meridian => [ nil ]
}
# Mapping some common timezone abbreviations which are not mapped or
# mapped inconsistenly in ActiveSupport (TzInfo).
#
@timezone_mapping = {
'AEST' => 'Australia/Sydney',
'AEDT' => 'Australia/Sydney',
'ACST' => 'Australia/Adelaide',
'ACDT' => 'Australia/Adelaide',
'PST' => 'PST8PDT',
'PDT' => 'PST8PDT',
'CST' => 'CST6CDT',
'CDT' => 'CST6CDT',
'EDT' => 'EST5EDT',
'MDT' => 'MST7MDT'
}
US_FORMAT_REGEXP = /\Am{1,2}[^m]/
FormatNotFound = Class.new(StandardError)
DuplicateFormat = Class.new(StandardError)
class << self
attr_accessor :time_formats, :date_formats, :datetime_formats, :format_tokens, :format_components, :timezone_mapping
attr_reader :date_format_set, :time_format_set, :datetime_format_set
# Adds new formats. Must specify format type and can specify a :before
# option to nominate which format the new formats should be inserted in
# front on to take higher precedence.
#
# Error is raised if format already exists or if :before format is not found.
#
def add_formats(type, *add_formats)
formats = send("#{type}_formats")
options = add_formats.last.is_a?(Hash) ? add_formats.pop : {}
before = options[:before]
raise FormatNotFound, "Format for :before option #{before.inspect} was not found." if before && !formats.include?(before)
add_formats.each do |format|
raise DuplicateFormat, "Format #{format.inspect} is already included in #{type.inspect} formats" if formats.include?(format)
index = before ? formats.index(before) : -1
formats.insert(index, format)
end
compile_formats
end
# Delete formats of specified type. Error raised if format not found.
#
def remove_formats(type, *remove_formats)
remove_formats.each do |format|
unless send("#{type}_formats").delete(format)
raise FormatNotFound, "Format #{format.inspect} not found in #{type.inspect} formats"
end
end
compile_formats
end
# Removes US date formats so that ambiguous dates are parsed as European format
#
def use_euro_formats
@date_format_set = @euro_date_format_set
@datetime_format_set = @euro_datetime_format_set
end
# Restores default to parse ambiguous dates as US format
#
def use_us_formats
@date_format_set = @us_date_format_set
@datetime_format_set = @us_datetime_format_set
end
def compile_formats
@sorted_token_keys = nil
@time_format_set = FormatSet.compile(time_formats)
@us_date_format_set = FormatSet.compile(date_formats)
@us_datetime_format_set = FormatSet.compile(datetime_formats)
@euro_date_format_set = FormatSet.compile(date_formats.select { |format| US_FORMAT_REGEXP !~ format })
@euro_datetime_format_set = FormatSet.compile(datetime_formats.select { |format| US_FORMAT_REGEXP !~ format })
@date_format_set = @us_date_format_set
@datetime_format_set = @us_datetime_format_set
end
def sorted_token_keys
@sorted_token_keys ||= format_tokens.keys.sort {|a,b| a.size <=> b.size }.reverse
end
# Returns format for type and other possible matching format set based on type
# and value length. Gives minor speed-up by checking string length.
#
def format_sets(type, string)
case type
when :date
[ @date_format_set, @datetime_format_set ]
when :datetime
if string.length < 11
[ @date_format_set, @datetime_format_set ]
else
[ @datetime_format_set, @date_format_set ]
end
when :time
if string.length < 11
[ @time_format_set ]
else
[ @datetime_format_set, @time_format_set ]
end
else
if string.length < 11
[ @date_format_set, @time_format_set, @datetime_format_set ]
else
[ @datetime_format_set, @date_format_set, @time_format_set ]
end
end
end
end
end
end
timeliness-0.3.10/lib/timeliness/format.rb 0000664 0000000 0000000 00000003653 13426410207 0020514 0 ustar 00root root 0000000 0000000 module Timeliness
class Format
include Helpers
CompilationFailed = Class.new(StandardError)
attr_reader :format_string, :regexp, :regexp_string, :token_count
def initialize(format_string)
@format_string = format_string
end
def compile!
@token_count = 0
format = format_string.dup
format.gsub!(/([\.\\])/, '\\\\\1') # escapes dots and backslashes
found_tokens, token_order = [], []
# Substitute tokens with numbered placeholder
Definitions.sorted_token_keys.each do |token|
token_regexp_str, arg_key = Definitions.format_tokens[token]
if format.gsub!(/#{token}/, "%<#{found_tokens.size}>")
if arg_key
token_regexp_str = "(#{token_regexp_str})"
@token_count += 1
end
found_tokens << [token_regexp_str, arg_key]
end
end
# Replace placeholders with token regexps
format.scan(/%<(\d)>/).each {|token_index|
token_index = token_index.first
token_regexp_str, arg_key = found_tokens[token_index.to_i]
format.gsub!("%<#{token_index}>", token_regexp_str)
token_order << arg_key
}
define_process_method(token_order.compact)
@regexp_string = format
@regexp = Regexp.new("^(#{format})$")
self
rescue => ex
raise CompilationFailed, "The format '#{format_string}' failed to compile using regexp string #{format}. Error message: #{ex.inspect}"
end
# Redefined on compile
def process(*args); end
private
def define_process_method(components)
values = [nil] * 8
components.each do |component|
position, code = Definitions.format_components[component]
values[position] = code || "#{component}.to_i" if position
end
instance_eval <<-DEF
def process(#{components.join(',')})
[#{values.map {|i| i || 'nil' }.join(',')}]
end
DEF
end
end
end
timeliness-0.3.10/lib/timeliness/format_set.rb 0000664 0000000 0000000 00000002613 13426410207 0021362 0 ustar 00root root 0000000 0000000 module Timeliness
class FormatSet
attr_reader :formats, :regexp
def self.compile(formats)
new(formats).compile!
end
def initialize(formats)
@formats = formats
@formats_hash = {}
@match_indexes = {}
end
# Compiles the formats into one big regexp. Stores the index of where
# each format's capture values begin in the matchdata.
def compile!
regexp_string = ''
@formats.inject(0) { |index, format_string|
format = Format.new(format_string).compile!
@formats_hash[format_string] = format
@match_indexes[index] = format
regexp_string = "#{regexp_string}(#{format.regexp_string})|"
index + format.token_count + 1 # add one for wrapper capture
}
@regexp = %r[\A(?:#{regexp_string.chop})\z]
self
end
def match(string, format_string=nil)
format = single_format(format_string) if format_string
match_regexp = format && format.regexp || @regexp
if match_data = match_regexp.match(string)
index = match_data.captures.index(string)
start = index + 1
values = match_data.captures[start..(start+7)].compact
format ||= @match_indexes[index]
format.process(*values)
end
end
def single_format(format_string)
@formats_hash.fetch(format_string) { Format.new(format_string).compile! }
end
end
end
timeliness-0.3.10/lib/timeliness/helpers.rb 0000664 0000000 0000000 00000002503 13426410207 0020657 0 ustar 00root root 0000000 0000000 module Timeliness
module Helpers
def full_hour(hour, meridian)
hour = hour.to_i
return hour if meridian.nil?
if meridian.delete('.').downcase == 'am'
raise(ArgumentError) if hour == 0 || hour > 12
hour == 12 ? 0 : hour
else
hour == 12 ? hour : hour + 12
end
end
def unambiguous_year(year)
if year.length <= 2
century = Time.now.year.to_s[0..1].to_i
century -= 1 if year.to_i >= Timeliness.ambiguous_year_threshold
year = "#{century}#{year.rjust(2,'0')}"
end
year.to_i
end
def month_index(month)
return month.to_i if month.to_i > 0 || /0+/ =~ month
month.length > 3 ? month_names.index(month.capitalize) : abbr_month_names.index(month.capitalize)
end
def month_names
i18n_loaded? ? I18n.t('date.month_names') : Date::MONTHNAMES
end
def abbr_month_names
i18n_loaded? ? I18n.t('date.abbr_month_names') : Date::ABBR_MONTHNAMES
end
def microseconds(usec)
(".#{usec}".to_f * 1_000_000).to_i
end
def offset_in_seconds(offset)
sign = offset =~ /^-/ ? -1 : 1
parts = offset.scan(/\d\d/).map {|p| p.to_f }
parts[1] = parts[1].to_f / 60
(parts[0] + parts[1]) * sign * 3600
end
def i18n_loaded?
defined?(I18n)
end
end
end
timeliness-0.3.10/lib/timeliness/parser.rb 0000664 0000000 0000000 00000012052 13426410207 0020511 0 ustar 00root root 0000000 0000000 module Timeliness
module Parser
class MissingTimezoneSupport < StandardError; end
class << self
def parse(value, *args)
return value if acts_like_temporal?(value)
return nil unless parseable?(value)
type, options = type_and_options_from_args(args)
time_array = _parse(value, type, options)
return nil if time_array.nil?
default_values_by_type(time_array, type, options) unless type == :datetime
make_time(time_array[0..7], options[:zone])
rescue NoMethodError => ex
raise ex unless ex.message =~ /undefined method `(zone|use_zone|current)' for Time:Class/
raise MissingTimezoneSupport, "ActiveSupport timezone support must be loaded to use timezones other than :utc and :local."
end
def make_time(time_array, zone_option=nil)
return nil unless fast_date_valid_with_fallback(*time_array[0..2])
zone, offset = zone_and_offset(time_array[7]) if time_array[7]
value = create_time_in_zone(time_array[0..6].compact, zone || zone_option)
value = shift_time_to_zone(value, zone_option) if zone
return nil unless value
offset ? value + (value.utc_offset - offset) : value
rescue ArgumentError, TypeError
nil
end
def _parse(string, type=nil, options={})
if options[:strict] && type
Definitions.send("#{type}_format_set").match(string, options[:format])
else
values = nil
Definitions.format_sets(type, string).find {|set| values = set.match(string, options[:format]) }
values
end
rescue
nil
end
private
def parseable?(value)
value.is_a?(String)
end
def acts_like_temporal?(value)
value.is_a?(Time) || value.is_a?(Date) || value.respond_to?(:acts_like_date?) || value.respond_to?(:acts_like_time?)
end
def type_and_options_from_args(args)
options = args.last.is_a?(Hash) ? args.pop : {}
type_or_now = args.first
if type_or_now.is_a?(Symbol)
type = type_or_now
elsif type_or_now
options[:now] = type_or_now
end
return type, options
end
def default_values_by_type(values, type, options)
case type
when :date
values[3..7] = nil
when :time
values[0..2] = current_date(options)
when nil
dummy_date = current_date(options)
values[0] ||= dummy_date[0]
values[1] ||= dummy_date[1] unless values.values_at(0,2).all?
values[2] ||= dummy_date[2]
end
end
def current_date(options)
now = if options[:now]
options[:now]
elsif options[:zone]
current_time_in_zone(options[:zone])
else
evaluate_date_for_time_type
end
now.is_a?(Array) ? now[0..2] : [now.year, now.month, now.day]
end
def current_time_in_zone(zone)
case zone
when :utc, :local
Time.now.send("get#{zone}")
when :current
Time.current
else
Time.use_zone(zone) { Time.current }
end
end
def shift_time_to_zone(time, zone=nil)
zone ||= Timeliness.default_timezone
case zone
when :utc, :local
time.send("get#{zone}")
when :current
time.in_time_zone
else
Time.use_zone(zone) { time.in_time_zone }
end
end
def create_time_in_zone(time_array, zone=nil)
zone ||= Timeliness.default_timezone
case zone
when :utc, :local
time_with_datetime_fallback(zone, *time_array)
when :current
Time.zone.local(*time_array)
else
Time.use_zone(zone) { Time.zone.local(*time_array) }
end
end
def zone_and_offset(parsed_value)
if parsed_value.is_a?(String)
zone = Definitions.timezone_mapping[parsed_value] || parsed_value
else
offset = parsed_value
end
return zone, offset
end
# Taken from ActiveSupport and simplified
def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
return nil if hour > 23 || min > 59 || sec > 59
::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
rescue
offset = utc_or_local == :local ? (::Time.local(2007).utc_offset.to_r/86400) : 0
::DateTime.civil(year, month, day, hour, min, sec, offset)
end
# Enforce strict date part validity which the Time class does not.
# Only does full date check if month and day are possibly invalid.
def fast_date_valid_with_fallback(year, month, day)
month && month < 13 && (day < 29 || Date.valid_civil?(year, month, day))
end
def evaluate_date_for_time_type
case Timeliness.date_for_time_type
when Array
Timeliness.date_for_time_type
when Proc
v = Timeliness.date_for_time_type.call
[v.year, v.month, v.day]
end
end
end
end
end
timeliness-0.3.10/lib/timeliness/version.rb 0000664 0000000 0000000 00000000053 13426410207 0020700 0 ustar 00root root 0000000 0000000 module Timeliness
VERSION = '0.3.10'
end
timeliness-0.3.10/spec/ 0000775 0000000 0000000 00000000000 13426410207 0014700 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/spec/spec_helper.rb 0000664 0000000 0000000 00000010575 13426410207 0017526 0 ustar 00root root 0000000 0000000 # This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# The `.rspec` file also contains a few flags that are not defaults but that
# users commonly want.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# These two settings work together to allow you to limit a spec run
# to individual examples or groups you care about by tagging them with
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
# get run.
config.filter_run :focus
config.run_all_when_everything_filtered = true
# Allows RSpec to persist some state between runs in order to support
# the `--only-failures` and `--next-failure` CLI options. We recommend
# you configure your source control system to ignore this file.
config.example_status_persistence_file_path = "spec/examples.txt"
# Limits the available syntax to the non-monkey patched syntax that is
# recommended. For more details, see:
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = 'doc'
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end
timeliness-0.3.10/spec/timeliness/ 0000775 0000000 0000000 00000000000 13426410207 0017054 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/spec/timeliness/core_ext/ 0000775 0000000 0000000 00000000000 13426410207 0020664 5 ustar 00root root 0000000 0000000 timeliness-0.3.10/spec/timeliness/core_ext/string_spec.rb 0000664 0000000 0000000 00000004460 13426410207 0023535 0 ustar 00root root 0000000 0000000 describe Timeliness::CoreExt, 'String' do
# Test values taken from ActiveSupport unit tests for compatibility
describe "#to_time" do
it 'should convert valid string to Time object in default zone' do
expect("2005-02-27 23:50".to_time).to eq Time.utc(2005, 2, 27, 23, 50)
end
it 'should convert ISO 8601 string to Time object' do
expect("2005-02-27T23:50:19.275038".to_time).to eq Time.utc(2005, 2, 27, 23, 50, 19, 275038)
end
context "with :local" do
it 'should convert valid string to local time' do
expect("2005-02-27 23:50".to_time(:local)).to eq Time.local(2005, 2, 27, 23, 50)
end
it 'should convert ISO 8601 string to local time' do
expect("2005-02-27T23:50:19.275038".to_time(:local)).to eq Time.local(2005, 2, 27, 23, 50, 19, 275038)
end
end
it 'should convert valid future string to Time object' do
expect("2039-02-27 23:50".to_time(:local)).to eq Time.local(2039, 2, 27, 23, 50)
end
it 'should convert valid future string to Time object' do
expect("2039-02-27 23:50".to_time).to eq DateTime.civil(2039, 2, 27, 23, 50)
end
it 'should convert empty string to nil' do
expect(''.to_time).to be_nil
end
end
describe "#to_datetime" do
it 'should convert valid string to DateTime object' do
expect("2039-02-27 23:50".to_datetime).to eq DateTime.civil(2039, 2, 27, 23, 50)
end
it 'should convert to DateTime object with UTC offset' do
expect("2039-02-27 23:50".to_datetime.offset).to eq 0
end
it 'should convert ISO 8601 string to DateTime object' do
datetime = DateTime.civil(2039, 2, 27, 23, 50, 19 + Rational(275038, 1000000), "-04:00")
expect("2039-02-27T23:50:19.275038-04:00".to_datetime).to eq datetime
end
it 'should use Rubys default start value' do
# Taken from ActiveSupport unit tests. Not sure on the implication.
expect("2039-02-27 23:50".to_datetime.start).to eq ::Date::ITALY
end
it 'should convert empty string to nil' do
expect(''.to_datetime).to be_nil
end
end
describe "#to_date" do
it 'should convert string to Date object' do
expect("2005-02-27".to_date).to eq Date.new(2005, 2, 27)
end
it 'should convert empty string to nil' do
expect(''.to_date).to be_nil
end
end
end
timeliness-0.3.10/spec/timeliness/definitions_spec.rb 0000664 0000000 0000000 00000006701 13426410207 0022732 0 ustar 00root root 0000000 0000000 describe Timeliness::Definitions do
context "add_formats" do
before do
@default_formats = definitions.time_formats.dup
end
it "should add format to format array" do
definitions.add_formats(:time, "h o'clock")
expect(definitions.time_formats).to include("h o'clock")
end
it "should parse new format after its added" do
should_not_parse("12 o'clock", :time)
definitions.add_formats(:time, "h o'clock")
should_parse("12 o'clock", :time)
end
it "should raise error if format exists" do
expect { definitions.add_formats(:time, "hh:nn:ss") }.to raise_error(Timeliness::Definitions::DuplicateFormat)
end
context "with :before option" do
it "should add new format with higher precedence" do
definitions.add_formats(:time, "ss:hh:nn", :before => 'hh:nn:ss')
time_array = parser._parse('59:23:58', :time)
expect(time_array).to eq [nil,nil,nil,23,58,59,nil,nil]
end
it "should raise error if :before format does not exist" do
expect { definitions.add_formats(:time, "ss:hh:nn", :before => 'nn:hh:ss') }.to raise_error(Timeliness::Definitions::FormatNotFound)
end
end
after do
definitions.time_formats = @default_formats
definitions.compile_formats
end
end
context "remove_formats" do
before do
@default_formats = definitions.time_formats.dup
end
it "should remove a single format from the formats array for type" do
definitions.remove_formats(:time, 'h.nn_ampm')
expect(definitions.time_formats).not_to include('h.nn_ampm')
end
it "should remove multiple formats from formats array for type" do
definitions.remove_formats(:time, 'h:nn', 'h.nn_ampm')
expect(definitions.time_formats).not_to include('h:nn')
expect(definitions.time_formats).not_to include('h.nn_ampm')
end
it "should prevent parsing of removed format" do
should_parse('2.12am', :time)
definitions.remove_formats(:time, 'h.nn_ampm')
should_not_parse('2.12am', :time)
end
it "should raise error if format does not exist" do
expect { definitions.remove_formats(:time, "ss:hh:nn") }.to raise_error(Timeliness::Definitions::FormatNotFound)
end
after do
definitions.time_formats = @default_formats
definitions.compile_formats
end
end
context "use_euro_formats" do
it "should allow ambiguous date to be parsed as European format" do
expect(parser._parse('01/02/2000', :date)).to eq [2000,1,2,nil,nil,nil,nil,nil]
definitions.use_euro_formats
expect(parser._parse('01/02/2000', :date)).to eq [2000,2,1,nil,nil,nil,nil,nil]
end
it "should not parse formats on switch to euro after initial compile" do
definitions.compile_formats
expect(Timeliness::FormatSet).not_to receive(:compile)
definitions.use_euro_formats
end
end
context "use_us_formats" do
before do
definitions.use_euro_formats
end
it "should allow ambiguous date to be parsed as European format" do
expect(parser._parse('01/02/2000', :date)).to eq [2000,2,1,nil,nil,nil,nil,nil]
definitions.use_us_formats
expect(parser._parse('01/02/2000', :date)).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
it "should not parse formats on switch to euro after initial compile" do
definitions.compile_formats
expect(Timeliness::FormatSet).not_to receive(:compile)
definitions.use_us_formats
end
end
end
timeliness-0.3.10/spec/timeliness/format_set_spec.rb 0000664 0000000 0000000 00000011233 13426410207 0022556 0 ustar 00root root 0000000 0000000 describe Timeliness::FormatSet do
context "#compile!" do
let(:set) { Timeliness::FormatSet.new(['yyyy-mm-dd', 'dd/mm/yyyy']) }
it 'should set the regexp for the set' do
set.compile!
expect(set.regexp).not_to be_nil
end
end
context "compiled regexp" do
context "for time formats" do
format_tests = {
'hh:nn:ss' => {:pass => ['12:12:12', '01:01:01'], :fail => ['1:12:12', '12:1:12', '12:12:1', '12-12-12']},
'hh-nn-ss' => {:pass => ['12-12-12', '01-01-01'], :fail => ['1-12-12', '12-1-12', '12-12-1', '12:12:12']},
'h:nn' => {:pass => ['12:12', '1:01'], :fail => ['12:2', '12-12']},
'h.nn' => {:pass => ['2.12', '12.12'], :fail => ['2.1', '12:12']},
'h nn' => {:pass => ['2 12', '12 12'], :fail => ['2 1', '2.12', '12:12']},
'h-nn' => {:pass => ['2-12', '12-12'], :fail => ['2-1', '2.12', '12:12']},
'h:nn_ampm' => {:pass => ['2:12am', '2:12 pm', '2:12 AM', '2:12PM'], :fail => ['1:2am', '1:12 pm', '2.12am']},
'h.nn_ampm' => {:pass => ['2.12am', '2.12 pm'], :fail => ['1:2am', '1:12 pm', '2:12am']},
'h nn_ampm' => {:pass => ['2 12am', '2 12 pm'], :fail => ['1 2am', '1 12 pm', '2:12am']},
'h-nn_ampm' => {:pass => ['2-12am', '2-12 pm'], :fail => ['1-2am', '1-12 pm', '2:12am']},
'h_ampm' => {:pass => ['2am', '2 am', '12 pm'], :fail => ['1.am', '12 pm', '2:12am']},
}
format_tests.each do |format, values|
it "should correctly match times in format '#{format}'" do
regexp = compile_regexp(format)
values[:pass].each {|value| expect(value).to match(regexp)}
values[:fail].each {|value| expect(value).not_to match(regexp)}
end
end
end
context "for date formats" do
format_tests = {
'yyyy/mm/dd' => {:pass => ['2000/02/01'], :fail => ['2000\02\01', '2000/2/1', '00/02/01']},
'yyyy-mm-dd' => {:pass => ['2000-02-01'], :fail => ['2000\02\01', '2000-2-1', '00-02-01']},
'yyyy.mm.dd' => {:pass => ['2000.02.01'], :fail => ['2000\02\01', '2000.2.1', '00.02.01']},
'm/d/yy' => {:pass => ['2/1/01', '02/01/00', '02/01/2000'], :fail => ['2/1/0', '2.1.01']},
'd/m/yy' => {:pass => ['1/2/01', '01/02/00', '01/02/2000'], :fail => ['1/2/0', '1.2.01']},
'm\d\yy' => {:pass => ['2\1\01', '2\01\00', '02\01\2000'], :fail => ['2\1\0', '2/1/01']},
'd\m\yy' => {:pass => ['1\2\01', '1\02\00', '01\02\2000'], :fail => ['1\2\0', '1/2/01']},
'd-m-yy' => {:pass => ['1-2-01', '1-02-00', '01-02-2000'], :fail => ['1-2-0', '1/2/01']},
'd.m.yy' => {:pass => ['1.2.01', '1.02.00', '01.02.2000'], :fail => ['1.2.0', '1/2/01']},
'd mmm yy' => {:pass => ['1 Feb 00', '1 Feb 2000', '1 February 00', '01 February 2000'],
:fail => ['1 Fe 00', 'Feb 1 2000', '1 Feb 0']}
}
format_tests.each do |format, values|
it "should correctly match dates in format '#{format}'" do
regexp = compile_regexp(format)
values[:pass].each {|value| expect(value).to match(regexp)}
values[:fail].each {|value| expect(value).not_to match(regexp)}
end
end
end
context "for datetime formats" do
format_tests = {
'ddd mmm d hh:nn:ss zo yyyy' => {:pass => ['Sat Jul 19 12:00:00 +1000 2008'], :fail => []},
'yyyy-mm-ddThh:nn:ss(?:Z|zo)' => {:pass => ['2008-07-19T12:00:00+10:00', '2008-07-19T12:00:00Z'], :fail => ['2008-07-19T12:00:00Z+10:00']},
}
format_tests.each do |format, values|
it "should correctly match datetimes in format '#{format}'" do
regexp = compile_regexp(format)
values[:pass].each {|value| expect(value).to match(regexp)}
values[:fail].each {|value| expect(value).not_to match(regexp)}
end
end
end
end
context "#match" do
let(:set) { Timeliness::FormatSet.compile(['yyyy-mm-dd', 'dd/mm/yyyy']) }
it 'should return array if string matches a format in set' do
expect(set.match('2000-01-02')).to be_kind_of(Array)
end
it 'should return nil if string does not matches a format in set' do
expect(set.match('2nd Feb 2000')).to be_nil
end
it 'should only use specific format string for match if provided' do
expect(set.match('2000-01-02', 'yyyy-mm-dd')).to be_kind_of(Array)
expect(set.match('2000-01-02', 'dd/mm/yyyy')).to be_nil
end
it 'should compile unknown format for one off match' do
expect(set.match('20001011')).to be_nil
expect(set.match('20001011', 'yyyymmdd')).to be_kind_of(Array)
end
end
def compile_regexp(format)
Timeliness::FormatSet.compile([format]).regexp
end
end
timeliness-0.3.10/spec/timeliness/format_spec.rb 0000664 0000000 0000000 00000010004 13426410207 0021676 0 ustar 00root root 0000000 0000000 describe Timeliness::Format do
describe "#compile!" do
it 'should compile valid string format' do
expect {
Timeliness::Format.new('yyyy-mm-dd hh:nn:ss.u zo').compile!
}.to_not raise_error
end
it 'should return self' do
format = Timeliness::Format.new('yyyy-mm-dd hh:nn:ss.u zo')
expect(format.compile!).to eq format
end
it 'should raise compilation error for bad format' do
expect {
Timeliness::Format.new('|--[)').compile!
}.to raise_error(Timeliness::Format::CompilationFailed)
end
end
describe "#process" do
it "should define method which outputs date array with values in correct order" do
expect(format_for('yyyy-mm-dd').process('2000', '1', '2')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
it "should define method which outputs date array from format with different order" do
expect(format_for('dd/mm/yyyy').process('2', '1', '2000')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
it "should define method which outputs date array with zeros when month and day are '0'" do
expect(format_for('m/d/yy').process('0', '0', '0000')).to eq [0,0,0,nil,nil,nil,nil,nil]
end
it "should define method which outputs date array with zeros when month and day are '00'" do
expect(format_for('m/d/yy').process('00', '00', '0000')).to eq [0,0,0,nil,nil,nil,nil,nil]
end
it "should define method which outputs time array" do
expect(format_for('hh:nn:ss').process('01', '02', '03')).to eq [nil,nil,nil,1,2,3,nil,nil]
end
it "should define method which outputs time array with meridian 'pm' adjusted hour" do
expect(format_for('hh:nn:ss ampm').process('01', '02', '03', 'pm')).to eq [nil,nil,nil,13,2,3,nil,nil]
end
it "should define method which outputs time array with meridian 'am' unadjusted hour" do
expect(format_for('hh:nn:ss ampm').process('01', '02', '03', 'am')).to eq [nil,nil,nil,1,2,3,nil,nil]
end
it "should define method which outputs time array with microseconds" do
expect(format_for('hh:nn:ss.u').process('01', '02', '03', '99')).to eq [nil,nil,nil,1,2,3,990000,nil]
end
it "should define method which outputs datetime array with zone offset" do
expect(format_for('yyyy-mm-dd hh:nn:ss.u zo').process('2001', '02', '03', '04', '05', '06', '99', '+10:00')).to eq [2001,2,3,4,5,6,990000,36000]
end
it "should define method which outputs datetime array with timezone string" do
expect(format_for('yyyy-mm-dd hh:nn:ss.u tz').process('2001', '02', '03', '04', '05', '06', '99', 'EST')).to eq [2001,2,3,4,5,6,990000,'EST']
end
context "with long month" do
let(:format) { format_for('dd mmm yyyy') }
context "with I18n loaded" do
before(:all) do
I18n.locale = :es
I18n.backend.store_translations :es, :date => { :month_names => %w{ ~ Enero Febrero Marzo } }
I18n.backend.store_translations :es, :date => { :abbr_month_names => %w{ ~ Ene Feb Mar } }
end
it 'should parse abbreviated month for current locale to correct value' do
expect(format.process('2', 'Ene', '2000')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
it 'should parse full month for current locale to correct value' do
expect(format.process('2', 'Enero', '2000')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
after(:all) do
I18n.locale = :en
end
end
context "without I18n loaded" do
before do
allow(format).to receive(:i18n_loaded?).and_return(false)
expect(I18n).not_to receive(:t)
end
it 'should parse abbreviated month to correct value' do
expect(format.process('2', 'Jan', '2000')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
it 'should parse full month to correct value' do
expect(format.process('2', 'January', '2000')).to eq [2000,1,2,nil,nil,nil,nil,nil]
end
end
end
end
def format_for(format)
Timeliness::Format.new(format).compile!
end
end
timeliness-0.3.10/spec/timeliness/parser_spec.rb 0000664 0000000 0000000 00000045323 13426410207 0021716 0 ustar 00root root 0000000 0000000 describe Timeliness::Parser do
before(:all) do
Timecop.freeze(2010,1,1,0,0,0)
end
describe "parse" do
it "should return Time object for valid datetime string" do
expect(parse("2000-01-01 12:13:14")).to be_kind_of(Time)
end
it "should return nil for empty string" do
expect(parse("")).to be_nil
end
it "should return nil for nil value" do
expect(parse(nil)).to be_nil
end
it "should return same value if value is a Time, Date, or DateTime" do
[Time.now, Date.new, DateTime.new].each do |value|
expect(parse(value)).to eq value
end
end
it "should return nil for non-string non-temporal values" do
[ {}, [], Class.new ].each do |value|
expect(parse(value)).to eq nil
end
end
it "should return time object for valid date string" do
expect(parse("2000-01-01")).to be_kind_of(Time)
end
it "should return nil for invalid date string" do
should_not_parse("2000-02-30")
end
it "should return nil for invalid date string where month is '0'" do
should_not_parse("0/01/2000")
end
it "should return nil for invalid date string where month is '00'" do
should_not_parse("00/01/2000")
end
it "should return nil for invalid date month string" do
should_not_parse("1 Foo 2000")
end
it "should return time object for valid time string" do
expect(parse("12:13:14")).to be_kind_of(Time)
end
it "should return nil for invalid time string" do
should_not_parse("25:00:00")
end
it "should return nil for datetime string with invalid date part" do
should_not_parse("2000-02-30 12:13:14")
end
it "should return nil for datetime string with invalid time part" do
should_not_parse("2000-02-01 25:13:14")
end
it 'should return nil for ISO 8601 string with invalid time part' do
should_not_parse("2000-02-01T25:13:14+02:00")
end
context "string with zone offset value" do
context "when current timezone is earler than string zone" do
before(:all) do
Timeliness.default_timezone = :current
Time.zone = 'Australia/Melbourne'
end
it 'should return value shifted by positive offset in default timezone' do
value = parse("2000-06-01T12:00:00+02:00")
expect(value).to eq Time.zone.local(2000,6,1,20,0,0)
expect(value.utc_offset).to eq 10.hours
end
it 'should return value shifted by negative offset in default timezone' do
value = parse("2000-06-01T12:00:00-01:00")
expect(value).to eq Time.zone.local(2000,6,1,23,0,0)
expect(value.utc_offset).to eq 10.hours
end
after(:all) do
Time.zone = nil
Timeliness.default_timezone = :local
end
end
context "when current timezone is later than string zone" do
before(:all) do
Timeliness.default_timezone = :current
Time.zone = 'America/Phoenix'
end
it 'should return value shifted by positive offset in default timezone' do
value = parse("2000-06-01T12:00:00+02:00")
expect(value).to eq Time.zone.local(2000,6,1,3,0,0)
expect(value.utc_offset).to eq -7.hours
end
it 'should return value shifted by negative offset in default timezone' do
value = parse("2000-06-01T12:00:00-01:00")
expect(value).to eq Time.zone.local(2000,6,1,6,0,0)
expect(value.utc_offset).to eq -7.hours
end
after(:all) do
Time.zone = nil
Timeliness.default_timezone = :local
end
end
end
context "string with zone abbreviation" do
before(:all) do
Time.zone = 'Australia/Melbourne'
end
it 'should return value using string zone adjusted to default :local timezone' do
Timeliness.default_timezone = :local
value = parse("Thu, 01 Jun 2000 03:00:00 MST")
expect(value).to eq Time.utc(2000,6,1,10,0,0).getlocal
expect(value.utc_offset).to eq Time.mktime(2000, 6, 1, 10, 0, 0).utc_offset
end
it 'should return value using string zone adjusted to default :current timezone' do
Timeliness.default_timezone = :current
Time.zone = 'Adelaide'
value = parse("Thu, 01 Jun 2000 03:00:00 MST")
expect(value).to eq Time.zone.local(2000,6,1,19,30,0)
expect(value.utc_offset).to eq 9.5.hours
end
it 'should return value using string zone adjusted to :zone option string timezone' do
Timeliness.default_timezone = :local
value = parse("Thu, 01 Jun 2000 03:00:00 MST", :zone => 'Perth')
expect(value).to eq Time.use_zone('Perth') { Time.zone.local(2000,6,1,18,0,0) }
expect(value.utc_offset).to eq 8.hours
end
after(:all) do
Time.zone = nil
end
end
context "with :datetime type" do
it "should return time object for valid datetime string" do
expect(parse("2000-01-01 12:13:14", :datetime)).to eq Time.local(2000,1,1,12,13,14)
end
it "should return nil for invalid date string" do
expect(parse("0/01/2000", :datetime)).to be_nil
end
end
context "with :date type" do
it "should return time object for valid date string" do
expect(parse("2000-01-01", :date)).to eq Time.local(2000,1,1)
end
it "should ignore time in datetime string" do
expect(parse('2000-02-01 12:13', :date)).to eq Time.local(2000,2,1)
end
it "should return nil for invalid date string" do
expect(parse("0/01/2000", :date)).to be_nil
end
end
context "with :time type" do
it "should return time object with a dummy date values" do
expect(parse('12:13', :time)).to eq Time.local(2010,1,1,12,13)
end
it "should ignore date in datetime string" do
expect(parse('2010-02-01 12:13', :time)).to eq Time.local(2010,1,1,12,13)
end
it "should raise error if time hour is out of range for AM meridian" do
expect(parse('13:14 am', :time)).to be_nil
end
end
context "with :now option" do
it 'should use date parts if string does not specify' do
time = parse("12:13:14", :now => Time.local(2010,1,1))
expect(time).to eq Time.local(2010,1,1,12,13,14)
end
end
context "with time value argument" do
it 'should use argument as :now option value' do
time = parse("12:13:14", Time.local(2010,1,1))
expect(time).to eq Time.local(2010,1,1,12,13,14)
end
end
context "with :zone option" do
context ":utc" do
it "should return time object in utc timezone" do
time = parse("2000-06-01 12:13:14", :datetime, :zone => :utc)
expect(time.utc_offset).to eq 0
end
it 'should return nil for partial invalid time component' do
expect(parse("2000-06-01 12:60", :datetime, :zone => :utc)).to be_nil
end
end
context ":local" do
it "should return time object in local system timezone" do
time = parse("2000-06-01 12:13:14", :datetime, :zone => :local)
expect(time.utc_offset).to eq Time.mktime(2000, 6, 1, 12, 13, 14).utc_offset
end
it 'should return nil for partial invalid time component' do
expect(parse("2000-06-01 12:60", :datetime, :zone => :local)).to be_nil
end
end
context ":current" do
it "should return time object in current timezone" do
Time.zone = 'Adelaide'
time = parse("2000-06-01 12:13:14", :datetime, :zone => :current)
expect(time.utc_offset).to eq 9.5.hours
end
it 'should return nil for partial invalid time component' do
expect(parse("2000-06-01 12:60", :datetime, :zone => :current)).to be_nil
end
end
context "named zone" do
it "should return time object in the timezone" do
time = parse("2000-06-01 12:13:14", :datetime, :zone => 'London')
expect(time.utc_offset).to eq 1.hour
end
it 'should return nil for partial invalid time component' do
expect(parse("2000-06-01 12:60", :datetime, :zone => 'London')).to be_nil
end
end
context "without ActiveSupport loaded" do
it 'should output message' do
expect {
expect(Time).to receive(:zone).and_raise(NoMethodError.new("undefined method `zone' for Time:Class"))
parse("2000-06-01 12:13:14", :zone => :current)
}.to raise_error(Timeliness::Parser::MissingTimezoneSupport)
expect {
expect(Time).to receive(:current).and_raise(NoMethodError.new("undefined method `current' for Time:Class"))
parse("12:13:14", :zone => :current)
}.to raise_error(Timeliness::Parser::MissingTimezoneSupport)
expect {
expect(Time).to receive(:use_zone).and_raise(NoMethodError.new("undefined method `use_zone' for Time:Class"))
parse("2000-06-01 12:13:14", :zone => 'London')
}.to raise_error(Timeliness::Parser::MissingTimezoneSupport)
end
end
end
context "for time type" do
context "with date from date_for_time_type" do
before do
@original = Timeliness.date_for_time_type
end
it 'should return date array' do
Timeliness.date_for_time_type = [2010,1,1]
expect(parse('12:13:14', :time)).to eq Time.local(2010,1,1,12,13,14)
end
it 'should return date array evaluated lambda' do
Timeliness.date_for_time_type = lambda { Time.local(2010,2,1) }
expect(parse('12:13:14', :time)).to eq Time.local(2010,2,1,12,13,14)
end
after do
Timeliness.date_for_time_type = @original
end
end
context "with :now option" do
it 'should use date from :now' do
expect(parse('12:13:14', :time, :now => Time.local(2010, 6, 1))).to eq Time.local(2010,6,1,12,13,14)
end
end
context "with :zone option" do
before(:all) do
Timecop.return
@current_tz = ENV['TZ']
ENV['TZ'] = 'Australia/Melbourne'
Timecop.freeze(2010,1,1,0,0,0)
end
it "should use date from the specified zone" do
time = parse("12:13:14", :time, :zone => :utc)
expect(time.year).to eq 2009
expect(time.month).to eq 12
expect(time.day).to eq 31
end
after(:all) do
Timecop.return
ENV['TZ'] = @current_tz
Timecop.freeze(2010,1,1,0,0,0)
end
end
end
end
describe "_parse" do
context "with no type" do
it "should return date array from date string" do
time_array = parser._parse('2000-02-01')
expect(time_array).to eq [2000,2,1,nil,nil,nil,nil,nil]
end
it "should return time array from time string" do
time_array = parser._parse('12:13:14', :time)
expect(time_array).to eq [nil,nil,nil,12,13,14,nil,nil]
end
it "should return datetime array from datetime string" do
time_array = parser._parse('2000-02-01 12:13:14')
expect(time_array).to eq [2000,2,1,12,13,14,nil,nil]
end
end
context "with type" do
it "should return date array from date string" do
time_array = parser._parse('2000-02-01', :date)
expect(time_array).to eq [2000,2,1,nil,nil,nil,nil,nil]
end
it "should not return time array from time string for :date type" do
time_array = parser._parse('12:13:14', :date)
expect(time_array).to eq nil
end
it "should return time array from time string" do
time_array = parser._parse('12:13:14', :time)
expect(time_array).to eq [nil,nil,nil,12,13,14,nil,nil]
end
it "should not return date array from date string for :time type" do
time_array = parser._parse('2000-02-01', :time)
expect(time_array).to eq nil
end
it "should return datetime array from datetime string when type is date" do
time_array = parser._parse('2000-02-01 12:13:14', :date)
expect(time_array).to eq [2000,2,1,12,13,14,nil,nil]
end
it "should return date array from date string when type is datetime" do
time_array = parser._parse('2000-02-01', :datetime)
expect(time_array).to eq [2000,2,1,nil,nil,nil,nil,nil]
end
it "should not return time array from time string when type is datetime" do
time_array = parser._parse('12:13:14', :datetime)
expect(time_array).to eq nil
end
end
context "with :strict => true" do
it "should return nil from date string when type is datetime" do
time_array = parser._parse('2000-02-01', :datetime, :strict => true)
expect(time_array).to be_nil
end
it "should return nil from datetime string when type is date" do
time_array = parser._parse('2000-02-01 12:13:14', :date, :strict => true)
expect(time_array).to be_nil
end
it "should return nil from datetime string when type is time" do
time_array = parser._parse('2000-02-01 12:13:14', :time, :strict => true)
expect(time_array).to be_nil
end
it "should parse date string when type is date" do
time_array = parser._parse('2000-02-01', :date, :strict => true)
expect(time_array).not_to be_nil
end
it "should parse time string when type is time" do
time_array = parser._parse('12:13:14', :time, :strict => true)
expect(time_array).not_to be_nil
end
it "should parse datetime string when type is datetime" do
time_array = parser._parse('2000-02-01 12:13:14', :datetime, :strict => true)
expect(time_array).not_to be_nil
end
it "should ignore strict parsing if no type specified" do
time_array = parser._parse('2000-02-01', :strict => true)
expect(time_array).not_to be_nil
end
end
context "with :format option" do
it "should return values if string matches specified format" do
time_array = parser._parse('2000-02-01 12:13:14', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
expect(time_array).to eq [2000,2,1,12,13,14,nil,nil]
end
it "should return nil if string does not match specified format" do
time_array = parser._parse('2000-02-01 12:13', :datetime, :format => 'yyyy-mm-dd hh:nn:ss')
expect(time_array).to be_nil
end
end
context "date with ambiguous year" do
it "should return year in current century if year below threshold" do
time_array = parser._parse('01-02-29', :date)
expect(time_array).to eq [2029,2,1,nil,nil,nil,nil,nil]
end
it "should return year in last century if year at or above threshold" do
time_array = parser._parse('01-02-30', :date)
expect(time_array).to eq [1930,2,1,nil,nil,nil,nil,nil]
end
it "should allow custom threshold" do
default = Timeliness.ambiguous_year_threshold
Timeliness.ambiguous_year_threshold = 40
time_array = parser._parse('01-02-39', :date)
expect(time_array).to eq [2039,2,1,nil,nil,nil,nil,nil]
time_array = parser._parse('01-02-40', :date)
expect(time_array).to eq [1940,2,1,nil,nil,nil,nil,nil]
Timeliness.ambiguous_year_threshold = default
end
end
end
describe "make_time" do
it "should return time object for valid time array" do
time = parser.make_time([2010,9,8,12,13,14])
expect(time).to eq Time.local(2010,9,8,12,13,14)
end
it "should return nil for invalid date in array" do
time = parser.make_time([2010,13,8,12,13,14])
expect(time).to be_nil
end
it "should return nil for invalid time in array" do
time = parser.make_time([2010,9,8,25,13,14])
expect(time).to be_nil
end
it "should return nil for invalid time in array with timezone" do
time = parser.make_time([2010,9,8,25,13,14,0,1])
expect(time).to be_nil
end
context "default timezone" do
before do
@default_timezone = Timeliness.default_timezone
end
it "should be used if no zone value" do
Timeliness.default_timezone = :utc
time = parser.make_time([2000,6,1,12,0,0])
expect(time.utc_offset).to eq 0
end
after do
Timeliness.default_timezone = @default_timezone
end
end
context "with zone value" do
context ":utc" do
it "should return time object in utc timezone" do
time = parser.make_time([2000,6,1,12,0,0], :utc)
expect(time.utc_offset).to eq 0
end
end
context ":local" do
it "should return time object in local system timezone" do
time = parser.make_time([2000,6,1,12,0,0], :local)
expect(time.utc_offset).to eq Time.mktime(2000,6,1,12,0,0).utc_offset
end
end
context ":current" do
it "should return time object in current timezone" do
Time.zone = 'Adelaide'
time = parser.make_time([2000,6,1,12,0,0], :current)
expect(time.utc_offset).to eq 9.5.hours
end
end
context "named zone" do
it "should return time object in the timezone" do
time = parser.make_time([2000,6,1,12,0,0], 'London')
expect(time.utc_offset).to eq 1.hour
end
end
end
end
describe "current_date" do
context "with no options" do
it 'should return date_for_time_type values with no options' do
dummy_date = Timeliness.date_for_time_type.call
expect(current_date).to eq [ dummy_date.year, dummy_date.month, dummy_date.day ]
end
end
context "with :now option" do
it 'should return date array from Time value' do
time = Time.now
date_array = [time.year, time.month, time.day]
expect(current_date(:now => time)).to eq date_array
end
end
context "with :zone option" do
it 'should return date array for utc zone' do
time = Time.now.getutc
date_array = [time.year, time.month, time.day]
expect(current_date(:zone => :utc)).to eq date_array
end
it 'should return date array for local zone' do
time = Time.now
date_array = [time.year, time.month, time.day]
expect(current_date(:zone => :local)).to eq date_array
end
it 'should return date array for current zone' do
Time.zone = 'London'
time = Time.current
date_array = [time.year, time.month, time.day]
expect(current_date(:zone => :current)).to eq date_array
end
it 'should return date array for named zone' do
time = Time.use_zone('London') { Time.current }
date_array = [time.year, time.month, time.day]
expect(current_date(:zone => 'London')).to eq date_array
end
end
end
after(:all) do
Timecop.return
end
end
timeliness-0.3.10/spec/timeliness_helper.rb 0000664 0000000 0000000 00000001243 13426410207 0020740 0 ustar 00root root 0000000 0000000 require 'active_support/time'
require 'timecop'
require 'timeliness'
require 'timeliness/core_ext'
module TimelinessHelpers
def parser
Timeliness::Parser
end
def definitions
Timeliness::Definitions
end
def parse(*args)
Timeliness::Parser.parse(*args)
end
def current_date(options={})
Timeliness::Parser.send(:current_date, options)
end
def should_parse(*args)
expect(Timeliness::Parser.parse(*args)).not_to be_nil
end
def should_not_parse(*args)
expect(Timeliness::Parser.parse(*args)).to be_nil
end
end
I18n.available_locales = ['en', 'es']
RSpec.configure do |c|
c.mock_with :rspec
c.include TimelinessHelpers
end timeliness-0.3.10/timeliness.gemspec 0000664 0000000 0000000 00000002065 13426410207 0017472 0 ustar 00root root 0000000 0000000 # -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "timeliness/version"
Gem::Specification.new do |s|
s.name = "timeliness"
s.version = Timeliness::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["Adam Meehan"]
s.email = %q{adam.meehan@gmail.com}
s.homepage = %q{http://github.com/adzap/timeliness}
s.summary = %q{Date/time parsing for the control freak.}
s.description = %q{Fast date/time parser with customisable formats, timezone and I18n support.}
s.license = "MIT"
s.rubyforge_project = %q{timeliness}
s.add_development_dependency 'activesupport', '>= 3.2'
s.add_development_dependency 'tzinfo', '>= 0.3.31'
s.add_development_dependency 'rspec', '~> 3.4'
s.add_development_dependency 'timecop'
s.add_development_dependency 'i18n'
s.files = `git ls-files`.split("\n")
s.files = `git ls-files`.split("\n") - %w{ .gitignore .rspec Gemfile Gemfile.lock }
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc"]
s.require_paths = ["lib"]
end