ruh-roo 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +677 -0
  3. data/Gemfile +24 -0
  4. data/LICENSE +24 -0
  5. data/README.md +315 -0
  6. data/lib/roo/base.rb +607 -0
  7. data/lib/roo/constants.rb +7 -0
  8. data/lib/roo/csv.rb +141 -0
  9. data/lib/roo/errors.rb +11 -0
  10. data/lib/roo/excelx/cell/base.rb +108 -0
  11. data/lib/roo/excelx/cell/boolean.rb +30 -0
  12. data/lib/roo/excelx/cell/date.rb +28 -0
  13. data/lib/roo/excelx/cell/datetime.rb +107 -0
  14. data/lib/roo/excelx/cell/empty.rb +20 -0
  15. data/lib/roo/excelx/cell/number.rb +89 -0
  16. data/lib/roo/excelx/cell/string.rb +19 -0
  17. data/lib/roo/excelx/cell/time.rb +44 -0
  18. data/lib/roo/excelx/cell.rb +110 -0
  19. data/lib/roo/excelx/comments.rb +55 -0
  20. data/lib/roo/excelx/coordinate.rb +19 -0
  21. data/lib/roo/excelx/extractor.rb +39 -0
  22. data/lib/roo/excelx/format.rb +71 -0
  23. data/lib/roo/excelx/images.rb +26 -0
  24. data/lib/roo/excelx/relationships.rb +33 -0
  25. data/lib/roo/excelx/shared.rb +39 -0
  26. data/lib/roo/excelx/shared_strings.rb +151 -0
  27. data/lib/roo/excelx/sheet.rb +151 -0
  28. data/lib/roo/excelx/sheet_doc.rb +248 -0
  29. data/lib/roo/excelx/styles.rb +64 -0
  30. data/lib/roo/excelx/workbook.rb +63 -0
  31. data/lib/roo/excelx.rb +480 -0
  32. data/lib/roo/font.rb +17 -0
  33. data/lib/roo/formatters/base.rb +15 -0
  34. data/lib/roo/formatters/csv.rb +84 -0
  35. data/lib/roo/formatters/matrix.rb +23 -0
  36. data/lib/roo/formatters/xml.rb +31 -0
  37. data/lib/roo/formatters/yaml.rb +40 -0
  38. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  39. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  40. data/lib/roo/libre_office.rb +4 -0
  41. data/lib/roo/link.rb +34 -0
  42. data/lib/roo/open_office.rb +628 -0
  43. data/lib/roo/spreadsheet.rb +39 -0
  44. data/lib/roo/tempdir.rb +21 -0
  45. data/lib/roo/utils.rb +128 -0
  46. data/lib/roo/version.rb +3 -0
  47. data/lib/roo.rb +36 -0
  48. data/roo.gemspec +28 -0
  49. metadata +189 -0
data/lib/roo/csv.rb ADDED
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+ require "time"
5
+
6
+ # The CSV class can read csv files (must be separated with commas) which then
7
+ # can be handled like spreadsheets. This means you can access cells like A5
8
+ # within these files.
9
+ # The CSV class provides only string objects. If you want conversions to other
10
+ # types you have to do it yourself.
11
+ #
12
+ # You can pass options to the underlying CSV parse operation, via the
13
+ # :csv_options option.
14
+ module Roo
15
+ class CSV < Roo::Base
16
+ attr_reader :filename
17
+
18
+ # Returns an array with the names of the sheets. In CSV class there is only
19
+ # one dummy sheet, because a csv file cannot have more than one sheet.
20
+ def sheets
21
+ ["default"]
22
+ end
23
+
24
+ def cell(row, col, sheet = nil)
25
+ sheet ||= default_sheet
26
+ read_cells(sheet)
27
+ @cell[normalize(row, col)]
28
+ end
29
+
30
+ def celltype(row, col, sheet = nil)
31
+ sheet ||= default_sheet
32
+ read_cells(sheet)
33
+ @cell_type[normalize(row, col)]
34
+ end
35
+
36
+ def cell_postprocessing(_row, _col, value)
37
+ value
38
+ end
39
+
40
+ def csv_options
41
+ @options[:csv_options] || {}
42
+ end
43
+
44
+ def set_value(row, col, value, _sheet)
45
+ @cell[[row, col]] = value
46
+ end
47
+
48
+ def set_type(row, col, type, _sheet)
49
+ @cell_type[[row, col]] = type
50
+ end
51
+
52
+ private
53
+
54
+ TYPE_MAP = {
55
+ String => :string,
56
+ Float => :float,
57
+ Date => :date,
58
+ DateTime => :datetime,
59
+ }
60
+
61
+ def celltype_class(value)
62
+ TYPE_MAP[value.class]
63
+ end
64
+
65
+ def read_cells(sheet = default_sheet)
66
+ sheet ||= default_sheet
67
+ return if @cells_read[sheet]
68
+ row_num = 0
69
+ max_col_num = 0
70
+
71
+ each_row csv_options do |row|
72
+ row_num += 1
73
+ col_num = 0
74
+
75
+ row.each do |elem|
76
+ col_num += 1
77
+ coordinate = [row_num, col_num]
78
+ @cell[coordinate] = elem
79
+ @cell_type[coordinate] = celltype_class(elem)
80
+ end
81
+
82
+ max_col_num = col_num if col_num > max_col_num
83
+ end
84
+
85
+ set_row_count(sheet, row_num)
86
+ set_column_count(sheet, max_col_num)
87
+ @cells_read[sheet] = true
88
+ end
89
+
90
+ def each_row(options, &block)
91
+ if uri?(filename)
92
+ each_row_using_tempdir(options, &block)
93
+ else
94
+ csv_foreach(filename_or_stream, options, &block)
95
+ end
96
+ end
97
+
98
+ def each_row_using_tempdir(options, &block)
99
+ ::Dir.mktmpdir(Roo::TEMP_PREFIX, ENV["ROO_TMP"]) do |tmpdir|
100
+ tmp_filename = download_uri(filename, tmpdir)
101
+ csv_foreach(tmp_filename, options, &block)
102
+ end
103
+ end
104
+
105
+ def csv_foreach(path_or_io, options, &block)
106
+ if is_stream?(path_or_io)
107
+ ::CSV.new(path_or_io, **options).each(&block)
108
+ else
109
+ ::CSV.foreach(path_or_io, **options, &block)
110
+ end
111
+ end
112
+
113
+ def set_row_count(sheet, last_row)
114
+ @first_row[sheet] = 1
115
+ @last_row[sheet] = last_row
116
+ @last_row[sheet] = @first_row[sheet] if @last_row[sheet].zero?
117
+
118
+ nil
119
+ end
120
+
121
+ def set_column_count(sheet, last_col)
122
+ @first_column[sheet] = 1
123
+ @last_column[sheet] = last_col
124
+ @last_column[sheet] = @first_column[sheet] if @last_column[sheet].zero?
125
+
126
+ nil
127
+ end
128
+
129
+ def clean_sheet(sheet)
130
+ read_cells(sheet)
131
+
132
+ @cell.each_pair do |coord, value|
133
+ @cell[coord] = sanitize_value(value) if value.is_a?(::String)
134
+ end
135
+
136
+ @cleaned[sheet] = true
137
+ end
138
+
139
+ alias_method :filename_or_stream, :filename
140
+ end
141
+ end
data/lib/roo/errors.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Roo
2
+ # A base error class for Roo. Most errors thrown by Roo should inherit from
3
+ # this class.
4
+ class Error < StandardError; end
5
+
6
+ # Raised when Roo cannot find a header row that matches the given column
7
+ # name(s).
8
+ class HeaderRowNotFoundError < Error; end
9
+
10
+ class FileNotFound < Error; end
11
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "roo/helpers/default_attr_reader"
4
+
5
+ module Roo
6
+ class Excelx
7
+ class Cell
8
+ class Base
9
+ extend Roo::Helpers::DefaultAttrReader
10
+ attr_reader :cell_type, :cell_value, :value
11
+
12
+ # FIXME: I think style should be deprecated. Having a style attribute
13
+ # for a cell doesn't really accomplish much. It seems to be used
14
+ # when you want to export to excelx.
15
+ attr_reader_with_default default_type: :base, style: 1
16
+
17
+
18
+ # FIXME: Updating a cell's value should be able tochange the cell's type,
19
+ # but that isn't currently possible. This will cause weird bugs
20
+ # when one changes the value of a Number cell to a String. e.g.
21
+ #
22
+ # cell = Cell::Number(*args)
23
+ # cell.value = 'Hello'
24
+ # cell.formatted_value # => Some unexpected value
25
+ #
26
+ # Here are two possible solutions to such issues:
27
+ # 1. Don't allow a cell's value to be updated. Use a method like
28
+ # `Sheet.update_cell` instead. The simple solution.
29
+ # 2. When `cell.value = ` is called, use injection to try and
30
+ # change the type of cell on the fly. But deciding what type
31
+ # of value to pass to `cell.value=`. isn't always obvious. e.g.
32
+ # `cell.value = Time.now` should convert a cell to a DateTime,
33
+ # not a Time cell. Time cells would be hard to recognize because
34
+ # they are integers. This approach would require a significant
35
+ # change to the code as written. The complex solution.
36
+ #
37
+ # If the first solution is used, then this method should be
38
+ # deprecated.
39
+ attr_writer :value
40
+
41
+ def initialize(value, formula, excelx_type, style, link, coordinate)
42
+ @cell_value = value
43
+ @cell_type = excelx_type if excelx_type
44
+ @formula = formula if formula
45
+ @style = style unless style == 1
46
+ @coordinate = coordinate
47
+ @value = link ? Roo::Link.new(link, value) : value
48
+ end
49
+
50
+ def type
51
+ if formula?
52
+ :formula
53
+ elsif link?
54
+ :link
55
+ else
56
+ default_type
57
+ end
58
+ end
59
+
60
+ def formula?
61
+ !!(defined?(@formula) && @formula)
62
+ end
63
+
64
+ def link?
65
+ Roo::Link === @value
66
+ end
67
+
68
+ alias_method :formatted_value, :value
69
+
70
+ def to_s
71
+ formatted_value
72
+ end
73
+
74
+ # DEPRECATED: Please use link? instead.
75
+ def hyperlink
76
+ warn '[DEPRECATION] `hyperlink` is deprecated. Please use `link?` instead.'
77
+ link?
78
+ end
79
+
80
+ # DEPRECATED: Please use link? instead.
81
+ def link
82
+ warn '[DEPRECATION] `link` is deprecated. Please use `link?` instead.'
83
+ link?
84
+ end
85
+
86
+ # DEPRECATED: Please use cell_value instead.
87
+ def excelx_value
88
+ warn '[DEPRECATION] `excelx_value` is deprecated. Please use `cell_value` instead.'
89
+ cell_value
90
+ end
91
+
92
+ # DEPRECATED: Please use cell_type instead.
93
+ def excelx_type
94
+ warn '[DEPRECATION] `excelx_type` is deprecated. Please use `cell_type` instead.'
95
+ cell_type
96
+ end
97
+
98
+ def empty?
99
+ false
100
+ end
101
+
102
+ def presence
103
+ empty? ? nil : self
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Roo
4
+ class Excelx
5
+ class Cell
6
+ class Boolean < Cell::Base
7
+ attr_reader :value, :formula, :format, :cell_value, :coordinate
8
+
9
+ attr_reader_with_default default_type: :boolean, cell_type: :boolean
10
+
11
+ def initialize(value, formula, style, link, coordinate)
12
+ super(value, formula, nil, style, nil, coordinate)
13
+ @value = link ? Roo::Link.new(link, value) : create_boolean(value)
14
+ end
15
+
16
+ def formatted_value
17
+ value ? 'TRUE' : 'FALSE'
18
+ end
19
+
20
+ private
21
+
22
+ def create_boolean(value)
23
+ # FIXME: Using a boolean will cause methods like Base#to_csv to fail.
24
+ # Roo is using some method to ignore false/nil values.
25
+ value.to_i == 1
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ require 'date'
2
+
3
+ module Roo
4
+ class Excelx
5
+ class Cell
6
+ class Date < Roo::Excelx::Cell::DateTime
7
+ attr_reader :value, :formula, :format, :cell_type, :cell_value, :coordinate
8
+
9
+ attr_reader_with_default default_type: :date
10
+
11
+ def initialize(value, formula, excelx_type, style, link, base_date, coordinate)
12
+ # NOTE: Pass all arguments to the parent class, DateTime.
13
+ super
14
+ @format = excelx_type.last
15
+ @value = link ? Roo::Link.new(link, value) : create_date(base_date, value)
16
+ end
17
+
18
+ private
19
+
20
+ def create_datetime(_,_); end
21
+
22
+ def create_date(base_date, value)
23
+ base_date + value.to_i
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module Roo
6
+ class Excelx
7
+ class Cell
8
+ class DateTime < Cell::Base
9
+ SECONDS_IN_DAY = 60 * 60 * 24
10
+
11
+ attr_reader :value, :formula, :format, :cell_value, :coordinate
12
+
13
+ attr_reader_with_default default_type: :datetime
14
+
15
+ def initialize(value, formula, excelx_type, style, link, base_timestamp, coordinate)
16
+ super(value, formula, excelx_type, style, nil, coordinate)
17
+ @format = excelx_type.last
18
+ @value = link ? Roo::Link.new(link, value) : create_datetime(base_timestamp, value)
19
+ end
20
+
21
+ # Public: Returns formatted value for a datetime. Format's can be an
22
+ # standard excel format, or a custom format.
23
+ #
24
+ # Standard formats follow certain conventions. Date fields for
25
+ # days, months, and years are separated with hyhens or
26
+ # slashes ("-", /") (e.g. 01-JAN, 1/13/15). Time fields for
27
+ # hours, minutes, and seconds are separated with a colon (e.g.
28
+ # 12:45:01).
29
+ #
30
+ # If a custom format follows those conventions, then the custom
31
+ # format will be used for the a cell's formatted value.
32
+ # Otherwise, the formatted value will be in the following
33
+ # format: 'YYYY-mm-dd HH:MM:SS' (e.g. "2015-07-10 20:33:15").
34
+ #
35
+ # Examples
36
+ # formatted_value #=> '01-JAN'
37
+ #
38
+ # Returns a String representation of a cell's value.
39
+ def formatted_value
40
+ formatter = @format.downcase.split(' ').map do |part|
41
+ if (parsed_format = parse_date_or_time_format(part))
42
+ parsed_format
43
+ else
44
+ warn 'Unable to parse custom format. Using "YYYY-mm-dd HH:MM:SS" format.'
45
+ return @value.strftime('%F %T')
46
+ end
47
+ end.join(' ')
48
+
49
+ @value.strftime(formatter)
50
+ end
51
+
52
+ private
53
+
54
+ def parse_date_or_time_format(part)
55
+ date_regex = /(?<date>[dmy]+[\-\/][dmy]+([\-\/][dmy]+)?)/
56
+ time_regex = /(?<time>(\[?[h]\]?+:)?[m]+(:?ss|:?s)?)/
57
+
58
+ if part[date_regex] == part
59
+ formats = DATE_FORMATS
60
+ elsif part[time_regex]
61
+ formats = TIME_FORMATS
62
+ else
63
+ return false
64
+ end
65
+
66
+ part.gsub(/#{formats.keys.join('|')}/, formats)
67
+ end
68
+
69
+ DATE_FORMATS = {
70
+ 'yyyy' => '%Y', # Year: 2000
71
+ 'yy' => '%y', # Year: 00
72
+ # mmmmm => J-D
73
+ 'mmmm' => '%B', # Month: January
74
+ 'mmm' => '%^b', # Month: JAN
75
+ 'mm' => '%m', # Month: 01
76
+ 'm' => '%-m', # Month: 1
77
+ 'dddd' => '%A', # Day of the Week: Sunday
78
+ 'ddd' => '%^a', # Day of the Week: SUN
79
+ 'dd' => '%d', # Day of the Month: 01
80
+ 'd' => '%-d' # Day of the Month: 1
81
+ # '\\\\'.freeze => ''.freeze, # NOTE: Fixes a custom format's output.
82
+ }
83
+
84
+ TIME_FORMATS = {
85
+ 'hh' => '%H', # Hour (24): 01
86
+ 'h' => '%-k', # Hour (24): 1
87
+ # 'hh'.freeze => '%I'.freeze, # Hour (12): 08
88
+ # 'h'.freeze => '%-l'.freeze, # Hour (12): 8
89
+ 'mm' => '%M', # Minute: 01
90
+ # FIXME: is this used? Seems like 'm' is used for month, not minute.
91
+ 'm' => '%-M', # Minute: 1
92
+ 'ss' => '%S', # Seconds: 01
93
+ 's' => '%-S', # Seconds: 1
94
+ 'am/pm' => '%p', # Meridian: AM
95
+ '000' => '%3N', # Fractional Seconds: thousandth.
96
+ '00' => '%2N', # Fractional Seconds: hundredth.
97
+ '0' => '%1N' # Fractional Seconds: tenths.
98
+ }
99
+
100
+ def create_datetime(base_timestamp, value)
101
+ timestamp = (base_timestamp + (value.to_f.round(6) * SECONDS_IN_DAY)).round(0)
102
+ ::Time.at(timestamp).utc.to_datetime
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,20 @@
1
+
2
+ module Roo
3
+ class Excelx
4
+ class Cell
5
+ class Empty < Cell::Base
6
+ attr_reader :value, :formula, :format, :cell_type, :cell_value, :coordinate
7
+
8
+ attr_reader_with_default default_type: nil, style: nil
9
+
10
+ def initialize(coordinate)
11
+ @coordinate = coordinate
12
+ end
13
+
14
+ def empty?
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Roo
4
+ class Excelx
5
+ class Cell
6
+ class Number < Cell::Base
7
+ attr_reader :value, :formula, :format, :cell_value, :coordinate
8
+
9
+ # FIXME: change default_type to number. This will break brittle tests.
10
+ attr_reader_with_default default_type: :float
11
+
12
+ def initialize(value, formula, excelx_type, style, link, coordinate)
13
+ super
14
+ # FIXME: Excelx_type is an array, but the first value isn't used.
15
+ @format = excelx_type.last
16
+ @value = link ? Roo::Link.new(link, value) : create_numeric(value)
17
+ end
18
+
19
+ def create_numeric(number)
20
+ return number if Excelx::ERROR_VALUES.include?(number)
21
+ case @format
22
+ when /%/
23
+ Float(number)
24
+ when /\.0/
25
+ Float(number)
26
+ else
27
+ (number.include?('.') || (/\A[-+]?\d+E[-+]?\d+\z/i =~ number)) ? Float(number) : Integer(number, 10)
28
+ end
29
+ end
30
+
31
+ def formatted_value
32
+ return @cell_value if Excelx::ERROR_VALUES.include?(@cell_value)
33
+
34
+ formatter = generate_formatter(@format)
35
+ if formatter.is_a? Proc
36
+ formatter.call(@cell_value)
37
+ else
38
+ Kernel.format(formatter, @cell_value)
39
+ end
40
+ end
41
+
42
+ def generate_formatter(format)
43
+ # FIXME: numbers can be other colors besides red:
44
+ # [BLACK], [BLUE], [CYAN], [GREEN], [MAGENTA], [RED], [WHITE], [YELLOW], [COLOR n]
45
+ case format
46
+ when /^General$/i then '%.0f'
47
+ when '0' then '%.0f'
48
+ when /^(0+)$/ then "%0#{$1.size}d"
49
+ when /^0\.(0+)$/ then "%.#{$1.size}f"
50
+ when '#,##0' then number_format('%.0f')
51
+ when /^#,##0.(0+)$/ then number_format("%.#{$1.size}f")
52
+ when '0%'
53
+ proc do |number|
54
+ Kernel.format('%d%%', number.to_f * 100)
55
+ end
56
+ when '0.00%'
57
+ proc do |number|
58
+ Kernel.format('%.2f%%', number.to_f * 100)
59
+ end
60
+ when '0.00E+00' then '%.2E'
61
+ when '#,##0 ;(#,##0)' then number_format('%.0f', '(%.0f)')
62
+ when '#,##0 ;[Red](#,##0)' then number_format('%.0f', '[Red](%.0f)')
63
+ when '#,##0.00;(#,##0.00)' then number_format('%.2f', '(%.2f)')
64
+ when '#,##0.00;[Red](#,##0.00)' then number_format('%.2f', '[Red](%.2f)')
65
+ # FIXME: not quite sure what the format should look like in this case.
66
+ when '##0.0E+0' then '%.1E'
67
+ when "_-* #,##0.00\\ _€_-;\\-* #,##0.00\\ _€_-;_-* \"-\"??\\ _€_-;_-@_-" then number_format('%.2f', '-%.2f')
68
+ when '@' then proc { |number| number }
69
+ else
70
+ raise "Unknown format: #{format.inspect}"
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def number_format(formatter, negative_formatter = nil)
77
+ proc do |number|
78
+ if negative_formatter
79
+ formatter = number.to_i > 0 ? formatter : negative_formatter
80
+ number = number.to_f.abs
81
+ end
82
+
83
+ Kernel.format(formatter, number).reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,19 @@
1
+ module Roo
2
+ class Excelx
3
+ class Cell
4
+ class String < Cell::Base
5
+ attr_reader :value, :formula, :format, :cell_value, :coordinate
6
+
7
+ attr_reader_with_default default_type: :string, cell_type: :string
8
+
9
+ def initialize(value, formula, style, link, coordinate)
10
+ super(value, formula, nil, style, link, coordinate)
11
+ end
12
+
13
+ def empty?
14
+ value.empty?
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ require 'date'
2
+
3
+ module Roo
4
+ class Excelx
5
+ class Cell
6
+ class Time < Roo::Excelx::Cell::DateTime
7
+ attr_reader :value, :formula, :format, :cell_value, :coordinate
8
+
9
+ attr_reader_with_default default_type: :time
10
+
11
+ def initialize(value, formula, excelx_type, style, link, base_date, coordinate)
12
+ # NOTE: Pass all arguments to DateTime super class.
13
+ super
14
+ @format = excelx_type.last
15
+ @datetime = create_datetime(base_date, value)
16
+ @value = link ? Roo::Link.new(link, value) : (value.to_f * 86_400).round.to_i
17
+ end
18
+
19
+ def formatted_value
20
+ formatter = @format.gsub(/#{TIME_FORMATS.keys.join('|')}/, TIME_FORMATS)
21
+ @datetime.strftime(formatter)
22
+ end
23
+
24
+ alias_method :to_s, :formatted_value
25
+
26
+ private
27
+
28
+ # def create_datetime(base_date, value)
29
+ # date = base_date + value.to_f.round(6)
30
+ # datetime_string = date.strftime('%Y-%m-%d %H:%M:%S.%N')
31
+ # t = round_datetime(datetime_string)
32
+ #
33
+ # ::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
34
+ # end
35
+
36
+ # def round_datetime(datetime_string)
37
+ # /(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
38
+ #
39
+ # ::Time.new(yyyy.to_i, mm.to_i, dd.to_i, hh.to_i, mi.to_i, ss.to_r).round(0)
40
+ # end
41
+ end
42
+ end
43
+ end
44
+ end