ScheduleExpression for every 40 days? - ejb-3.0

How can I declare a timer which is invoked every x days? For example, I want to invoke the timer every 40 days. How should I setup my timer? I cannot convert "40 days" to hours as hours expects a range between 0-23. I cannot put 40 days in dayOfMonth as it expects a range between 1 to 31. So how should I do that?
ScheduleExpression expression = new ScheduleExpression();
expression.second("0").minute("0").hour("0").dayOfMonth("40");

You can try the below method of TimerService interface to create a interval timer, that will expire every 40 days by specifying that duration as intervalDuration after initialization of it by initialDuration in milliseconds.
createTimer(long initialDuration, long intervalDuration, java.io.Serializable info)
Create an interval timer whose first expiration occurs after a specified duration, and whose subsequent expirations occur after a specified interval.

Related

Round millseconds timestamp to nearest 30 seconds

I have following ruby code to get current time in "milliseconds", for example: 1648059542287 which is equivalent to Wed Mar 23 2022 18:19:02
What I need is timestamp rounded to nearest 30 seconds, for above example, I need it rounded to 1648059540000. Any suggestions?
#ctime = Time.now.to_f
(#ctime * 1000).to_i
Using the time you provided, I think this will do what you want:
Take your time, convert it to an integer
divide by floating point value 30 the number of half minutes
round that value and multiple by 30 to get back to the number of seconds
Create a new time object based on the rounded value.
input = Time.at(1648059542,287000)
Time.at((input.to_i / 30.0).round * 30)

Relative time calculation

I have an application implementing RESTful API. I have two methods create_order and order_status. The first method creates order and persists it with the current time in the order.time field:
order.time = Time.now
The second method responds with a hardcoded value:
:eta => 20.minutes.from_now.to_i
Instead of returning the hardcoded 20 minutes, how can I return the relative value that decreases with elapsed time (depending on the time when status request was made)?
At the beginning of the order, they are the same (20.minutes.from_now.to_i), but if the request is made after 5 mins, it should be 15.minutes.from_now.to_i.
I would save some other attribute along with order.time
For example : order.eta = Time.now + 1200
Or else : order.processing_time = 1200 and then order.eta could be calculated.
I like the second solution better, enabling different processing times for different orders.

What is the value of the ISO 8601 duration `P1M` (in seconds)?

Suppose I have an ISO 8601 duration, expressed as "P1M". Phrased colloquially, this means "one month." Is there a standard rule for converting this into a number of seconds, assuming the start date is not known?
For 30-day months, it might be 2,592,000.
For 31-day months, it might be 2,678,400.
In February, it might be 2,419,200 or it might be 2,505,600.
My gut says there's no way to resolve "one month" to an exact number of seconds without knowing context, and where those seconds are laid out on the calendar. But are there standard rules/conventions to calculate these durations in an abstract way?
From ISO 8601 documentation that I found (page 6 - http://xml.coverpages.org/ISO-FDIS-8601.pdf), it seems you are correct in that the number of seconds in a month cannot definitively be determined. However it does note that "In certain applications a month is regarded as a unit of time of 30 days", so depending on your application this may be a valid approach.
The distinction between "Calendar Time" (Years, Months, etc) and "Absolute Time" (Hours, Minutes, Seconds, etc) is sometimes an important one. As an example, some people might complain about having 13 mortgage payments some years if they paid every 30 days as opposed to every month.
You are right, an ISO 8601 duration is dependent of the context.
A duration is a period/an interval of time between two dates.
Example :
2020-01-01/2020-02-01 = P1M = P31D
2020-02-01/2020-03-01 = P1M = P29D
2019-02-01/2019-03-01 = P1M = P28D
If you want a fixed duration indepedent of the context, use the day notation P30D, P60D, P90D... instead.
The same applies for years :
2019-01-01/2020-01-01 = P1Y = P12M = P365D
2020-01-01/2021-01-01 = P1Y = P12M = P366D
If you can't have context information about a duration, for example P1M retrieved from database or given by user input, use by default today's context.
//What is a duration of one month in seconds ?
P1M = ? (no context)
//Use default context
Today = 2020-03-31
2020-03-31/P1M = 2020-03-31/2020-04-30
=> P1M = P30D
//A month contains 2 592 000 seconds

Simple Add to time and compare GO

Hi I can't seem to get my head around the correct way to do time arithmetic in Go.
I have a time "object" later initialized to Now() and stored.
insertTime time.Time
Later, I need to see if the item is older than 15 minutes.
How do i do this?
Do I need to create a Duration of 15 Minutes add it to the current time and compare? If so, how do I do that?
func (Time) After will be helpful, I believe. Schema:
when := time.Now()
...
if time.Now().After(when.Add(15*time.Minute)) {
// Conditionally process something if at least 15 minutes elapsed
}
Instead of a variable, when could be a field of some struct, for example.
Alternative approach:
deadline := time.Now().Add(15*time.Minute)
...
if time.Now().After(deadline) {
// Conditionally process something if at least 15 minutes elapsed
}
I prefer the later version personally.

How to choose a random time once per hour

Suppose I want to run a task once per hour, but at a variable time during the hour. It doesn't have to be truly random; I just don't want to do it at the top of the hour every hour, for example. And I want to do it once per hour only.
This eliminates several obvious approaches, such as sleeping a random amount of time between 30 and 90 minutes, then sleeping again. It would be possible (and pretty likely) for the task to run several times in a row with a sleep of little more than 30 minutes.
The approach I'm thinking about looks like this: every hour, hash the Unix timestamp of the hour, and mod the result by 3600. Add the result to the Unix timestamp of the hour, and that's the moment when the task should run. In pseudocode:
while now = clock.tick; do
// now = a unix timestamp
hour = now - now % 3600;
hash = md5sum(hour);
the_time = hour + hash % 3600;
if now == the_time; then
do_the_work();
end
end
I'm sure this will meet my requirements, but I thought it would be fun to throw this question out and see what ideas other people have!
For the next hour to do work in, just pick a random minute within that hour.
That is, pick a random time for the next interval to do work in; this might be the same interval (hour) as the current interval (hour) if work has carried over from the previous interval.
The "time to sleep" is simply the time until then. This could also be execute "immediately" on a carry-over situation if the random time was before now: this will ensure that a random time is picked each hour, unless work takes more than an hour.
Don't make it more complex than it has to be - there is no reason to hash or otherwise muck with random here. This is how "Enterprise" solutions like SharePoint Timers (with an Hourly Schedule) work.
Schedule your task (with cron or the like) to run at the top of every hour.
At the beginning of your task, sleep for a random amount of time, from 0 to (60 - (the estimated running time of your task + a fudge factor)) minutes.
If you don't want your task to run twice simultaneously, you can use a pid file. The task can check - after sleeping - for this file and wait for the currently running task to finish before starting again.
I've deployed my suggested solution and it is working very well. For example, once per minute I sample some information from a process I'm monitoring, but I do it at variable times during the minute. I created a method of a Timestamp type, called RandomlyWithin, as follows, in Go code:
func (t Timestamp) RandomlyWithin(dur Timestamp, entropy ...uint32) Timestamp {
intervalStart := t - t % dur
toHash := uint32(intervalStart)
if len(entropy) > 0 {
toHash += entropy[0]
}
md5hasher.Reset()
md5hasher.Write([]byte{
uint8(toHash >> 24 & 255),
uint8(toHash >> 16 & 255),
uint8(toHash >> 8 & 255),
uint8(toHash & 255)})
randomNum := binary.BigEndian.Uint32(md5hasher.Sum(nil)[0:4])
result := intervalStart + Timestamp(randomNum)%dur
return result
}

Resources