module GreenButtonData::Dst

Constants

BITMASK_DAY_OF_MONTH
BITMASK_DAY_OF_WEEK
BITMASK_DST_RULE
BITMASK_HOUR
BITMASK_MONTH
BITMASK_SECOND

From ESPI XML schema:

extension

Bit map encoded rule from which is calculated the start or

end time, within the current year, to which daylight savings time offset must be applied.

The rule encoding: Bits 0 - 11: seconds 0 - 3599 Bits 12 - 16: hours 0 - 23 Bits 17 - 19: day of the week 0 = not applicable, 1 - 7 (Monday = 1) Bits:20 - 24: day of the month 0 = not applicable, 1 - 31 Bits: 25 - 27: operator (detailed below) Bits: 28 - 31: month 1 - 12

Rule value of 0xFFFFFFFF means rule processing/DST correction is disabled.

The operators:

0: DST starts/ends on the Day of the Month 1: DST starts/ends on the Day of the Week that is on or after the Day of the Month 2: DST starts/ends on the first occurrence of the Day of the Week in a month 3: DST starts/ends on the second occurrence of the Day of the Week in a month 4: DST starts/ends on the third occurrence of the Day of the Week in a month 5: DST starts/ends on the forth occurrence of the Day of the Week in a month 6: DST starts/ends on the fifth occurrence of the Day of the Week in a month 7: DST starts/ends on the last occurrence of the Day of the Week in a month

An example: DST starts on third Friday in March at 1:45 AM. The rule… Seconds: 2700 Hours: 1 Day of Week: 5 Day of Month: 0 Operator: 4 Month: 3

BITSHIFT_DAY_OF_MONTH
BITSHIFT_DAY_OF_WEEK
BITSHIFT_DST_RULE
BITSHIFT_HOUR
BITSHIFT_MONTH

Public Instance Methods

byte_to_dst_datetime(byte, year = Time.now.year) click to toggle source
# File lib/green-button-data/dst.rb, line 51
def byte_to_dst_datetime(byte, year = Time.now.year)
  # Bits 0 - 11: seconds 0 - 3599
  seconds = byte & BITMASK_SECOND

  # Bits 12 - 16: hours 0 - 23
  hour = (byte & BITMASK_HOUR) >> BITSHIFT_HOUR

  # Bits 17 - 19: day of the week; 0 = NA, 1 - 7 (Monday = 1)
  weekday = (byte & BITMASK_DAY_OF_WEEK) >> BITSHIFT_DAY_OF_WEEK

  # Bits 20 - 24: day of the month; 0 = NA, 1 - 31
  day = (byte & BITMASK_DAY_OF_MONTH) >> BITSHIFT_DAY_OF_MONTH

  # Bits 25 - 27: DST rule 0 - 7
  dst_rule = (byte & BITMASK_DST_RULE) >> BITSHIFT_DST_RULE

  # Bits 28 - 31: month 1 - 12
  month = (byte & BITMASK_MONTH) >> BITSHIFT_MONTH

  # Raise an error unless all the values are in valid range
  validate_dst_rules dst_rule, month, weekday, day, hour, seconds

  # In Ruby, Sunday = 0 not 7
  weekday = weekday == 7 ? 0 : weekday

  # Add the hour and seconds component to the day
  dst_datetime dst_rule, year, month, weekday, day, hour, seconds
end
dst_datetime(dst_rule, year, month, weekday, day, hour, seconds) click to toggle source
# File lib/green-button-data/dst.rb, line 80
def dst_datetime(dst_rule, year, month, weekday, day, hour, seconds)
  if dst_rule == 1
    # Rule 1: DST starts/ends on Day of Week on or after the Day of Month
    day_of_month = DateTime.new year, month, day
    day_offset = if weekday >= day_of_month.wday
      weekday - day_of_month.wday
    else
      7 + weekday - day_of_month.wday
    end

    day_of_month + day_offset
  elsif dst_rule.between?(2, 6)
    # Rule 2 - 6: DST starts/ends on Nth Day of Week in given month
    # Nth Day of Week (e.g. third Friday of July)
    nth_weekday_of year, month, weekday, dst_rule - 1
  elsif dst_rule == 7
    # Rule 7: DST starts/ends on last Day of Week in given month
    last_weekday_of year, month, weekday
  else
    # Rule 0: DST starts/ends on the Day of Month
    DateTime.new year, month, day
  end + Rational(hour * 3600 + seconds, 86400)
end
validate_dst_rules(dst_rule, month, weekday, day, hour, seconds) click to toggle source
# File lib/green-button-data/dst.rb, line 104
def validate_dst_rules(dst_rule, month, weekday, day, hour, seconds)
  seconds.between?(0, 3599) and hour.between?(0, 23) and
  weekday.between?(1, 7) and day.between?(0, 31) and
  dst_rule.between?(0, 7) and month.between?(1, 12) or
  raise RangeError, 'Invalid value range'
end