Class: TZOffset

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/tz_offset.rb,
lib/tz_offset/abbrev.rb,
lib/tz_offset/version.rb,
lib/tz_offset/tasks/extract_offsets.rb

Overview

Simple class representing timezone offset (in minutes). Knows almost nothing about timezone name, DST or other complications, but useful when ONLY offset is known.

Usage:

o = Reality::TZOffset.parse('UTC+3')
# => #<Reality::TZOffset(UTC+03:00)>

o.now
# => 2016-04-16 19:01:40 +0300
o.local(2016, 4, 1, 20, 30)
# => 2016-04-01 20:30:00 +0300
o.convert(Time.now)
# => 2016-04-16 19:02:22 +0300

Constant Summary collapse

VERSION =
'0.0.4'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(seconds, name: nil, description: nil, region: nil, isdst: nil) ⇒ TZOffset

Constructs offset from number of seconds. In most cases, you don't want to use it, but rather parse.

Parameters:

  • seconds (Fixnum)

    Number of seconds in offset.



116
117
118
119
120
121
122
# File 'lib/tz_offset.rb', line 116

def initialize(seconds, name: nil, description: nil, region: nil, isdst: nil)
  @seconds = seconds
  @name = name
  @description = description
  @isdst = isdst
  @region = region
end

Instance Attribute Details

#descriptionString (readonly)

Full symbolic timezone description, as per wikipedia (like "Eastern European Summer Time" for "EEST").

Returns:

  • (String)


39
40
41
# File 'lib/tz_offset.rb', line 39

def description
  @description
end

#nameString (readonly)

Note:

TZOffset never tries to "guess" the name, it is only known if an object was parsed/created from it.

Symbolic offset name if available (like "EEST").

Returns:

  • (String)


33
34
35
# File 'lib/tz_offset.rb', line 33

def name
  @name
end

#regionString (readonly)

"Region" part of #description, like "Eastern European" for "EEST".

Returns:

  • (String)


44
45
46
# File 'lib/tz_offset.rb', line 44

def region
  @region
end

#secondsFixnum (readonly) Also known as: to_i

Number of seconds in offset.

Returns:

  • (Fixnum)


24
25
26
# File 'lib/tz_offset.rb', line 24

def seconds
  @seconds
end

Class Method Details

.parse(text) ⇒ TZOffset, ...

Parses TZOffset from string. Understands several options like:

  • GMT (not all TZ names, just well-known abbreviations);
  • UTC+3 (or GMT+3);
  • +03:30;
  • ..and several combinations.

Examples:

TZOffset.parse('+05:30') # => #<TZOffset +05:30>
TZOffset.parse('UTC+0200') # => #<TZOffset +02:00>
TZOffset.parse('something') # => nil
TZOffset.parse('EST') # => #<TZOffset -05:00 (EST)>
TZOffset.parse('CST') # => [#<TZOffset -06:00 (CST)>, #<TZOffset +08:00 (CST)>, #<TZOffset -05:00 (CST)>]
TZOffset.parse('CST').map(&:description) # => ["Central Standard Time (North America)", "China Standard Time", "Cuba Standard Time"]

Returns:

  • (TZOffset, Array<TZOffset>, nil)

    Returns array on ambigous abbreviations, and nil on unparseable string.



69
70
71
72
73
74
# File 'lib/tz_offset.rb', line 69

def parse(text)
  return ABBREV[text.upcase] if ABBREV.key?(text.upcase)

  sec = parse_text(text.gsub(MINUSES, '-'))
  sec && new(sec)
end

.zeroTZOffset Also known as: utc

Returns zero (UTC) offset.

Returns:



79
80
81
# File 'lib/tz_offset.rb', line 79

def zero
  @zero ||= new(0)
end

Instance Method Details

#+(other) ⇒ TZOffset

Sums offset with other or just number of seconds.

Examples:

TZOffset.parse('+2') + TZOffset.parse('+5')
# => #<TZOffset +07:00>
TZOffset.parse('+2') + 1200
# => #<TZOffset +02:20>

Returns:



160
161
162
163
164
165
166
167
168
169
# File 'lib/tz_offset.rb', line 160

def +(other)
  case other
  when TZOffset
    TZOffset.new(seconds + other.seconds)
  when Numeric
    TZOffset.new(seconds + other)
  else
    fail ArgumentError, "Can't sum with #{other.class}"
  end
end

#-(other) ⇒ TZOffset

Substracts other offset or number of seconds.

Examples:

TZOffset.parse('+2') - TZOffset.parse('+5')
# => #<TZOffset -03:00>
TZOffset.parse('+2') - 1200
# => #<TZOffset +01:40>

Returns:



180
181
182
183
# File 'lib/tz_offset.rb', line 180

def -(other)
  other.respond_to?(:-@) or fail ArgumentError, "Can't subtract #{other.class} from TZOffset"
  self + -other
end

#-@TZOffset

Returns Offset negated.

Returns:



147
148
149
# File 'lib/tz_offset.rb', line 147

def -@
  TZOffset.new(-seconds)
end

#<=>(other) ⇒ Boolean

Returns:

  • (Boolean)


201
202
203
204
# File 'lib/tz_offset.rb', line 201

def <=>(other)
  return nil unless other.is_a?(TZOffset)
  minutes <=> other.minutes
end

#==(other) ⇒ Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/tz_offset.rb', line 209

def ==(other)
  other.class == self.class && other.seconds == seconds
end

#convert(tm) ⇒ Time

Converts tm into current offset.

Parameters:

  • tm (Time)

    Time object to convert (with any offset);

Returns:

  • (Time)

    Converted object.



225
226
227
228
229
230
# File 'lib/tz_offset.rb', line 225

def convert(tm)
  t = tm.getutc + seconds

  # FIXME: usec are lost
  mk(t.year, t.month, t.day, t.hour, t.min, t.sec)
end

#dst?Boolean

If offset is symbolic (e.g., "EET", not just "+02:00"), returns whether it is daylight saving time offset.

See also #opposite for obtaining non-DST related to current DST offset and vice versa.

Returns:

  • (Boolean)


189
190
191
# File 'lib/tz_offset.rb', line 189

def dst?
  @isdst
end

#inspectString

Returns:

  • (String)


134
135
136
137
138
139
# File 'lib/tz_offset.rb', line 134

def inspect
  nm = name ? " (#{name})" : ''

  '#<%s %s%02i:%02i%s%s>' %
    [self.class.name, sign, *minutes.abs.divmod(60), inspectable_seconds, nm]
end

#local(*values) ⇒ Time

Like Ruby's Time.local, but in current offset.

Returns:

  • (Time)

    Constructed time in that offset.



216
217
218
219
# File 'lib/tz_offset.rb', line 216

def local(*values)
  values << 0 until values.count == 6
  mk(*values)
end

#minutesInteger

Minutes component of offset.

Returns:

  • (Integer)


127
128
129
# File 'lib/tz_offset.rb', line 127

def minutes
  seconds.abs / 60 * (seconds <=> 0)
end

#nowTime

Like Ruby's Time.now, but in current offset.

Returns:

  • (Time)

    Current time in that offset.



235
236
237
# File 'lib/tz_offset.rb', line 235

def now
  convert(Time.now)
end

#oppositeTZOffset

For symbolic offsets, returns opposite (DST for non-DST and vice versa) offset object if known, nil otherwise.

Examples:

eet = TZOffset.parse('EET')
# => #<TZOffset +02:00 (EET)>
eet.opposite
# => #<TZOffset +03:00 (EEST)>
TZOffset.parse('+8').opposite
# => nil

Returns:



251
252
253
254
# File 'lib/tz_offset.rb', line 251

def opposite
  return nil unless region
  ABBREV.values.flatten.detect { |tz| tz.region == region && tz.dst? == !dst? }
end

#parse(str) ⇒ Time

Note:

If time string contains timezone abbreviation or offset by itself, it is just ignored. The method is intended for "quick-n-dirty" parsing of things like "what is 12:30 in CEST currently?"

Like Time.parse, but produces time in current offset.

Examples:

# My current date and zone
Time.parse('12:30')
# => 2016-10-26 12:30:00 +0300
TZOffset.parse('PDT').parse('12:30')
# => 2016-10-26 12:30:00 -0700
# Now I can know what it will be for me when somebody
# says "I'll be available 12:30 PDT tomorrow":
TZOffset.parse('PDT').parse('12:30').localtime
# => 2016-10-26 22:30:00 +0300

Parameters:

  • str (String)

    Same string that Time.parse could accept.

Returns:

  • (Time)

    Time parsed from str into current offset.



276
277
278
279
# File 'lib/tz_offset.rb', line 276

def parse(str)
  t = Time.parse(str)
  t && local(t.year, t.month, t.day, t.hour, t.min, t.sec)
end

#to_sString

Returns:

  • (String)


142
143
144
# File 'lib/tz_offset.rb', line 142

def to_s
  '%s%02i:%02i%s' % [sign, *minutes.abs.divmod(60), inspectable_seconds]
end

#zero?Boolean Also known as: utc?

If this offset is zero (UTC).

Returns:

  • (Boolean)


194
195
196
# File 'lib/tz_offset.rb', line 194

def zero?
  @seconds.zero?
end