When launching my application, the AlarmManager is being triggered immediately because the time occurs in the past.
My idea was to check the actual time with the schedule one :
if(calendar.before(Calendar.getInstance())); //where calendar is my scheduled calendar
If the above condition is true then:
calendar.add(Calendar.DAY_OF_YEAR, 1);
I think this will work.
However the confusion is at day 365:
If the scheduled time was before the Actual time, it will add one day according to this line: calendar.add(Calendar.DAY_OF_YEAR, 1);
and it will become 1
Doesn't that make it always in the past? Because there is no 366 ? Thus the AlarmManager will be always triggering it immediately considering it in the past?
EDIT:
Do you suggest I put instead :
calendar.add(Calendar.HOUR_OF_DAY, 24);
CommonsWare's comment is correct; add() will add that amount of time and adjust all the fields appropriately.
The behavior you were concerned about would occur if you used roll() instead of add(). But you should be safe with add().
Here's the doc if you want to dig in further.
Related
First, definition of "occur at midnight" is that when task is run, new DateTime() or similar will show 00:00:00 or later for the time portion when converted to a human readable format. Important point is that it must not show 23:59:59 of the previous day.
A common way to achieve this would be to calculate how many milliseconds are between now and the desired point in time, and then use a ScheduledExecutorService to execute the task at the correct time. However, when a leap second is inserted this will result in the task running a second early (or a few milliseconds early depending on how the leap second is 'smeared' and when you scheduled the task):
Runnable task = ...
long numberOfMillisUntilMidnight = ...
ScheduledExecutorService executor = ...
// task runs too early when leap seconds are inserted
executor.schedule(task, numberOfMillisUntilMidnight, TimeUnit.MILLISECONDS);
The reason is that executor.schedule() is based on System.nanoTime() which obviously ignores the leap seconds. I guess what I need is some scheduler based on "run at this time" rather than "run after this amount of time".
For those who are interested, the reason the task must run at midnight related to the fact that all events in my system must be categorized according to which day they occurred on, and in so far as is possible, this needs to be in sync with another system. Of course it would be better if the other system stamped each event with what day it is, but we are not there.
I guess what I need is some scheduler based on "run at this time" rather than "run after this amount of time"
That would be the all-singing, all-dancing solution. But:
First, definition of "occur at midnight" is that when task is run, new DateTime() or similar will show 00:00:00 or later for the time portion...Important point is that it must not show 23:59:59 of the previous day.
(my emphasis)
The simple way is always add a second, or even two. So it'd be 00:00:01 (00:00:00 or later) in the common case, and 00:00:00 (not 23:59:59) in the leap second case.
Based on the resulting discussions it seems clear that, in general, it is unwise to rely on your scheduler to run a task at the "correct" time if "wall time" is important to you. This is also true when running daily tasks at the same "wall time" across daylight savings shifts, although unlike the leap second case, the daylight savings case is well supported by existing tools (by Quartz for example).
Instead I think the best approach for such "wall time sensitive" processes is that when the task is run, check the system clock at that point. If your schedule was inaccurate for whatever reason (leap seconds are not the only time your system clock is adjusted relative to the elapsed time measured by System.nanoTime()) and the time has not yet been reached, then do nothing and reschedule the task for the correct time. This approach would also work for schedules that respond to daylight savings changes but as mentioned above this is already supported by common tools.
This approach was inspired by the comment by Jonathon Reinhart above. Rescheduling rather than sleeping though seems better.
Assuming that your concrete ScheduledExecutorService-implementation relies on System.nanoTime() (as you said) and taking into account your requirement/configuration that the initial delay parameter of the method schedule(...) counts the elapsed milliseconds until next midnight including a possible leap second,
I suggest you to use a leap-second-aware solution. An example using my library Time4J shows how to calculate the delay parameter:
Moment now = SystemClock.currentMoment(); // should not be called during a leap second
Moment nextMidnight =
now.with(
PlainTime.COMPONENT.setToNext(PlainTime.midnightAtStartOfDay()).in(
Timezone.ofSystem().with(
GapResolver.NEXT_VALID_TIME.and(OverlapResolver.EARLIER_OFFSET)
)
)
);
long delayInMilliseconds = SI.NANOSECONDS.between(now, nextMidnight) / 1_000_000;
This code will also choose the earliest valid local time after midnight in case of daylight-saving-change (standard-Java would rather push the time forward by the size of the gap possibly resulting in a local time later than first valid time). For most zones, this is only relevant if choosing an arbitrary start time after midnight (dependent on business requirements).
What so ever, you should also care about connecting your systems to the same NTP-clock. Either you rely on OS-NTP-configuration, or you can use a Java-based clock connecting to NTP (Time4J offers here a solution, too).
If your chosen clock is just doing arbitrary jumps (i.e. if someone has manually adjusted it or in case of bad NTP-configuration) then rescheduling the task after having checked the local walltime again is probably safer. However, I still think that calculating the delay parameter by Time4J-code above is a good idea because the chance to match midnight is higher than just to run the task and rechecking the local time.
You could also combine both approaches: exact calculation of delay AND check/reschedule.
I'm looking for some ways to make an app that every body can use all the futures for just 3 days, after the limited time ends some of futures disables but again via In-App Purchase they will ready to use.
The question is, How can I set a timer to count down for 3 days from the time that application for first time opened? I should do it in some way that when the phone power offs there mustn't be problem.again after powering on and without opening the app it should count down to 00:00:00.
Is there any samples for this? Or how can I do it?
As #4castle said, set a time stamp when they first open the app. Then, if you want to display a countdown with an exact time until expiration, have a text box somewhere that displays time remaining. Calendar
import java.util.Calendar
if( this.firstTimeRunning() ){
Calendar start = Calendar.getInstance();
//save start.getTimeInMillis()
}
Calendar end = Calendar.getInstance();
end.setTimeInMillis( /* saved millisec value */);
end.set(Calendar.DAY, end.get(Calendar.DAY) + 3);
long difference = end.getTimeInMillis() - start.getTimeInMillis();
text_box.setText(/* format difference*/); //update every second
Something like that.
iam trying to make a task to be executed EVERYDAY at 8am (example).
Currently what i have done is make a task, execute it automatically but only for a period of time (in this case 50 seconds) i want it to be executed every day at 8am.
my current code :
Timer time = new Timer();
certif_envia_notificacion st = new certif_envia_notificacion();
time.schedule(st, 0, 50000);
where certif_envia_notificacion is the task that i want to execute, and it does execute every 50 seconds.
Currently the only way i can figure this out is in the task certif_envia_notificacion ask for the time and execute if its 8am, but that seems like a huge waste of server resources, since ill have to execute the task at least 24 times a day.
Thanks in advance.
This is kind of a hack solution that I thought up, but feel free to give comments/feedback based on your requirements.
Basically, from my understanding you have a Java program that runs automatically when the computer starts up (if it restarts), and will then check every hour to see if it is the correct time to run the application. Why not keep it running this way, but instead of running every hour, calculate the time required to get to the next time required (e.g. 8PM the next day).
So for example, lets say you restart it at 3:15PM. When the java program runs, get it to get the current time (System.currentTimeMil...) and then calculate the time required to get to 8PM. You can do some simple math on this (e.g. 20 - current time = time required to wait) and if its negative, simply add 24 to it (e.g. if its 20 - 23, the answer is 24 - 3 = 21, thus wait 21 hours for the next 8PM).
This process can be used every time you run the code, or on startup. I'd recommend just creating a simple function to calculate the required sleep time.
What i finally did was execute the procedure every one hour and make a question of the hour and select the hour that i wanted, i know its not the best way but i needed to finish it fast....
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
if(hour == DesiredHour){
//do stuff
}else if(hour == DesiredHour2){
//do stuff 2
}
Thanks for the comments.
I have a system that needs to trigger at certain intervals
If it is given the following:
minutes:25, seconds:10
It should then trigger every hour, 25 minutes and 10 seconds past the hour. For example, 7:25:10, 8:25:10, 9:25:10, and so on.
This would be simple enough, and I already have that code working. The problem is that it only works if the system checks at least once a second, otherwise it will miss a trigger.
So how can I check if the trigger units would have matched the current time units since the last check? The time between checks will vary greatly.
The trigger units are stored like this:
// units that must match the current time <Calendar Unit, Trigger>
private Map<Integer, Integer> triggerUnits;
First move to enum instead of map. The enum can contain hour, second, day, whatever. The good new is that such enum already exists in JDK and is called TimeUnit. Each member of this enum knows to translate the time to other units.
So, parse string hour:5. Translate the 5 hours to 3600*5*1000 milliseconds. This value will be used in your system. You have several possibilities but I'd suggest you to start from java.util.Timer. Each task can be scheduled in the timer. It uses one single thread for execution of all tasks.
If you want you can use use Executors framework:
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.schedule(...);
The schedule method here directly works with time units. You even do not have to translate from one unit to another.
Each time you trigger the system, store the next time that the code needs to be triggered. During the checks, simply check if the current time has passed this "next time", and if so, then trigger the system.
Not precisely an answer for what you've asked, but I'd suggest using cron4j: the Predictor sounds like it is almost exactly what you need. Translate your spec into cron format, and then pass it to the Predictor and it will actually tell you the absolute time of the next execution. You can just schedule your check to happen at that moment in time or use a ScheduledExecutor to fire the job.
Might be a bit more complicated in some ways (and its an additional dependency), but completely eliminates the timing risk.
How can i synchronize the time (second , hour).
i have this
int minuto = cal.get(Calendar.MINUTE);
int day_Completed = 1440;
but i have no idea how can i do it.
I tried doing this
changing the pc time when a loop is running to see if the var minuto change.
but doesn't work.
An instance of calendar statically reflects one moment in time. It won't get updated automatically, it is not behaving like a clock.
If you want to "synchronize" with the actual time, then you have to
use some sort of timer, maybe based on Thread.sleep for a start
on each "timer event" get the current time (System.currentTimMillis()) and
update the instance of calendar with that value.