Module: Sekki24::TimeScale

Defined in:
lib/sekki24/time_scale.rb

Constant Summary collapse

UNIX_EPOCH_JD =
2_440_587.5
SECONDS_PER_DAY =
86_400.0
OFFSET_PATTERN =
/\A([+-])(\d{2}):(\d{2})\z/

Class Method Summary collapse

Class Method Details

.decimal_year(time) ⇒ Object



33
34
35
36
37
38
# File 'lib/sekki24/time_scale.rb', line 33

def decimal_year(time)
  utc_time = coerce_time(time).getutc
  year_start = Time.utc(utc_time.year, 1, 1)
  next_year = Time.utc(utc_time.year + 1, 1, 1)
  utc_time.year + ((utc_time - year_start) / (next_year - year_start))
end

.fixed_offset(timezone) ⇒ Object

Raises:

  • (ArgumentError)


59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/sekki24/time_scale.rb', line 59

def fixed_offset(timezone)
  return validate_offset(timezone) if timezone.is_a?(Integer)
  return 0 if %w[UTC Z].include?(timezone)

  if timezone.is_a?(String)
    match = OFFSET_PATTERN.match(timezone)
    raise ArgumentError, 'timezone must use the format "+09:00"' unless match

    sign = match[1] == "+" ? 1 : -1
    hours = match[2].to_i
    minutes = match[3].to_i
    raise ArgumentError, "timezone offset is out of range" if hours > 23 || minutes > 59

    return validate_offset(sign * ((hours * 3600) + (minutes * 60)))
  end

  return nil if timezone.respond_to?(:utc_to_local)

  raise ArgumentError, "timezone must be an offset String, Integer, or timezone object"
end

.jd_to_utc(jd) ⇒ Object



16
17
18
# File 'lib/sekki24/time_scale.rb', line 16

def jd_to_utc(jd)
  Time.at((Float(jd) - UNIX_EPOCH_JD) * SECONDS_PER_DAY).utc
end

.jde_to_utc(jde) ⇒ Object



25
26
27
28
29
30
31
# File 'lib/sekki24/time_scale.rb', line 25

def jde_to_utc(jde)
  utc = jd_to_utc(jde)
  2.times do
    utc = jd_to_utc(Float(jde) - (DeltaT.seconds(decimal_year(utc)) / SECONDS_PER_DAY))
  end
  utc
end

.localize(time, timezone) ⇒ Object

Raises:

  • (ArgumentError)


40
41
42
43
44
45
46
47
48
49
# File 'lib/sekki24/time_scale.rb', line 40

def localize(time, timezone)
  utc_time = coerce_time(time).getutc
  offset = fixed_offset(timezone)
  return utc_time.getlocal(offset) unless offset.nil?

  local = timezone.utc_to_local(utc_time)
  return local if local.is_a?(Time)

  raise ArgumentError, "timezone utc_to_local must return a Time"
end

.timezone_key(timezone) ⇒ Object



51
52
53
54
55
56
57
# File 'lib/sekki24/time_scale.rb', line 51

def timezone_key(timezone)
  offset = fixed_offset(timezone)
  return [:offset, offset].freeze unless offset.nil?

  identifier = timezone.identifier if timezone.respond_to?(:identifier)
  [:timezone, identifier || timezone.object_id].freeze
end

.utc_to_jd(time) ⇒ Object



11
12
13
14
# File 'lib/sekki24/time_scale.rb', line 11

def utc_to_jd(time)
  utc_time = coerce_time(time).getutc
  (utc_time.to_r / SECONDS_PER_DAY) + UNIX_EPOCH_JD
end

.utc_to_jde(time) ⇒ Object



20
21
22
23
# File 'lib/sekki24/time_scale.rb', line 20

def utc_to_jde(time)
  utc_time = coerce_time(time).getutc
  utc_to_jd(utc_time) + (DeltaT.seconds(decimal_year(utc_time)) / SECONDS_PER_DAY)
end