/
timezone_period.rb
179 lines (162 loc) · 6.81 KB
/
timezone_period.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# encoding: UTF-8
# frozen_string_literal: true
module TZInfo
# {TimezonePeriod} represents a period of time for a time zone where the same
# offset from UTC applies. It provides access to the observed offset, time
# zone abbreviation, start time and end time.
#
# The period of time can be unbounded at the start, end, or both the start
# and end.
#
# @abstract Time zone period data will returned as an instance of one of the
# subclasses of {TimezonePeriod}.
class TimezonePeriod
# @return [TimezoneOffset] the offset that applies in the period of time.
attr_reader :offset
# Initializes a {TimezonePeriod}.
#
# @param offset [TimezoneOffset] the offset that is observed for the period
# of time.
# @raise [ArgumentError] if `offset` is `nil`.
def initialize(offset)
raise ArgumentError, 'offset must be specified' unless offset
@offset = offset
end
# @return [TimezoneTransition] the transition that defines the start of this
# {TimezonePeriod} (`nil` if the start is unbounded).
def start_transition
raise_not_implemented(:start_transition)
end
# @return [TimezoneTransition] the transition that defines the end of this
# {TimezonePeriod} (`nil` if the end is unbounded).
def end_transition
raise_not_implemented(:end_transition)
end
# Returns the base offset from UTC in seconds (`observed_utc_offset -
# std_offset`). This does not include any adjustment made for daylight
# savings time and will typically remain constant throughout the year.
#
# To obtain the currently observed offset from UTC, including the effect of
# daylight savings time, use {observed_utc_offset} instead.
#
# If you require accurate {base_utc_offset} values, you should install the
# tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}.
# When using {DataSources::ZoneinfoDataSource}, the value of
# {base_utc_offset} has to be derived from changes to the observed UTC
# offset and DST status since it is not included in zoneinfo files.
#
# @return [Integer] the base offset from UTC in seconds.
def base_utc_offset
@offset.base_utc_offset
end
alias utc_offset base_utc_offset
# Returns the offset from the time zone's standard time in seconds
# (`observed_utc_offset - base_utc_offset`). Zero when daylight savings time
# is not in effect. Non-zero (usually 3600 = 1 hour) if daylight savings is
# being observed.
#
# If you require accurate {std_offset} values, you should install the
# tzinfo-data gem and set {DataSources::RubyDataSource} as the {DataSource}.
# When using {DataSources::ZoneinfoDataSource}, the value of {std_offset}
# has to be derived from changes to the observed UTC offset and DST status
# since it is not included in zoneinfo files.
#
# @return [Integer] the offset from the time zone's standard time in
# seconds.
def std_offset
@offset.std_offset
end
# The abbreviation that identifies this offset. For example GMT
# (Greenwich Mean Time) or BST (British Summer Time) for Europe/London.
#
# @return [String] the abbreviation that identifies this offset.
def abbreviation
@offset.abbreviation
end
alias abbr abbreviation
alias zone_identifier abbreviation
# Returns the observed offset from UTC in seconds (`base_utc_offset +
# std_offset`). This includes adjustments made for daylight savings time.
#
# @return [Integer] the observed offset from UTC in seconds.
def observed_utc_offset
@offset.observed_utc_offset
end
alias utc_total_offset observed_utc_offset
# Determines if daylight savings is in effect (i.e. if {std_offset} is
# non-zero).
#
# @return [Boolean] `true` if {std_offset} is non-zero, otherwise `false`.
def dst?
@offset.dst?
end
# Returns the UTC start time of the period or `nil` if the start of the
# period is unbounded.
#
# The result is returned as a {Timestamp}. To obtain the start time as a
# `Time` or `DateTime`, call either {Timestamp#to_time to_time} or
# {Timestamp#to_datetime to_datetime} on the result.
#
# @return [Timestamp] the UTC start time of the period or `nil` if the start
# of the period is unbounded.
def starts_at
timestamp(start_transition)
end
# Returns the UTC end time of the period or `nil` if the end of the period
# is unbounded.
#
# The result is returned as a {Timestamp}. To obtain the end time as a
# `Time` or `DateTime`, call either {Timestamp#to_time to_time} or
# {Timestamp#to_datetime to_datetime} on the result.
#
# @return [Timestamp] the UTC end time of the period or `nil` if the end of
# the period is unbounded.
def ends_at
timestamp(end_transition)
end
# Returns the local start time of the period or `nil` if the start of the
# period is unbounded.
#
# The result is returned as a {TimestampWithOffset}. To obtain the start
# time as a `Time` or `DateTime`, call either {TimestampWithOffset#to_time
# to_time} or {TimestampWithOffset#to_datetime to_datetime} on the result.
#
# @return [TimestampWithOffset] the local start time of the period or `nil`
# if the start of the period is unbounded.
def local_starts_at
timestamp_with_offset(start_transition)
end
# Returns the local end time of the period or `nil` if the end of the period
# is unbounded.
#
# The result is returned as a {TimestampWithOffset}. To obtain the end time
# as a `Time` or `DateTime`, call either {TimestampWithOffset#to_time
# to_time} or {TimestampWithOffset#to_datetime to_datetime} on the result.
#
# @return [TimestampWithOffset] the local end time of the period or `nil` if
# the end of the period is unbounded.
def local_ends_at
timestamp_with_offset(end_transition)
end
private
# Raises a {NotImplementedError} to indicate that subclasses should override
# a method.
#
# @raise [NotImplementedError] always.
def raise_not_implemented(method_name)
raise NotImplementedError, "Subclasses must override #{method_name}"
end
# @param transition [TimezoneTransition] a transition or `nil`.
# @return [Timestamp] the {Timestamp} representing when a transition occurs,
# or `nil` if `transition` is `nil`.
def timestamp(transition)
transition ? transition.at : nil
end
# @param transition [TimezoneTransition] a transition or `nil`.
# @return [TimestampWithOffset] a {Timestamp} representing when a transition
# occurs with offset set to {#offset}, or `nil` if `transition` is `nil`.
def timestamp_with_offset(transition)
transition ? TimestampWithOffset.set_timezone_offset(transition.at, offset) : nil
end
end
end