groupdate2 4.1.5 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +58 -34
- data/CONTRIBUTING.md +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +43 -9
- data/lib/groupdate/active_record.rb +1 -0
- data/lib/groupdate/enumerable.rb +9 -15
- data/lib/groupdate/magic.rb +66 -8
- data/lib/groupdate/query_methods.rb +3 -10
- data/lib/groupdate/relation.rb +7 -0
- data/lib/groupdate/relation_builder.rb +64 -48
- data/lib/groupdate/series_builder.rb +107 -62
- data/lib/groupdate/sql_server_group_clause.rb +3 -3
- data/lib/groupdate/version.rb +1 -1
- data/lib/groupdate2.rb +14 -4
- metadata +45 -31
@@ -1,25 +1,18 @@
|
|
1
1
|
module Groupdate
|
2
2
|
module QueryMethods
|
3
3
|
Groupdate::PERIODS.each do |period|
|
4
|
-
define_method :"group_by_#{period}" do |field,
|
4
|
+
define_method :"group_by_#{period}" do |field, **options|
|
5
5
|
Groupdate::Magic::Relation.generate_relation(self,
|
6
6
|
period: period,
|
7
7
|
field: field,
|
8
|
-
time_zone: time_zone,
|
9
|
-
range: range,
|
10
8
|
**options
|
11
9
|
)
|
12
10
|
end
|
13
11
|
end
|
14
12
|
|
15
13
|
def group_by_period(period, field, permit: nil, **options)
|
16
|
-
|
17
|
-
|
18
|
-
if permitted_periods.include?(period.to_s)
|
19
|
-
send("group_by_#{period}", field, **options)
|
20
|
-
else
|
21
|
-
raise ArgumentError, "Unpermitted period"
|
22
|
-
end
|
14
|
+
Groupdate::Magic.validate_period(period, permit)
|
15
|
+
send("group_by_#{period}", field, **options)
|
23
16
|
end
|
24
17
|
end
|
25
18
|
end
|
data/lib/groupdate/relation.rb
CHANGED
@@ -3,9 +3,9 @@ require_relative 'sql_server_group_clause'
|
|
3
3
|
module Groupdate
|
4
4
|
class RelationBuilder
|
5
5
|
include SqlServerGroupClause
|
6
|
-
attr_reader :period, :column, :day_start, :week_start
|
6
|
+
attr_reader :period, :column, :day_start, :week_start, :series_label
|
7
7
|
|
8
|
-
def initialize(relation, column:, period:, time_zone:, time_range:, week_start:, day_start:)
|
8
|
+
def initialize(relation, column:, period:, time_zone:, time_range:, week_start:, day_start:, series_label:)
|
9
9
|
@relation = relation
|
10
10
|
@column = resolve_column(relation, column)
|
11
11
|
@period = period
|
@@ -13,6 +13,7 @@ module Groupdate
|
|
13
13
|
@time_range = time_range
|
14
14
|
@week_start = week_start
|
15
15
|
@day_start = day_start
|
16
|
+
@series_label = series_label
|
16
17
|
|
17
18
|
if relation.default_timezone == :local
|
18
19
|
raise Groupdate::Error, "ActiveRecord::Base.default_timezone must be :utc to use Groupdate"
|
@@ -20,7 +21,10 @@ module Groupdate
|
|
20
21
|
end
|
21
22
|
|
22
23
|
def generate
|
23
|
-
|
24
|
+
group_by = group_clause
|
25
|
+
@relation = @relation.group(group_by).where(*where_clause)
|
26
|
+
@relation.select_values += ["#{group_by} AS #{series_label}"] if series_label
|
27
|
+
@relation
|
24
28
|
end
|
25
29
|
|
26
30
|
private
|
@@ -32,22 +36,26 @@ module Groupdate
|
|
32
36
|
case adapter_name
|
33
37
|
when "SQLServer"
|
34
38
|
sql_server_group_clause(time_zone)
|
35
|
-
when "
|
39
|
+
when "Mysql2", "Mysql2Spatial", "Mysql2Rgeo"
|
40
|
+
day_start_column = "CONVERT_TZ(#{column}, '+00:00', ?) - INTERVAL ? second"
|
41
|
+
|
36
42
|
case period
|
37
|
-
when :day_of_week
|
38
|
-
["DAYOFWEEK(CONVERT_TZ(DATE_SUB(#{column}, INTERVAL #{day_start} second), '+00:00', ?)) - 1", time_zone]
|
39
|
-
when :hour_of_day
|
40
|
-
["(EXTRACT(HOUR from CONVERT_TZ(#{column}, '+00:00', ?)) + 24 - #{day_start / 3600}) % 24", time_zone]
|
41
43
|
when :minute_of_hour
|
42
|
-
["
|
44
|
+
["MINUTE(#{day_start_column})", time_zone, day_start]
|
45
|
+
when :hour_of_day
|
46
|
+
["HOUR(#{day_start_column})", time_zone, day_start]
|
47
|
+
when :day_of_week
|
48
|
+
["DAYOFWEEK(#{day_start_column}) - 1", time_zone, day_start]
|
43
49
|
when :day_of_month
|
44
|
-
["DAYOFMONTH(
|
50
|
+
["DAYOFMONTH(#{day_start_column})", time_zone, day_start]
|
51
|
+
when :day_of_year
|
52
|
+
["DAYOFYEAR(#{day_start_column})", time_zone, day_start]
|
45
53
|
when :month_of_year
|
46
|
-
["MONTH(
|
54
|
+
["MONTH(#{day_start_column})", time_zone, day_start]
|
47
55
|
when :week
|
48
|
-
["CONVERT_TZ(DATE_FORMAT(
|
56
|
+
["CONVERT_TZ(DATE_FORMAT(#{day_start_column} - INTERVAL ((? + DAYOFWEEK(#{day_start_column})) % 7) DAY, '%Y-%m-%d 00:00:00') + INTERVAL ? second, ?, '+00:00')", time_zone, day_start, 12 - week_start, time_zone, day_start, day_start, time_zone]
|
49
57
|
when :quarter
|
50
|
-
["
|
58
|
+
["CONVERT_TZ(DATE_FORMAT(DATE(CONCAT(YEAR(#{day_start_column}), '-', LPAD(1 + 3 * (QUARTER(#{day_start_column}) - 1), 2, '00'), '-01')), '%Y-%m-%d %H:%i:%S') + INTERVAL ? second, ?, '+00:00')", time_zone, day_start, time_zone, day_start, day_start, time_zone]
|
51
59
|
else
|
52
60
|
format =
|
53
61
|
case period
|
@@ -65,43 +73,54 @@ module Groupdate
|
|
65
73
|
"%Y-01-01 00:00:00"
|
66
74
|
end
|
67
75
|
|
68
|
-
["
|
76
|
+
["CONVERT_TZ(DATE_FORMAT(#{day_start_column}, ?) + INTERVAL ? second, ?, '+00:00')", time_zone, day_start, format, day_start, time_zone]
|
69
77
|
end
|
70
78
|
when "PostgreSQL", "PostGIS"
|
79
|
+
day_start_column = "#{column}::timestamptz AT TIME ZONE ? - INTERVAL ?"
|
80
|
+
day_start_interval = "#{day_start} second"
|
81
|
+
|
71
82
|
case period
|
72
|
-
when :day_of_week
|
73
|
-
["EXTRACT(DOW from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
|
74
|
-
when :hour_of_day
|
75
|
-
["EXTRACT(HOUR from #{column}::timestamptz AT TIME ZONE ? - INTERVAL '#{day_start} second')::integer", time_zone]
|
76
83
|
when :minute_of_hour
|
77
|
-
["EXTRACT(MINUTE
|
84
|
+
["EXTRACT(MINUTE FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
85
|
+
when :hour_of_day
|
86
|
+
["EXTRACT(HOUR FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
87
|
+
when :day_of_week
|
88
|
+
["EXTRACT(DOW FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
78
89
|
when :day_of_month
|
79
|
-
["EXTRACT(DAY
|
90
|
+
["EXTRACT(DAY FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
91
|
+
when :day_of_year
|
92
|
+
["EXTRACT(DOY FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
80
93
|
when :month_of_year
|
81
|
-
["EXTRACT(MONTH
|
82
|
-
when :week
|
83
|
-
["(DATE_TRUNC('
|
94
|
+
["EXTRACT(MONTH FROM #{day_start_column})::integer", time_zone, day_start_interval]
|
95
|
+
when :week
|
96
|
+
["(DATE_TRUNC('day', #{day_start_column} - INTERVAL '1 day' * ((? + EXTRACT(DOW FROM #{day_start_column})::integer) % 7)) + INTERVAL ?) AT TIME ZONE ?", time_zone, day_start_interval, 13 - week_start, time_zone, day_start_interval, day_start_interval, time_zone]
|
84
97
|
else
|
85
|
-
|
98
|
+
if day_start == 0
|
99
|
+
# prettier
|
100
|
+
["DATE_TRUNC(?, #{day_start_column}) AT TIME ZONE ?", period, time_zone, day_start_interval, time_zone]
|
101
|
+
else
|
102
|
+
["(DATE_TRUNC(?, #{day_start_column}) + INTERVAL ?) AT TIME ZONE ?", period, time_zone, day_start_interval, day_start_interval, time_zone]
|
103
|
+
end
|
86
104
|
end
|
87
105
|
when "SQLite"
|
88
106
|
raise Groupdate::Error, "Time zones not supported for SQLite" unless @time_zone.utc_offset.zero?
|
89
107
|
raise Groupdate::Error, "day_start not supported for SQLite" unless day_start.zero?
|
90
|
-
raise Groupdate::Error, "week_start not supported for SQLite" unless week_start == 6
|
91
108
|
|
92
109
|
if period == :week
|
93
|
-
["strftime('
|
110
|
+
["strftime('%Y-%m-%d 00:00:00 UTC', #{column}, '-6 days', ?)", "weekday #{(week_start + 1) % 7}"]
|
94
111
|
else
|
95
112
|
format =
|
96
113
|
case period
|
97
|
-
when :hour_of_day
|
98
|
-
"%H"
|
99
114
|
when :minute_of_hour
|
100
115
|
"%M"
|
116
|
+
when :hour_of_day
|
117
|
+
"%H"
|
101
118
|
when :day_of_week
|
102
119
|
"%w"
|
103
120
|
when :day_of_month
|
104
121
|
"%d"
|
122
|
+
when :day_of_year
|
123
|
+
"%j"
|
105
124
|
when :month_of_year
|
106
125
|
"%m"
|
107
126
|
when :second
|
@@ -120,37 +139,38 @@ module Groupdate
|
|
120
139
|
"%Y-01-01 00:00:00 UTC"
|
121
140
|
end
|
122
141
|
|
123
|
-
["strftime(
|
142
|
+
["strftime(?, #{column})", format]
|
124
143
|
end
|
125
144
|
when "Redshift"
|
145
|
+
day_start_column = "CONVERT_TIMEZONE(?, #{column}::timestamp) - INTERVAL ?"
|
146
|
+
day_start_interval = "#{day_start} second"
|
147
|
+
|
126
148
|
case period
|
127
|
-
when :day_of_week
|
128
|
-
["EXTRACT(DOW from CONVERT_TIMEZONE(?, #{column}::timestamp) - INTERVAL '#{day_start} second')::integer", time_zone]
|
129
|
-
when :hour_of_day
|
130
|
-
["EXTRACT(HOUR from CONVERT_TIMEZONE(?, #{column}::timestamp) - INTERVAL '#{day_start} second')::integer", time_zone]
|
131
149
|
when :minute_of_hour
|
132
|
-
["EXTRACT(MINUTE from
|
150
|
+
["EXTRACT(MINUTE from #{day_start_column})::integer", time_zone, day_start_interval]
|
151
|
+
when :hour_of_day
|
152
|
+
["EXTRACT(HOUR from #{day_start_column})::integer", time_zone, day_start_interval]
|
153
|
+
when :day_of_week
|
154
|
+
["EXTRACT(DOW from #{day_start_column})::integer", time_zone, day_start_interval]
|
133
155
|
when :day_of_month
|
134
|
-
["EXTRACT(DAY from
|
156
|
+
["EXTRACT(DAY from #{day_start_column})::integer", time_zone, day_start_interval]
|
157
|
+
when :day_of_year
|
158
|
+
["EXTRACT(DOY from #{day_start_column})::integer", time_zone, day_start_interval]
|
135
159
|
when :month_of_year
|
136
|
-
["EXTRACT(MONTH from
|
160
|
+
["EXTRACT(MONTH from #{day_start_column})::integer", time_zone, day_start_interval]
|
137
161
|
when :week # start on Sunday, not Redshift default Monday
|
138
162
|
# Redshift does not return timezone information; it
|
139
163
|
# always says it is in UTC time, so we must convert
|
140
164
|
# back to UTC to play properly with the rest of Groupdate.
|
141
|
-
#
|
142
|
-
["CONVERT_TIMEZONE(?, 'Etc/UTC', DATE_TRUNC(
|
165
|
+
week_start_interval = "#{week_start} day"
|
166
|
+
["CONVERT_TIMEZONE(?, 'Etc/UTC', DATE_TRUNC('week', #{day_start_column} - INTERVAL ?) + INTERVAL ? + INTERVAL ?)::timestamp", time_zone, time_zone, day_start_interval, week_start_interval, week_start_interval, day_start_interval]
|
143
167
|
else
|
144
|
-
["CONVERT_TIMEZONE(?, 'Etc/UTC', DATE_TRUNC(?,
|
168
|
+
["CONVERT_TIMEZONE(?, 'Etc/UTC', DATE_TRUNC(?, #{day_start_column}) + INTERVAL ?)::timestamp", time_zone, period, time_zone, day_start_interval, day_start_interval]
|
145
169
|
end
|
146
170
|
else
|
147
171
|
raise Groupdate::Error, "Connection adapter not supported: #{adapter_name}"
|
148
172
|
end
|
149
173
|
|
150
|
-
if adapter_name == "MySQL" && period == :week
|
151
|
-
query[0] = "CAST(#{query[0]} AS DATETIME)"
|
152
|
-
end
|
153
|
-
|
154
174
|
clause = @relation.send(:sanitize_sql_array, query)
|
155
175
|
|
156
176
|
# cleaner queries in logs
|
@@ -163,11 +183,7 @@ module Groupdate
|
|
163
183
|
end
|
164
184
|
|
165
185
|
def clean_group_clause_mysql(clause)
|
166
|
-
clause
|
167
|
-
if clause.start_with?("DATE_ADD(") && clause.end_with?(", INTERVAL 0 second)")
|
168
|
-
clause = clause[9..-21]
|
169
|
-
end
|
170
|
-
clause
|
186
|
+
clause.gsub(/ (\-|\+) INTERVAL 0 second/, "")
|
171
187
|
end
|
172
188
|
|
173
189
|
def where_clause
|
@@ -11,19 +11,55 @@ module Groupdate
|
|
11
11
|
@day_start = day_start
|
12
12
|
@options = options
|
13
13
|
@round_time = {}
|
14
|
+
@week_start_key = Groupdate::Magic::DAYS[@week_start] if @week_start
|
14
15
|
end
|
15
16
|
|
16
17
|
def generate(data, default_value:, series_default: true, multiple_groups: false, group_index: nil)
|
17
18
|
series = generate_series(data, multiple_groups, group_index)
|
18
19
|
series = handle_multiple(data, series, multiple_groups, group_index)
|
19
20
|
|
21
|
+
verified_data = {}
|
22
|
+
series.each do |k|
|
23
|
+
verified_data[k] = data.delete(k)
|
24
|
+
end
|
25
|
+
|
26
|
+
# this is a fun one
|
27
|
+
# PostgreSQL and Ruby both return the 2nd hour when converting/parsing a backward DST change
|
28
|
+
# Other databases and Active Support return the 1st hour (as expected)
|
29
|
+
# Active Support good: ActiveSupport::TimeZone["America/Los_Angeles"].parse("2013-11-03 01:00:00")
|
30
|
+
# MySQL good: SELECT CONVERT_TZ('2013-11-03 01:00:00', 'America/Los_Angeles', 'Etc/UTC');
|
31
|
+
# SQLServer good: SELECT CAST('2013-11-03 01:00:00' AS DATETIME2(3)) AT TIME ZONE 'Pacific Standard Time' AT TIME ZONE 'UTC'
|
32
|
+
# Ruby not good: Time.parse("2013-11-03 01:00:00")
|
33
|
+
# PostgreSQL not good: SELECT '2013-11-03 01:00:00'::timestamp AT TIME ZONE 'America/Los_Angeles';
|
34
|
+
# we need to account for this here
|
35
|
+
if series_default && CHECK_PERIODS.include?(period)
|
36
|
+
data.each do |k, v|
|
37
|
+
key = multiple_groups ? k[group_index] : k
|
38
|
+
# TODO only do this for PostgreSQL
|
39
|
+
# this may mask some inconsistent time zone errors
|
40
|
+
# but not sure there's a better approach
|
41
|
+
if key.hour == (key - 1.hour).hour && series.include?(key - 1.hour)
|
42
|
+
key -= 1.hour
|
43
|
+
if multiple_groups
|
44
|
+
k[group_index] = key
|
45
|
+
else
|
46
|
+
k = key
|
47
|
+
end
|
48
|
+
verified_data[k] = v
|
49
|
+
elsif key != round_time(key)
|
50
|
+
# only need to show what database returned since it will cast in Ruby time zone
|
51
|
+
# raise Groupdate::Error, "Database and Ruby have inconsistent time zone info. Database returned #{key}: #{round_time(key)}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
20
56
|
unless entire_series?(series_default)
|
21
|
-
series = series.select { |k|
|
57
|
+
series = series.select { |k| verified_data[k] }
|
22
58
|
end
|
23
59
|
|
24
60
|
value = 0
|
25
61
|
result = Hash[series.map do |k|
|
26
|
-
value =
|
62
|
+
value = verified_data[k] || (@options[:carry_forward] && value) || default_value
|
27
63
|
key =
|
28
64
|
if multiple_groups
|
29
65
|
k[0...group_index] + [key_format.call(k[group_index])] + k[(group_index + 1)..-1]
|
@@ -34,20 +70,22 @@ module Groupdate
|
|
34
70
|
[key, value]
|
35
71
|
end]
|
36
72
|
|
37
|
-
# only check for database
|
38
|
-
# only checks remaining keys to avoid expensive calls to round_time
|
39
|
-
if series_default && CHECK_PERIODS.include?(period)
|
40
|
-
check_consistent_time_zone_info(data, multiple_groups, group_index)
|
41
|
-
end
|
42
|
-
|
43
73
|
result
|
44
74
|
end
|
45
75
|
|
76
|
+
def format_series_label(series_label)
|
77
|
+
series_label = round_time(series_label) if series_label.respond_to?(:to_time)
|
78
|
+
key_format.call(series_label)
|
79
|
+
end
|
80
|
+
|
46
81
|
def round_time(time)
|
47
82
|
time = time.to_time.in_time_zone(time_zone)
|
48
83
|
|
49
|
-
|
50
|
-
|
84
|
+
if day_start != 0
|
85
|
+
# apply day_start to a time object that's not affected by DST
|
86
|
+
time = change_zone.call(time, utc)
|
87
|
+
time -= day_start.seconds
|
88
|
+
end
|
51
89
|
|
52
90
|
time =
|
53
91
|
case period
|
@@ -60,9 +98,7 @@ module Groupdate
|
|
60
98
|
when :day
|
61
99
|
time.beginning_of_day
|
62
100
|
when :week
|
63
|
-
|
64
|
-
weekday = (time.wday - 1) % 7
|
65
|
-
(time - ((7 - week_start + weekday) % 7).days).midnight
|
101
|
+
time.beginning_of_week(@week_start_key)
|
66
102
|
when :month
|
67
103
|
time.beginning_of_month
|
68
104
|
when :quarter
|
@@ -74,30 +110,44 @@ module Groupdate
|
|
74
110
|
when :minute_of_hour
|
75
111
|
time.min
|
76
112
|
when :day_of_week
|
77
|
-
|
113
|
+
time.days_to_week_start(@week_start_key)
|
78
114
|
when :day_of_month
|
79
115
|
time.day
|
80
116
|
when :month_of_year
|
81
117
|
time.month
|
118
|
+
when :day_of_year
|
119
|
+
time.yday
|
82
120
|
else
|
83
121
|
raise Groupdate::Error, "Invalid period"
|
84
122
|
end
|
85
123
|
|
86
|
-
|
87
|
-
|
124
|
+
if day_start != 0 && time.is_a?(Time)
|
125
|
+
time += day_start.seconds
|
126
|
+
time = change_zone.call(time, time_zone)
|
127
|
+
end
|
88
128
|
|
89
129
|
time
|
90
130
|
end
|
91
131
|
|
132
|
+
def change_zone
|
133
|
+
@change_zone ||= begin
|
134
|
+
if ActiveSupport::VERSION::STRING >= "5.2"
|
135
|
+
->(time, zone) { time.change(zone: zone) }
|
136
|
+
else
|
137
|
+
# TODO make more efficient
|
138
|
+
->(time, zone) { zone.parse(time.strftime("%Y-%m-%d %H:%M:%S")) }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
92
143
|
def time_range
|
93
144
|
@time_range ||= begin
|
94
145
|
time_range = options[:range]
|
95
146
|
if time_range.is_a?(Range) && time_range.first.is_a?(Date)
|
96
147
|
# convert range of dates to range of times
|
97
|
-
|
98
|
-
last = time_zone.parse(time_range.last.to_s)
|
148
|
+
last = time_range.last.in_time_zone(time_zone)
|
99
149
|
last += 1.day unless time_range.exclude_end?
|
100
|
-
time_range = Range.new(
|
150
|
+
time_range = Range.new(time_range.first.in_time_zone(time_zone), last, true)
|
101
151
|
elsif !time_range && options[:last]
|
102
152
|
if period == :quarter
|
103
153
|
step = 3.months
|
@@ -117,7 +167,8 @@ module Groupdate
|
|
117
167
|
if options[:current] == false
|
118
168
|
round_time(start_at - step)...round_time(now)
|
119
169
|
else
|
120
|
-
|
170
|
+
# extend to end of current period
|
171
|
+
round_time(start_at)...(round_time(now) + step)
|
121
172
|
end
|
122
173
|
end
|
123
174
|
end
|
@@ -141,6 +192,8 @@ module Groupdate
|
|
141
192
|
0..59
|
142
193
|
when :day_of_month
|
143
194
|
1..31
|
195
|
+
when :day_of_year
|
196
|
+
1..366
|
144
197
|
when :month_of_year
|
145
198
|
1..12
|
146
199
|
else
|
@@ -164,8 +217,8 @@ module Groupdate
|
|
164
217
|
tr
|
165
218
|
end
|
166
219
|
|
167
|
-
if time_range.
|
168
|
-
series = [round_time(time_range.
|
220
|
+
if time_range.begin
|
221
|
+
series = [round_time(time_range.begin)]
|
169
222
|
|
170
223
|
if period == :quarter
|
171
224
|
step = 3.months
|
@@ -174,9 +227,10 @@ module Groupdate
|
|
174
227
|
end
|
175
228
|
|
176
229
|
last_step = series.last
|
230
|
+
day_start_hour = day_start / 3600
|
177
231
|
loop do
|
178
232
|
next_step = last_step + step
|
179
|
-
next_step = round_time(next_step) if next_step.hour !=
|
233
|
+
next_step = round_time(next_step) if next_step.hour != day_start_hour # add condition to speed up
|
180
234
|
break unless time_range.cover?(next_step)
|
181
235
|
|
182
236
|
if next_step == last_step
|
@@ -195,34 +249,36 @@ module Groupdate
|
|
195
249
|
end
|
196
250
|
|
197
251
|
def key_format
|
198
|
-
|
199
|
-
|
252
|
+
@key_format ||= begin
|
253
|
+
locale = options[:locale] || I18n.locale
|
254
|
+
use_dates = options.key?(:dates) ? options[:dates] : Groupdate.dates
|
200
255
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
256
|
+
if options[:format]
|
257
|
+
if options[:format].respond_to?(:call)
|
258
|
+
options[:format]
|
259
|
+
else
|
260
|
+
sunday = time_zone.parse("2014-03-02 00:00:00")
|
261
|
+
lambda do |key|
|
262
|
+
case period
|
263
|
+
when :hour_of_day
|
264
|
+
key = sunday + key.hours + day_start.seconds
|
265
|
+
when :minute_of_hour
|
266
|
+
key = sunday + key.minutes + day_start.seconds
|
267
|
+
when :day_of_week
|
268
|
+
key = sunday + key.days + (week_start + 1).days
|
269
|
+
when :day_of_month
|
270
|
+
key = Date.new(2014, 1, key).to_time
|
271
|
+
when :month_of_year
|
272
|
+
key = Date.new(2014, key, 1).to_time
|
273
|
+
end
|
274
|
+
I18n.localize(key, format: options[:format], locale: locale)
|
218
275
|
end
|
219
|
-
I18n.localize(key, format: options[:format], locale: locale)
|
220
276
|
end
|
277
|
+
elsif [:day, :week, :month, :quarter, :year].include?(period) && use_dates
|
278
|
+
lambda { |k| k.to_date }
|
279
|
+
else
|
280
|
+
lambda { |k| k }
|
221
281
|
end
|
222
|
-
elsif [:day, :week, :month, :quarter, :year].include?(period) && use_dates
|
223
|
-
lambda { |k| k.to_date }
|
224
|
-
else
|
225
|
-
lambda { |k| k }
|
226
282
|
end
|
227
283
|
end
|
228
284
|
|
@@ -242,23 +298,12 @@ module Groupdate
|
|
242
298
|
end
|
243
299
|
end
|
244
300
|
|
245
|
-
def check_consistent_time_zone_info(data, multiple_groups, group_index)
|
246
|
-
keys = data.keys
|
247
|
-
if multiple_groups
|
248
|
-
keys.map! { |k| k[group_index] }
|
249
|
-
keys.uniq!
|
250
|
-
end
|
251
|
-
|
252
|
-
keys.each do |key|
|
253
|
-
if key != round_time(key)
|
254
|
-
# only need to show what database returned since it will cast in Ruby time zone
|
255
|
-
raise Groupdate::Error, "Database and Ruby have inconsistent time zone info. Database returned #{key} != #{round_time(key)}"
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
301
|
def entire_series?(series_default)
|
261
302
|
options.key?(:series) ? options[:series] : series_default
|
262
303
|
end
|
304
|
+
|
305
|
+
def utc
|
306
|
+
@utc ||= ActiveSupport::TimeZone["Etc/UTC"]
|
307
|
+
end
|
263
308
|
end
|
264
309
|
end
|