System.currentTimeInMillis() not giving accurate value in Android - java

I have an Android app which finds the time interval between two events.
When Event 1 fires a broadcast, I store the current time using System.currentTimeInMillis()
I do the same when the second event occurs and then calculate the difference.
However, the result is always a couple of seconds off, in the sense that I know the interval was around 4 seconds but the value I get is around 6.
Is this because of the delay between sending the broadcast, receiving it and then storing the value?
If so, what's a better way to do it to get a more accurate value?

Per Developer.android.com (http://developer.android.com/reference/android/os/SystemClock.html):
System.currentTimeMillis() is the standard "wall" clock (time and
date) expressing milliseconds since the epoch. The wall clock can be
set by the user or the phone network (see setCurrentTimeMillis(long)),
so the time may jump backwards or forwards unpredictably. This clock
should only be used when correspondence with real-world dates and
times is important, such as in a calendar or alarm clock application.
Interval or elapsed time measurements should use a different clock.
If you are using System.currentTimeMillis(), consider listening to the
ACTION_TIME_TICK, ACTION_TIME_CHANGED and ACTION_TIMEZONE_CHANGED
Intent broadcasts to find out when the time changes.

Related

Android: How can I start a timer that begins at the next exact multiple of 2 seconds?

I am new to android and have been thrown in at the deep end with a somewhat complicated project.
I effectively have a number of devices running the same app and they are either staff or Exclusion zones.
I need to use bluetooth beacons to have the devices transmit their GPS coordinates, and the exclusion zones also transmit their boundary size (Bluetooth beacon distance detection was not reliably accurate enough.)
What I want to do is have a service running (I think) that has the staff devices listen for one second, whilst the exclusion zones broadcast, then all devices flip between listening and broadcasting for the next second, then repeat.
Any detected boundary violations calculated by taking the distance between the devices own GPS coordinate and any that have been broadcast by other devices of the opposing type are then to be logged.
How can I get a timer to start, and repeatedly call the function every 2 seconds, at the next exact multiple of 2 seconds?
NOT 2 seconds from the point at which the function is called. For instance if the time is 12h:35m:01s:223ms I want the repeating function to be called at 12:35:02
Compute the time remaining to the next two-second mark and then use that to schedule a delayed, one-time task that will start a two-second repeating timer.

How can I know how much time has passed between two operations in my app? [duplicate]

This question already has answers here:
How do I measure time elapsed in Java? [duplicate]
(15 answers)
Closed 5 years ago.
I'm working on an Android app and I have this problem.
For example, if I delete a file (operation A) and I receive a new file (operation B), I want to know how much time has passed between the two operations. I want it to work also if, in between, the user changes the date of the system, turns off the internet or restarts the device.
I know that exists SystemClock.elapsedRealtime() but its value restarts from zero if the user restarts the device.
I cannot use System.currentTimeMillis() because it changes if user changes the date.
I cannot get a date from the internet.
Thanks
Use System.currentTimeMillis(). It gets the time elapsed since the epoch (January 1st 1970).
You need a global var:
long start;
on the first action:
start = System.currentTimeMillis();
Since it's the time from the epoch, restarting the device isn't going to change it (i.e. System.nanoTime would be reset). However, as with most other methods, it isn't safe from changing the time of the device. If someone changes the time on the device back to the start of the epoch, you will experience some problems.
Note that there is no way to get the exact time since the event happened if the time is changed. I.e. if the user does operation A, waits a few hours, sets the clock back to a few hours ago, there's basically no offline ways you can check that. If you use a server, you can get the time from that, but there's not any way to get the accurate, unmodified time difference offline that's tamper proof (where tampering is changing the time).
TL;DR: System.currentTimeMillis is an offline option, but it isn't safe from time changing. If you need it to show the right time difference independently of the user changing the time of the device, use a server.
EDIT:
If you can't use System.currentTimeMillis or get a time from the internet, you can't measure the time at all. AFAIK, every Java/Android API relies on System.currentTimeMillis (or get the current time some other way). Example: the Date class can be converted to a Long representing the current time in milliseconds. For long-term timing, you either have to use System.currentTimeMillis or a server. System.nanoTime restarts when the JVM restarts. So does elapsedRealTime.
You just need to grab the time from somewhere before and after the activities you want to time and take one from the other. This uses the system clock but you could equally get the real time from some other source
long startTime = System.currentTimeMillis();
// Your code
System.out.println("Operation took " + (System.currentTimeMillis() - startTime) + " milliseconds");

How can a task be scheduled in Java to occur at midnight, even if a leap second has just occurred?

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.

Android running thread every 1 Second to Increment Unix Timestamp

I need to running thread every one second. But when application killed, the thread must be still alive.
My thread task is used for increment Unix Timestamp (that synchronized when the first time application running from our server time) by one every second. I need to create this task because in some device, date time can changed unpredictable (maybe low on battery, hard reset, dropped or something else).
My Activity must be get that Unix Timestamp value when it needed.
From SO, Alarm Manager is not a good choice,
I would recommend you not to use an AlarmManager for 30 seconds, as some have suggested. Because 30 seconds is too short. it will drain the battery. For AlarmManager use a minimum 1 minute with RTC.
Other people suggest using Timer Task or ScheduledExecutorService, what the best thread to fit my need?
Thanks.
You would never achieve that. Any process could be killed by System. And task running every seconds is horrible (like AlarmManager said).
One idea is: save your server time and device time such as SystemClock.elapsedRealtime() . (do not use System.currentTimeMillis() for this purpose. ... this is display time for user and can be changed by user or something).
When you need time later, get elapsedRealtime() again and compare with stored elapsedRealtime(), and add this diff to stored server time. You will get desired time.
Or simply ask current time to your server , depends on needs :).
If you want to care hard reset I think that you should have database on your server to manage the first time when user launches app.

What is the correct method for getting the uptime of the device?

I need to get the uptime of the device and for this I've been using the method called SystemClock.uptimeMillis(). Some users have complained the the uptime statistics aren't correct and the device has been up for a lot longer.
I read the docs but I'm confused as to what method in the SystemClock class will yield the real uptime — should I use elapsedRealtime()?
That depends on how you define "uptime" with respect to your app.
uptimeMillis() does not count time spent in sleep mode. So, if the user turns on their device, runs it for five minutes before it goes to sleep, then does not return to the device for a week, uptimeMillis() will return a value around five minutes.
elapsedRealtime() does count time spent in sleep mode. So, if the user turns on their device, runs it for five minutes before it goes to sleep, then does not return to the device for a week, elapsedRealtime() will return a value around one week.

Categories