I been analyzing the proper calculation of the duedate for my app. I am working with a lending app where I need to display the due date for the borrower.
let say the approved date of their loan is 2019-10-27 and today is 11-5-2019. the payment scheme is dynamic. depending on what the admin set. in this example, the payment scheme weekly so I just need to say;
$duedate = date('M d Y', strtotime($loan_application->date_approval. ' + '.$loan_application->scheme->num_days.' days') );
from my example above the due date is supposedly on Nov 3, 2019. Now how can I make it say that the next due date is on Nov 10, 2019?
I really tried to analyze, here's my thought.
I get the difference between the approval date and NOW()
$diff = Carbon::createFromTimestamp(strtotime($loan_application->date_approval))->diff(Carbon::now())->days;
now I compared the $diff with $loan_application->scheme->num_days. so let say the $diff=9 and $loan_application->scheme->num_days = 7
now I created the condition
if ($diff > $loan_application->scheme->num_days) {
//should display
Nov 10, 2019
//because the current date is already Nov 5
}
and after Nov 10, + 7 days again, and + 7 days again and so on.
here is the complete code I already have;
$dateApproved = Carbon::parse($loan_application->date_approval)->toFormattedDateString();
$now = Carbon::today('M d Y');
$duedate = date('M d Y', strtotime($loan_application->date_approval. ' + '.$loan_application->scheme->num_days.' days') );
$diff = Carbon::createFromTimestamp(strtotime($loan_application->date_approval))->diff(Carbon::now())->days;
$numOfScheme = $loan_application->loanDuration->num_days / $loan_application->scheme->num_days;
if ($diff > $loan_application->scheme->num_days) {
}
I hope you understand my question. Please help. Thank you so much in advance.
this will add number of days from payment scheme. in my example 7 days. but how can I tell my code that today is already 2 days late, add additional 7 days
It took some time but I understood your question.
$date_approval = Carbon::createFromTimestamp(strtotime($loan_application->date_approval));
$scheme_numdays = $loan_application->scheme->num_days;
$days = (intdiv($date_approval->diff(Carbon::now())->days , $scheme_numdays) + 1) * $scheme_numdays
$due_date = $date_approval->addDays($days)->format('M d Y');
intdiv is just php's integer division.
In my project i get from external system date&time in VARIANT DATE type and need to convert it to datetime (i.e. 43347.6625 => 04/09/2018 16:29:59).
Do you know how to do it in ruby? what is the best approach? I did not find any ruby built-in method to do such a conversion...
here a method to do the calculation, the date you give is not correct, it should be what this method is returning, check with https://planetcalc.com/7027/
def variant2datetime variant
# number of days after 1-1-1900 minus 2 days for starting with 0
# and having a day that didn't exist because 1900 wasn't a leap year
date = Time.new("1900-01-01") + (variant.to_i - 2) * 24 * 60 * 60
fraction = variant % 1
hours = (fraction - fraction.to_i) * 24
minutes = (hours - hours.to_i) * 60
seconds = (minutes - minutes.to_i) * 60
Time.new(date.year, date.month, date.day, hours.to_i, minutes.to_i, seconds.to_i)
end
variant2datetime 43347.6625 # 2018-09-04 15:53:59 +0200
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
~ 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.
I currently have code that creates a CTime object from a defined value.
#define TIME_VALUE 0x301DDF00 // Aug 1, 1995 # 04:00:00
CTime t = CTime( TIME_VALUE );
This creates the desired date of Aug 1, 1995 04:00:00
I can no longer use CTime so I am trying to use time_t and tm instead. Since the CTime constructor takes in the number of seconds since Jan 1, 1970 and time_t represents the number of seconds since Jan 1, 1970, I tried to use the following code.
#define TIME_VALUE 0x301DDF00 // Aug 1, 1995 # 04:00:00
time_t tmpTime = TIME_VALUE;
struct tm createTime;
if( localtime_s( &createTime, &tmpTime ) == S_OK )
{
// Use createTime
}
createTime ends up as August 1, 0095 04:00:00. How am I supposed to go from the defined value to a time_t and tm successfully?
Thanks in advance.
Sorry. I didn't look at the tm documentation closely enough. The year is the actual year minus 1900 and the month is zero based. I got it now.