I recently encountered below scenario in drools. I want to know how to proceed with the rule design for this.
Class Emp{
beingDate:Date
endDate:Date
}
Rule to determine annual income for the employee based on the given dates:
For dates before 3/5/2003 the hourly rate is $3.5 and annual multiplier is 2100
For dates after 3/5/2003 the hourly rate changes every year (given data) and annual multiplier is 2092.
There might be scenarios where begin date is before 3/5/2003 and end date is after 3/5/2003.
What is the best way to design rules for this scenario.
Update: added an e.g. for more clarity
If the object is
empObj={
beginDate=10/8/2001,
endDate=5/10/2005
}
The rule should give the sum of below:
3.5 * (no. of days in 2001 starting 10/8/2001) / (total no. of days in 2001) * 2100
3.5 * 2100 ==> This is for year 2002
3.5 * (no. of days in 2003 before 3/5/2003) / (total no. of days in 2003) * 2100
(2003 hourly rate) * (no. of days in 2003 after 3/5/2003) / (total no. of days in 2003) * 2092 ==> note the change in yearly multiplier..
(2004 hourly rate) * 2092
(2005 hourly rate) * (no. of days in 2005 before 5/10/2005) / (total no. of days in 2005) * 2092
One way to do this is to have one rule per year. So it would look something like this
rule "2001"
when:
e : Emp( beginDate < "01-Jan-2002" )
then:
// 1. Get the number of days worked in 2001, probably easiest to do with some Java helper method
// 2. Calculate the sum
// 3. Add the sum to some Fact, could be the same Emp fact even
end
rule "2002"
when:
e : Emp( beginDate < "01-Jan-2003" )
then:
// As with 2001
end
The rest of the rules are very similar, just change the yearly multiplier accordingly. If you decide to use the Emp object to hold the sum, add method like
class Emp {
long sum = 0
void addToSum( long value ) { sum += value }
}
And in your RHS side call the method and update the object on each rule.
Hope this helps.
Related
I have dates that look like "17-JAN-19", "18-FEB-20". When I attempt to use the Dates package Date("17-JAN-19", "d-u-yy") I get reasonably 0019-01-17. I could do Date("17-JAN-19", "d-u-yy") + Year(2000) but that introduces the possibility of new errors (I was going to give the example of leap year but that generally works though there is the very rare error Date("29-FEB-00", "d-u-yy")+Year(1900)).
Is there a date format that embeds known information about century?
As mentioned in https://github.com/JuliaLang/julia/issues/30002 there are multiple heuristics for assigning the century to a date. I would recommend being explicit and handling it through a helper function.
const NOCENTURYDF = DateFormat("d-u-y")
"""
parse_date(obj::AbstractString,
breakpoint::Integer = year(now()) - 2000,
century::Integer = 20)
Parses date in according to DateFormat("d-u-y") after attaching century information.
If the year portion is greater that the current year,
it assumes it corresponds to the previous century.
"""
function parse_date(obj::AbstractString,
breakpoint::Integer = year(now()) - 2000,
century::Integer = 20)
# breakpoint = year(now()) - 2000
# century = year(now()) ÷ 100
#assert 0 ≤ breakpoint ≤ 99
yy = rpad(parse(Int, match(r"\d{2}$", obj).match), 2, '0')
Date(string(obj[1:7],
century - (parse(Int, yy) > breakpoint),
yy),
NOCENTURYDF)
end
parse_date("17-JAN-19")
parse_date("29-FEB-00")
I'm trying to calculate a difference between connection time and disconnected time. See image below. But DATEPART formula that I'm using only allows me to use one parameter (hour, minute, second,...)
However, as in the image, I have an ID where disconnection at 3/1/17 2:35:22PM and connection back at 3/2/17 1:59:38 PM
Ideal Response: 23 hours, 24 minutes and 16 seconds
but using the formula:
ZN(LOOKUP(ATTR(DATEPART('minute', [Disconnected At])),-1)-(ATTR(DATEPART('minute', [Connected At]))))
it isn't doing the trick.
Could someone help me to achieve my ideal response? Or similar result that would give me the completeness of date and time?
Thank You
Tableau ScreenShot
Use DATEDIFF by seconds between your two dates. Then create a calc field as follows:
//replace [Seconds] with whatever field has the number of seconds in it
//and use a custom number format of 00:00:00:00 (drop the first 0 to get rid of leading 0's for days)
IIF([Seconds] % 60 == 60,0,[Seconds] % 60)// seconds
+ IIF(INT([Seconds]/60) %60 == 60, 0, INT([Seconds]/60) %60) * 100 //minutes
+ IIF(INT([Seconds]/3600) % 24 == 0, 0, INT([Seconds]/3600) % 24) * 10000 //hours
+ INT([Seconds]/86400) * 1000000 // days
for more information, check out this blog post where I got this from. http://drawingwithnumbers.artisart.org/formatting-time-durations/
I have a variable with a date table that looks like this
* table:
[day]
* number: 15
[year]
* number: 2015
[month]
* number: 2
How do I get the days between the current date and the date above? Many thanks!
You can use os.time() to convert your table to seconds and get the current time and then use os.difftime() to compute the difference. see Lua Wiki for more details.
reference = os.time{day=15, year=2015, month=2}
daysfrom = os.difftime(os.time(), reference) / (24 * 60 * 60) -- seconds in a day
wholedays = math.floor(daysfrom)
print(wholedays) -- today it prints "1"
as #barnes53 pointed out could be off by one day for a few seconds so it's not ideal, but it may be good enough for your needs.
You can use the algorithms gathered here:
chrono-Compatible Low-Level Date Algorithms
The algorithms are shown using C++, but they can be easily implemented in Lua if you like, or you can implement them in C or C++ and then just provide Lua bindings.
The basic idea using these algorithms is to compute a day number for the two dates and then just subtract them to give you the number of days.
--[[
http://howardhinnant.github.io/date_algorithms.html
Returns number of days since civil 1970-01-01. Negative values indicate
days prior to 1970-01-01.
Preconditions: y-m-d represents a date in the civil (Gregorian) calendar
m is in [1, 12]
d is in [1, last_day_of_month(y, m)]
y is "approximately" in
[numeric_limits<Int>::min()/366, numeric_limits<Int>::max()/366]
Exact range of validity is:
[civil_from_days(numeric_limits<Int>::min()),
civil_from_days(numeric_limits<Int>::max()-719468)]
]]
function days_from_civil(y, m, d)
if m <= 2 then
y = y - 1
m = m + 9
else
m = m - 3
end
local era = math.floor(y/400)
local yoe = y - era * 400 -- [0, 399]
local doy = math.modf((153*m + 2)/5) + d-1 -- [0, 365]
local doe = yoe * 365 + math.modf(yoe/4) - math.modf(yoe/100) + doy -- [0, 146096]
return era * 146097 + doe - 719468
end
local reference_date = {year=2001, month = 1, day = 1}
local date = os.date("*t")
local reference_days = days_from_civil(reference_date.year, reference_date.month, reference_date.day)
local days = days_from_civil(date.year, date.month, date.day)
print(string.format("Today is %d days into the 21st century.",days-reference_days))
os.time (under Windows, at least) is limited to years from 1970 and up. If, for example, you need a general solution to also find ages in days for people born before 1970, this won't work. You can use a julian date conversion and subtract between the two numbers (today and your target date).
A sample julian date function that will work for practically any date AD is given below (Lua v5.3 because of // but you could adapt to earlier versions):
local
function div(n,d)
local a, b = 1, 1
if n < 0 then a = -1 end
if d < 0 then b = -1 end
return a * b * (math.abs(n) // math.abs(d))
end
--------------------------------------------------------------------------------
-- Convert a YYMMDD date to Julian since 1/1/1900 (negative answer possible)
--------------------------------------------------------------------------------
function julian(year, month, day)
local temp
if (year < 0) or (month < 1) or (month > 12)
or (day < 1) or (day > 31) then
return
end
temp = div(month - 14, 12)
return (
day - 32075 +
div(1461 * (year + 4800 + temp), 4) +
div(367 * (month - 2 - temp * 12), 12) -
div(3 * div(year + 4900 + temp, 100), 4)
) - 2415021
end
I've been trying to figure out how to convert a birthday (DateTime) to the astronomically "exact" DateTime value. Timezone: UTC+1.
Example:
My friend was born 1984-01-27 11:35
1984 is a leap year. But 1700, 1800 and 1900 were not leap years. So until the 29. February of the year 2000 we are running behind in astronomoically exact time. In 1984 we are "almost" one day behind. So the astronomoically exact time would be after the official DateTime of my friend's birth, right?
These are the Gregorian calendar tweaks I know of:
Every year has 365 days
Every 4th year is a leap year (= has 366 days instead of 365)
Every 100th year is not a leap year
Every 400th year is a leap year (dispite the previous rule)
The additional day is added at the end of February (February has 29 days in a leap year)
Astronomoically a year has 365,2422 days.
Which means that a day is 24,0159254794 hours long.
A time value where the official and astronomoical times are "exactly" the same would be 2000-03-01T00:00:00, right?
So one would need to figure out how big the discrepancy between the official time and the astronomically exact time is at a given official time.
I've been thinking about it for hours, until my head started hurting. I figured I'll share my headache with you. Maybe you guys know any time library that can calculate this?
I came up with a "solution" that seems to be fairly accurate enough. Here's what it does:
The method starts at 1600-03-01T00:00. 18 years after Pope Gregor XIII. (after whom our Gregorian Calendar system is named) fixed the Julian Calendar (named after Julius Caesar) in 1582 by declaring that after the 4th October (Thursday) the next day would be the 15th October (Friday) - so there is actually no 5th to 14th October 1582 in history books - and also adding the 100th and 400th year rules to the calendar system.
The method sums up the discrepany between the official date and the exact date until the given date is reached.
At leap years it applies the correction added by Pope Gregor XIII. It does so at the end of February.
Code:
public static DateTime OfficialDateTimeToExactDateTime(DateTime dtOfficial)
{
const double dExactDayLengthInHours = 24.0159254794;
DateTime dtParse = new DateTime(1600, 3, 1, 0, 0, 0);
double dErrorInHours = 0.0;
while (dtParse <= dtOfficial)
{
dErrorInHours += dExactDayLengthInHours - 24;
dtParse = dtParse.AddDays(1);
if (dtParse.Month == 3 && dtParse.Day == 1 &&
((dtParse.Year % 4 == 0 && dtParse.Year % 100 != 0) ||
(dtParse.Year % 400 == 0)) )
{
dErrorInHours -= 24;
}
}
dErrorInHours += ((double)dtOfficial.Hour + (double)dtOfficial.Minute / 60 + (double)dtOfficial.Second / 3600) * (dExactDayLengthInHours - 24);
return dtOfficial.AddHours(dErrorInHours * -1);
}
I did some sanity testing:
If you pass a date before 2000-03-01T00:00 you get a negative correction. Because we measure days shorter as they in fact are.
If you pass a date after 2000-03-01T00:00 you get a positive correction. This is because 2000 is a leap year (while 1700, 1800 and 1900 are not), but the correction applied is too big. In 24 x 400 = 4800 years the correction would be about one day too big. So in the year 1600 + 4800 = 6400 (if man is still alive), you would need to delcare 6400 a non-leap year, despite the rules of the Gregorian calendar.
I been working on parsing out bookmarks from an export file generated by google bookmarks. This file contains the following date attributes:
ADD_DATE="1231721701079000"
ADD_DATE="1227217588219000"
These are not standard unix style timestamps. Can someone point me in the right direction here? I'll be parsing them using c# if you are feeling like really helping me out.
Chrome uses a modified form of the Windows Time format (“Windows epoch”) for its timestamps, both in the Bookmarks file and the history files. The Windows Time format is the number of 100ns-es since January 1, 1601. The Chrome format is the number of microseconds since the same date, and thus 1/10 as large.
To convert a Chrome timestamp to and from the Unix epoch, you must convert to seconds and compensate for the difference between the two base date-times (11644473600).
Here’s the conversion formulas for Unix, JavaScript (Unix in milliseconds), Windows, and Chrome timestamps (you can rearrange the +/× and -/÷, but you’ll lose a little precision):
u : Unix timestamp eg: 1378615325
j : JavaScript timestamp eg: 1378615325177
c : Chrome timestamp eg: 13902597987770000
w : Windows timestamp eg: 139025979877700000
u = (j / 1000)
u = (c - 116444736000000) / 10000000
u = (w - 1164447360000000) / 100000000
j = (u * 1000)
j = (c - 116444736000000) / 10000
j = (w - 1164447360000000) / 100000
c = (u * 10000000) + 116444736000000
c = (j * 10000) + 116444736000000
c = (w / 10)
w = (u * 100000000) + 1164447360000000
w = (j * 100000) + 1164447360000000
w = (c * 10)
Note that these are pretty big numbers, so you’ll need to use 64-bit numbers or else handle them as strings like with PHP’s BC-math module.
In Javascript the code will look like this
function chromeDtToDate(st_dt) {
var microseconds = parseInt(st_dt, 10);
var millis = microseconds / 1000;
var past = new Date(1601, 0, 1).getTime();
return new Date(past + millis);
}
1231721701079000 looks suspiciously like time since Jan 1st, 1970 in microseconds.
perl -wle 'print scalar gmtime(1231721701079000/1_000_000)'
Mon Jan 12 00:55:01 2009
I'd make some bookmarks at known times and try it out to confirm.
Eureka! I remembered having read the ADD_DATE’s meaning at some website, but until today, I could not find it again.
http://MSDN.Microsoft.com/en-us/library/aa753582(v=vs.85).aspx
offers this explanation as a “Note” just before the heading “Exports and Imports”:
“Throughout this file[-]format definition, {date} is a decimal integer that represents the number of seconds elapsed since midnight January 1, 1970.”
Before that, examples of {date} were shown:
<DT><H3 FOLDED ADD_DATE="{date}">{title}</H3>
…
and
<DT>{title}
…
Someday, I will write a VBA macro to convert these to recognizable dates, but not today!
If someone else writes a conversion script first, please share it. Thanks.
As of the newest Chrome Version 73.0.3683.86 (Official Build) (64-bit):
When I export bookmark, I got an html file like "bookmarks_3_22_19.html".
And each item has an 'add_date' field which contains date string. like this:
Stack Overflow
This timestamp is actually seconds (not microseconds) since Jan 1st, 1970. So we can parse it with Javascript like following code:
function ChromeTimeToDate(timestamp) {
var seconds = parseInt(timestamp, 10);
var dt = new Date();
dt.setTime(seconds * 1000);
return dt;
}
For the upper example link, we can call ChromeTimeToDate('1553220774') to get Date.
ChromeTimeToDate('1553220774')
12:09:03.263 Fri Mar 22 2019 10:12:54 GMT+0800 (Australian Western Standard Time)
Initially looking at it, it almost looks like if you chopped off the last 6 digits you'd get a reasonable Unix Date using the online converter
1231721701 = Mon, 12 Jan 2009 00:55:01 GMT
1227217588 = Thu, 20 Nov 2008 21:46:28 GMT
The extra 6 digits could be formatting related or some kind of extended attributes.
There is some sample code for the conversion of Unix Timestamps if that is in fact what it is.
look here for code samples: http://www.epochconverter.com/#code
// my groovy (java) code finally came out as:
def convertDate(def epoch)
{
long dv = epoch / 1000; // divide by 1,000 to avoid milliseconds
String dt = new java.text.SimpleDateFormat("dd/MMM/yyyy HH:mm:ss").format(new java.util.Date (dv));
// to get epoch date:
//long epoch = new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970 01:00:00").getTime() * 1000;
return dt;
} // end of def
So firefox bookmark date exported as json gave me:
json.lastModified :1366313580447014
convert from epoch date:18/Apr/2013 21:33:00
from :
println "convert from epoch date:"+convertDate(json.lastModified)
function ConvertToDateTime(srcChromeBookmarkDate) {
//Hp --> The base date which google chrome considers while adding bookmarks
var baseDate = new Date(1601, 0, 1);
//Hp --> Total number of seconds in a day.
var totalSecondsPerDay = 86400;
//Hp --> Read total number of days and seconds from source chrome bookmark date.
var quotient = Math.floor(srcChromeBookmarkDate / 1000000);
var totalNoOfDays = Math.floor(quotient / totalSecondsPerDay);
var totalNoOfSeconds = quotient % totalSecondsPerDay;
//Hp --> Add total number of days to base google chrome date.
var targetDate = new Date(baseDate.setDate(baseDate.getDate() + totalNoOfDays));
//Hp --> Add total number of seconds to target date.
return new Date(targetDate.setSeconds(targetDate.getSeconds() + totalNoOfSeconds));
}
var myDate = ConvertToDateTime(13236951113528894);
var alert(myDate);
//Thu Jun 18 2020 10:51:53 GMT+0100 (Irish Standard Time)
#Python program
import time
d = 1630352263 #for example put here, if (ADD_DATE="1630352263")
print(time.ctime(d)) #Mon Aug 30 22:37:43 2021 - you will see