I want to check if Time.now is between two times (start, end) values which are stored as String in a two columns with the "%I:%M:%S" format.
I get the same format if I use Time.now.strftime("%I:%M:%S") ... but then I'm lost.
Try something like:
n = Time.now
t1 = Time.parse('1:30:4')
t2 = Time.parse('3:30:4')
n.to_f > t1.to_f and n.to_f < t2.to_f
I solved it, by using "time without time zone" in the columns "start" and "end" format.
Also, to check if the Time.now is between the values stored in the database I use Time.zone.now.
start < Time.zone.now
and end > Time.zone.now
You can convert the time to seconds since midnight and compare integers.
require 'date'
range_start = 79200 # 10pm (22 * 60 * 60)
range_end = 82800 # 11pm (23 * 60 * 60)
time_since_midnight = Time.now.to_i - Date.today.to_time.to_i
#Check if the the time now is between 10pm and 11pm
print time_since_midnight.between?(range_start, range_end)
I want to trigger a notification for all my users at a specific time in their time zone. I want to compute the delay the server should wait before firing the notification. I can compute the time at the users Time Zone using Time.now.in_time_zone(person.time_zone)
I can strip out the hours, minutes and seconds from that time and find out the seconds remaining to the specific time. However, I was wondering if there's a more elegant method where I could set 9:00 AM on today and tomorrow in a timezone and compare it with Time.now.in_time_zone(person.time_zone) and just find out the number of seconds using arithmetic operations in the ruby Time Class.
Or in short my question is: (was: before the downvote!)
How do I compute the number of seconds to the next 9:00 AM in New York?
What about this
next9am = Time.now.in_time_zone(person.time_zone).seconds_until_end_of_day + 3600 * 9
next9am -= 24 * 60 * 60 if Time.now.in_time_zone(person.time_zone).hour < 9
NOTIFICATION_HOUR = 9
local_time = Time.now.in_time_zone(person.time_zone)
desired_time = local_time.hour >= NOTIFICATION_HOUR ? local_time + 1.day : local_time
desired_time = Time.new(desired_time.year, desired_time.month, desired_time.day, NOTIFICATION_HOUR, 0, 0, desired_time.utc_offset)
return desired_time - local_time
How can I determine the number of days between two Time instances in Ruby?
> earlyTime = Time.at(123)
> laterTime = Time.now
> time_difference = laterTime - earlyTime
I'd like to determine the number of days in time_difference (I'm not worried about fractions of days. Rounding up or down is fine).
Difference of two times is in seconds. Divide it by number of seconds in 24 hours.
(t1 - t2).to_i / (24 * 60 * 60)
require 'date'
days_between = (Date.parse(laterTime.to_s) - Date.parse(earlyTime.to_s)).round
Edit ...or more simply...
require 'date'
(laterTime.to_date - earlyTime.to_date).round
earlyTime = Time.at(123)
laterTime = Time.now
time_difference = laterTime - earlyTime
time_difference_in_days = time_difference / 1.day # just divide by 1.day
[1] pry(main)> earlyTime = Time.at(123)
=> 1970-01-01 01:02:03 +0100
[2] pry(main)> laterTime = Time.now
=> 2014-04-15 11:13:40 +0200
[3] pry(main)> (laterTime.to_date - earlyTime.to_date).to_i
=> 16175
To account for DST (Daylight Saving Time), you'd have to count it by the days. Note that this assumes less than a day is counted as 1 (rounded up):
num = 0
cur = start_time
while cur < end_time
num += 1
cur = cur.advance(:days => 1)
end
return num
Here is a simple answer that works across DST:
numDays = ((laterTime - earlyTime)/(24.0*60*60)).round
60*60 is the number of seconds in an hour
24.0 is the number of hours in a day. It's a float because some days are a little more than 24 hours, some are less. So when we divide by the number of seconds in a day we still have a float, and round will round to the closest integer.
So if we go across DST, either way, we'll still round to the closest day. Even if you're in some weird timezone that changes more than an hour for DST.
in_days (Rails 6.1+)
Rails 6.1 introduces new ActiveSupport::Duration conversion methods like in_seconds, in_minutes, in_hours, in_days, in_weeks, in_months, and in_years.
As a result, now, your problem can be solved as:
date_1 = Time.parse('2020-10-18 00:00:00 UTC')
date_2 = Time.parse('2020-08-13 03:35:38 UTC')
(date_2 - date_1).seconds.in_days.to_i.abs
# => 65
Here is a link to the corresponding PR.
None of these answers will actually work if you don't want to estimate and you want to take into account daylight savings time.
For instance 10 AM on Wednesday before the fall change of clocks and 10 AM the Wednesday afterwards, the time between them would be 1 week and 1 hour. During the spring it would be 1 week minus 1 hour.
In order to get the accurate time you can use the following code
def self.days_between_two_dates later_time, early_time
days_between = (later_time.to_date-early_time.to_date).to_f
later_time_time_of_day_in_seconds = later_time.hour*3600+later_time.min*60+later_time.sec
earlier_time_time_of_day_in_seconds = early_time.hour*3600+early_time.min*60+early_time.sec
days_between + (later_time_time_of_day_in_seconds - early_time_time_of_day_in_seconds)/1.0.day
end
~ Approximate Solar Noon
lw = 88.743 # my longitude
jdate = Date.ordinal_to_jd(Time.now.year, Time.now.yday)
n = (jdate - 2451545 - 0.0009 - lw / 360).round # lw is users longitude west of 0.
j_noon = 2451545 + 0.0009 + lw / 360 + n
puts j_noon
=> 2455616.24740833
As an update, part of the confusion would be that solar noon is where all
calculations started since January 1, 4713 BC Greenwich noon.
The correct use of Date.ordinal_to_jd has not compensated for this fact. So by
adding or subtracting 12 hours like this:
jdn = Date.ordinal_to_jd(Time.now.year, Time.now.yday) - 0.5
we should get less errors. Just which do we use though since our calculations
start with yesterdays noon?
The code is derived from the two equations from this page Sunrise_equation.
The first answer I got from a user here was that we don't understand the use of
0.0009 and lw / 360. lw / 360 would appear to be a fractional day of arc from the
prime meridian. As for the 0.0009, it must be a small amount of variance in
seconds since January 1, 4713 BC Greenwich noon. see IAU standards for more info
I calculate it to be 0.007776 seconds according to this page.
I have a little bit of info from Date class not including method details.
=begin
--------------------------------------------------------------------- Class: Date
Class representing a date.
See the documentation to the file date.rb for an overview.
Internally, the date is represented as an Astronomical Julian Day Number, ajd.
The Day of Calendar Reform, sg, is also stored, for conversions to other date formats.
(There is also an of field for a time zone offset,
but this is only for the use of the DateTime subclass.)
A new Date object is created using one of the object creation class methods named
after the corresponding date format, and the arguments appropriate to that date
format; for instance, Date::civil()
(aliased to Date::new()) with year, month, and day-of-month, or Date::ordinal() with
year and day-of-year.
All of these object creation class methods also take the Day of Calendar Reform as an
optional argument.
Date objects are immutable once created.
Once a Date has been created, date values can be retrieved for the different date
formats supported using instance methods. For instance, #mon() gives the Civil month,
#cwday() gives the Commercial day of the week, and #yday() gives the Ordinal day of
the year. Date values can be retrieved in any format, regardless of what format was
used to create the Date instance.
The Date class includes the Comparable module, allowing date objects to be compared
and sorted, ranges of dates to be created, and so forth.
---------------------------------------------------------------------------------
Includes:
Comparable(<, <=, ==, >, >=, between?)
Constants:
MONTHNAMES: [nil] + %w(January February March April May June July August
September October November December)
DAYNAMES: %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
ABBR_MONTHNAMES: [nil] + %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
ABBR_DAYNAMES: %w(Sun Mon Tue Wed Thu Fri Sat)
ITALY: 2299161
ENGLAND: 2361222
JULIAN: Infinity.new
GREGORIAN: -Infinity.new
Class methods:
_load, _parse, _strptime, ajd_to_amjd, ajd_to_jd, amjd_to_ajd, civil, civil_to_jd,
commercial, commercial_to_jd, day_fraction_to_time, gregorian?, gregorian_leap?, jd,
jd_to_ajd, jd_to_civil, jd_to_commercial, jd_to_ld, jd_to_mjd, jd_to_ordinal,
jd_to_wday, julian?, julian_leap?, ld_to_jd, mjd_to_jd, new, now, ordinal,
ordinal_to_jd, parse, s3e, strptime, time_to_day_fraction, today, valid_civil?,
valid_commercial?, valid_jd?, valid_ordinal?, valid_time?
Instance methods:
+, -, <<, <=>, ===, >>, _dump, ajd, amjd, asctime, civil, commercial, ctime, cwday,
cweek, cwyear, day, day_fraction, downto, england, eql?, gregorian, gregorian?, hash,
hour, inspect, italy, jd, julian, julian?, ld, leap?, mday, min, mjd, mon, month,
new_offset, new_start, next, next_day, offset, ordinal, sec, sec_fraction, start,
step, strftime, succ, time, to_s, to_yaml, upto, wday, weeknum0, weeknum1, wnum0,
wnum1, yday, year, zone
=end
As a side note, it's great that Ruby has a way to calculate the julian-date.
I'm looking into the Javascript code from NOAA.
Here is a class that I was inspired to write by the link.
class JulianDayNumber
def initialize(year = 2000, month = 1, day = 1) #defaults to Jan. 01, 2000
#year = year
#month = month
#day = day
end
def calcJDN
if (#month <= 2) then
#year -= 1
#month += 12
end
varA = (#year/100).floor
varB = 2 - varA + (varA/4).floor
jdn = (365.25*(#year + 4716)).floor \
+ (30.6001*(#month+1)).floor \
+ #day + varB - 1524.5
return jdn
end
end
jd = JulianDayNumber.new(2011, 3, 2)
julianday = jd.calcJDN
puts julianday
=> 2455622.5
Now this gets me there but I'm still researching for the way back for a number such
as the one calculated by the top most equation. Trying this we can see that we do
get a 0.5 in the JDN. Who is right? Ruby or NOAA?
NOAA uses the January 1st 2000 value of 2451545.0 that is subtracted from the jd to get time
in fractional century like this
def calcTimeJulianCent(j)
t = (j - 2451545.0)/36525.0
return t
end
Ruby has a number of ways of calculating Julian Day and you need to pick the right one. NOAA is calculating the JD since January 1, 4713 BC Greenwich noon as you know. It always ends in .5 because they are leaving out the fractional days.
Ruby's Julian Day is weird:
For scientific purposes, it is
convenient to refer to a date simply
as a day count, counting from an
arbitrary initial day. The date first
chosen for this was January 1, 4713
BCE. A count of days from this date is
the Julian Day Number or Julian Date,
which is abbreviated as jd in the Date
class. This is in local time, and
counts from midnight on the initial
day.
Which makes no sense for astronomical use. but wait..
The stricter usage is in UTC, and
counts from midday on the initial day.
This is referred to in the Date class
as the Astronomical Julian Day Number,
and abbreviated as ajd. In the Date
class, the Astronomical Julian Day
Number includes fractional days.
(rubydoc)
This is what you are looking for, ajd. Just get it without the fractional days:
julianday = Date.civil(#year, #month, #day).ajd
puts julianday
=> 2455622.5
No need to port 9 lines of JavaScript from NOAA. Ruby's got your back! ;)
Well thanks everybody, I guess that I can answer my own question now. I overlooked a simple method in the Date class. It is Date.day_fraction_to_time(day fractional). As I have a working program now I would like to share it with eveyone.
include Math
to_r = PI / 180.0
to_d = 180.0 / PI
latitude = 41.9478 # my latitude
longitude = 88.74277 # my longitude
lw = longitude / 360
jdate = Date.civil(Time.now.year, Time.now.month, Time.now.day).ajd
jdate = (jdate * 2).to_i/2 + 1
n = (jdate - 2451545 - 0.0009 - lw).round
j_noon = 2451545 + 0.0009 + lw + n
mean_anomaly = (357.52911 + 0.98560028 * (jdate - 2451545)) % 360
center = 1.9148 * sin(mean_anomaly * to_r) + 0.0200 * sin(2 * mean_anomaly * to_r) + \
0.0003 * sin(3 * mean_anomaly * to_r)
lambda = (mean_anomaly + 102.9372 + center + 180) % 360
j_transit = j_noon + (0.0053 * sin(mean_anomaly * to_r)) - (0.0069 * sin(2 * lambda * \
to_r))
delta = asin(0.397753054 * sin(lambda * to_r)) * to_d
omega = acos(sin(-0.83 * to_r)/cos(latitude * to_r) * cos(delta * to_r) \
- tan(latitude * to_r) * tan(delta * to_r)) * to_d
j_set = 2451545 + 0.0009 + ((omega + longitude)/360 + n + 0.0053 * sin(mean_anomaly * \
to_r)) - 0.0069 * sin(2 * lambda * to_r)
j_rise = j_transit - (j_set - j_transit)
rise = Date.day_fraction_to_time(j_rise - jdate)# + 0.25 for + 6 hours
risehour = rise[0].to_s
risemin = rise[1].to_s
risetime = "#{risehour}:#{risemin}"
puts "Sun rise = #{risetime} UTC"
transit = Date.day_fraction_to_time(j_transit - jdate)# + 0.25
transithour = transit[0].to_s
transitmin = transit[1].to_s
transittime = "#{transithour}:#{transitmin}"
puts "Solar noon = #{transittime} UTC"
set = Date.day_fraction_to_time(j_set - jdate)# + 0.25
sethour = set[0].to_s
setmin = set[1].to_s
settime = "#{sethour}:#{setmin} UTC"
puts "Sun set = #{settime}"
The method ordinal_to_jd converts the day with index 0 of the year 2011 (Gregorian calendar) to the corresponding day in the Julian calendar, then you are using the magical value of 0.0009 for which i dont know any reason, then you are adding the ratio of your longitude (east or west?) of the whole 360* circle and then adding todays day-of-year (54 if you evaluated it today). The combination of Julian calendar and longitudinal ratio makes not much sense, but hey its a nice number since you mixed a 0.0009 in.