Skip to content

Commit

Permalink
Make working with Instant easier
Browse files Browse the repository at this point in the history
Signed-off-by: Jimmy Tanagra <jcode@tanagra.id.au>
  • Loading branch information
jimtng authored and ccutrer committed Sep 19, 2024
1 parent 2d2789e commit d46e1d7
Show file tree
Hide file tree
Showing 18 changed files with 579 additions and 38 deletions.
11 changes: 11 additions & 0 deletions lib/openhab/core/types/date_time_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,17 @@ def to_zoned_date_time(context = nil) # rubocop:disable Lint/UnusedMethodArgumen
zoned_date_time
end

# @!visibility private
def to_instant(_context = nil)
# @deprecated OH 3.4 getInstant() was added in OH 4.0
return get_instant if respond_to?(:get_instant)

zoned_date_time.to_instant
end

# @!method to_instant
# @return [Instant]

# act like a Ruby Time
def_delegator :zoned_date_time, :month_value, :month
def_delegator :zoned_date_time, :day_of_month, :mday
Expand Down
140 changes: 138 additions & 2 deletions lib/openhab/core_ext/java/instant.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,148 @@
# frozen_string_literal: true

require "forwardable"

require_relative "time"

module OpenHAB
module CoreExt
module Java
java_import java.time.Instant
Instant = java.time.Instant

# Extensions to {java.time.Instant}
class Instant < java.lang.Object; end
class Instant < java.lang.Object
extend Forwardable
include Time
include Between

class << self # rubocop:disable Lint/EmptyClass
# @!scope class

# @!attribute [r] now
# @return [Instant]

# @!method parse(text, formatter = nil)
# Parses a string into an Instant object.
#
# @param [String] text The text to parse.
# @param [java.time.format.DateTimeFormatter] formatter The formatter to use.
# @return [Instant]
end

# @!scope instance

# @!method to_local_time
# @return [LocalTime]
# @!method to_local_date
# @return [LocalDate]
# @!method to_month_day
# @return [MonthDay]
# @!method to_date
# @return [Date]
# @!method to_month
# @return [Month]
# @!method yesterday?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#yesterday?)
# @!method today?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#today?)
# @!method tomorrow?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#tomorrow?)
def_delegators :to_zoned_date_time,
:to_local_time,
:to_local_date,
:to_date,
:to_month_day,
:to_month,
:yesterday?,
:today?,
:tomorrow?

# @param [TemporalAmount, #to_instant, #to_zoned_date_time, Numeric] other
# If other is a Numeric, it's interpreted as seconds.
# @return [Duration] If other responds to #to_zoned_date_time
# @return [Instant] If other is a TemporalAmount
def -(other)
if other.is_a?(Instant)
java.time.Duration.between(other, self)
elsif other.respond_to?(:to_instant)
java.time.Duration.between(other.to_instant, self)
elsif other.respond_to?(:to_zoned_date_time)
java.time.Duration.between(other.to_zoned_date_time.to_instant, self)
elsif other.is_a?(Numeric)
minus(other.seconds)
else
minus(other)
end
end

# @param [TemporalAmount, Numeric] other
# If other is a Numeric, it's interpreted as seconds.
# @return [Instant]
def +(other)
return plus(other.seconds) if other.is_a?(Numeric)

plus(other)
end

#
# The number of seconds since the Unix epoch.
# @return [Integer]
#
def to_i
epoch_second
end

#
# The number of seconds since the Unix epoch.
# @return [Float]
#
def to_f
((epoch_second * 1_000_000_000) + nano).fdiv(1_000_000_000.0)
end

# This comes from JRuby

# @!method to_time
# @return [Time]

# @return [Integer, nil]
def <=>(other)
logger.trace { "(#{self.class}) #{self} <=> #{other} (#{other.class})" }
# compare instants, otherwise it will differ by timezone, which we don't want
# (use eql? if you care about that)
if other.respond_to?(:to_instant)
logger.trace { "Comparing #{self} to #{other.to_instant}" }
compare_to(other.to_instant(to_zoned_date_time))
elsif other.respond_to?(:coerce) && (lhs, rhs = other.coerce(self))
lhs <=> rhs
end
end

# @param [ZonedDateTime, nil] context A {ZonedDateTime} used to match the zone id. Defaults to UTC.
# @return [ZonedDateTime]
def to_zoned_date_time(context = nil)
zone = context&.zone || java.time.ZoneOffset::UTC
at_zone(zone)
end

# @!visibility private
def to_instant(_context = nil)
self
end

#
# Converts `other` to {Instant}, if possible
#
# @param [#to_instant] other
# @return [Array, nil]
#
def coerce(other)
logger.trace { "Coercing #{self} as a request from #{other.class}" }
return [other.to_instant(to_zoned_date_time), self] if other.respond_to?(:to_instant)

[other.to_zoned_date_time(zoned_date_time).to_instant, self] if other.respond_to?(:to_zoned_date_time)
end
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/openhab/core_ext/java/local_date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ def to_zoned_date_time(context = nil)
zone = context&.zone || java.time.ZoneId.system_default
at_start_of_day(zone)
end

# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in missing fields
# during conversion. {ZonedDateTime.now} is assumed if not given.
# @return [Instant]
def to_instant(context = nil)
zone = context&.zone || java.time.ZoneOffset::UTC
at_start_of_day(zone).to_instant
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/openhab/core_ext/java/local_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ def to_zoned_date_time(context = nil)
context ||= ZonedDateTime.now
context.with(self)
end

# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in missing fields
# during conversion. {ZonedDateTime.now} is assumed if not given.
# @return [Instant]
def to_instant(context = nil)
context ||= Instant.now.to_zoned_date_time
to_zoned_date_time(context).to_instant
end
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/openhab/core_ext/java/month.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ def to_month_day
def to_zoned_date_time(context = nil)
to_local_date(context).to_zoned_date_time(context)
end

# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in the year during conversion,
# with the date set to the first day of the month.
# {Instant.now} is assumed if not given.
# @return [Instant]
def to_instant(context = nil)
context ||= Instant.now.to_zoned_date_time
to_local_date(context).to_instant
end
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/openhab/core_ext/java/month_day.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,15 @@ def to_month_day
def to_zoned_date_time(context = nil)
to_local_date(context).to_zoned_date_time(context)
end

# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in missing year during conversion,
# {ZonedDateTime.now} is assumed if not given.
# @return [Instant]
def to_instant(context = nil)
context ||= Instant.now.to_zoned_date_time
to_local_date(context).to_instant
end
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/openhab/core_ext/java/time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ def self.included(klass)
# less than, equal to, or greater than self
#
def <=>(other)
logger.trace { "(#{self.class}) #{self} <=> #{other} (#{other.class})" }
if other.is_a?(self.class)
compare_to(other)
elsif other.respond_to?(:coerce)
Expand All @@ -50,6 +51,7 @@ def <=>(other)
# Convert `other` to this class, if possible
# @return [Array, nil]
def coerce(other)
logger.trace { "Coercing #{self} as a request from #{other.class}" }
coercion_method = self.class.coercion_method
return unless other.respond_to?(coercion_method)
return [other.send(coercion_method), self] if other.method(coercion_method).arity.zero?
Expand Down
30 changes: 24 additions & 6 deletions lib/openhab/core_ext/java/zoned_date_time.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "forwardable"

require_relative "time"

module OpenHAB
Expand All @@ -9,6 +11,7 @@ module Java

# Extensions to {java.time.ZonedDateTime}
class ZonedDateTime
extend Forwardable
include Time
include Between

Expand Down Expand Up @@ -60,20 +63,20 @@ def +(other)
end

#
# @!method to_i
# The number of seconds since the Unix epoch.
#
# @return [Integer]
def to_i
to_instant.epoch_second
end
#

#
# @!method to_f
# The number of seconds since the Unix epoch.
#
# @return [Float]
def to_f
to_instant.to_epoch_milli / 1000.0
end
#

delegate %i[to_i to_f] => :to_instant

# @return [Date]
def to_date
Expand Down Expand Up @@ -226,13 +229,28 @@ def <=>(other)
end
end

# @!visibility private
alias_method :raw_to_instant, :to_instant

# @!visibility private
def to_instant(_context = nil)
raw_to_instant
end

#
# @!method to_instant
# Converts this object to an {Instant}
# @return [Instant]
#

#
# Converts `other` to {ZonedDateTime}, if possible
#
# @param [#to_zoned_date_time] other
# @return [Array, nil]
#
def coerce(other)
logger.trace { "Coercing #{self} as a request from #{other.class}" }
[other.to_zoned_date_time(self), self] if other.respond_to?(:to_zoned_date_time)
end
end
Expand Down
25 changes: 18 additions & 7 deletions lib/openhab/core_ext/ruby/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ def to_month_day
java.time.MonthDay.of(month, day)
end

# @!method yesterday?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#yesterday?)
# @!method today?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#today?)
# @!method tomorrow?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#tomorrow?)
def_delegators :to_zoned_date_time, :yesterday?, :today?, :tomorrow?

# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in missing fields during conversion.
# {OpenHAB::CoreExt::Java::ZonedDateTime.now ZonedDateTime.now} is assumed
Expand All @@ -64,13 +72,15 @@ def to_zoned_date_time(context = nil)
to_local_date.to_zoned_date_time(context)
end

# @!method yesterday?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#yesterday?)
# @!method today?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#today?)
# @!method tomorrow?
# (see OpenHAB::CoreExt::Java::ZonedDateTime#tomorrow?)
def_delegators :to_zoned_date_time, :yesterday?, :today?, :tomorrow?
# @param [ZonedDateTime, nil] context
# A {ZonedDateTime} used to fill in missing fields during conversion.
# {OpenHAB::CoreExt::Java::ZonedDateTime.now ZonedDateTime.now} is assumed
# if not given.
# @return [Instant]
def to_instant(context = nil)
context ||= Instant.now.to_zoned_date_time
to_zoned_date_time(context).to_instant
end

# @return [Integer, nil]
def compare_with_coercion(other)
Expand All @@ -94,6 +104,7 @@ def compare_with_coercion(other)
# @return [Array, nil]
#
def coerce(other)
logger.trace { "Coercing #{self} as a request from #{other.class}" }
return nil unless other.respond_to?(:to_date)
return [other.to_date, self] if other.method(:to_date).arity.zero?

Expand Down
6 changes: 6 additions & 0 deletions lib/openhab/core_ext/ruby/date_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,14 @@ def to_zoned_date_time(context = nil) # rubocop:disable Lint/UnusedMethodArgumen
to_java(ZonedDateTime)
end

# @return [Instant]
def to_instant(_context = nil)
to_java(Instant)
end

# (see Time#coerce)
def coerce(other)
logger.trace { "Coercing #{self} as a request from #{other.class}" }
return unless other.respond_to?(:to_zoned_date_time)

zdt = to_zoned_date_time
Expand Down
Loading

0 comments on commit d46e1d7

Please sign in to comment.