I've noticed that System.currentTimeMillis() time is device dependent. If I change the time on the device's clock, this method will return a different answer.
For example: If the real time now is 10:00, and I change the clock on my device to 9:30, then System.currentTimeMillis() will return the 9:30 time (in milliseconds..).
I've also tried this answer and some other answers, but didn't find anything useful.
I should state that my app works mostly offline.
Is there a way to get the real current time (device independent) without external API?
If it were not for the 'offline' part, I'd have suggested to use a time server, but given that your app is offline most of the time that might not be a good solution.
If you don't need the actual time but just a time that cannot be messed with, you can use SystemClock.elapsedRealtime() which gives you the time since the device last booted.
You could also combine time server and SystemClock.elapsedRealtime(): Fetch the time from timer server once (e.g. after bootup) and from then on add elapsedRealtime() to that initial value (minus the elapsedRealtime value of when you get the timerserver value).
If you use the GPS location provider, getTime() will return the UTC time derived from the GPS signal, rather than the device time. The GPS location provider can work offline - but it will be much slower to obtain a fix compared to being online when it can access the A-GPS info.
Related
I have a blockchain api with correct time, but when some android devices where the users themselves set their time (auto-clock is not enabled), I am having problem with working with this api because of the difference between these two times. Could you help me to identity this difference? System.currrentMillisSecond() method is returning the time set by the user.
You don't have other way than syncing with 3rd-party, getting current time from e.g. own server-side or some web service and counting time basing on it. You may calculate diff between "real-time" and "on-device-time", but still user can minimalize your app and during it's work (Service in background?) can change again locally set time
Note that there is also SystemClock.elapsedRealtime() which returns elapsed time since last boot. This can't be changed by user during runtime (only by restarting device), so may be helpful for counting difference
val synced = getTimestampFromWeb() // instead of unreliable System.currrentMillisSecond()
val elapsedWhenSynced = SystemClock.elapsedRealtime()
// store these in some
...
// use below line anytime later
val currentTime = synced + (SystemClock.elapsedRealtime() - elapsedWhenSynced)
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");
I have a bit of a unique issue. I'm collaborating with several other Computer Science Majors at my university on an Android Metronome app that allows two users with the app to sync metronomes. Right now, I can send the desired beats per minute of the metronome from one phone to the other and both phones will start to play their respective metronomes. Due to the latency of Bluetooth, the metronomes are only in sync about 20% of the time.
So, here's where the problem is. We're trying to make it so both of the metronomes will start at the exact same time. One way I've thought of doing this is once the first user presses the send button on their phone, a time stamp will be created. This time stamp will be exactly two seconds after the user presses the send button. The time stamp will then be sent to the second phone and the phone will utilize this time stamp to start it's metronome at the same exact time as the first phone. I've tried accomplishing this by putting UTC time in a while loop and then constantly checking the time, to no avail. Does anyone have any ideas as to how we can go about implementing this? I couldn't find any similar problem on StackOverflow, or any other website for that matter.
It's a bit late probably for your project, but if interested. This is a bit long, it's more like a case study.
If your project was about syncing two device clocks remotely, then this won't help you, but if it was about syncing the metronomes, then this may be a start.
First, getting millisecond accurate timings and callbacks in android using java is next to impossible, since android is not a real time system ( All sleep methods and timer might not execute on the exact millisecond you're expecting ). You may want to go with NDK for triggering your beat events, because native threads in android can achieve that, but if you're happy with your single metronome implementation, then that's good enough to read the rest of this .
Full disclosure :
I am the author of JAM the app referenced in the answer I just published a few days ago.
I ran into the same problem when developing the app.
And whether this answer will help you or not, depending on your situation.
and if you're going down the "clock sync" route ( Which I do plan on exploring to improve my app down the road with more features ) but the solution that I found did not involves time sync.
I will mention my approach and then state what I found as advantages/disadvantages for each of the methods .
Instead of syncing clocks ( A very difficult problem, especially for what the app was supposed to do , and that is trigger ticks on multiple devices at the "same" time ) I opted for a subscribe/publish model, where multiple devices can "subscribe" to a host device via bluetooth, and the host device controls and "publishes" the metronome beats.
most times sending a few hundred bytes ( Enough information about each beat ) via bluetooth takes less than 2ms , it could spike up to 10 and sometimes even 30, but that rarely seems to happen .
That approach took care of the syncing problem, now I can send beat events from one device to another in 2ms , and if some sort of delay happened, it will self correct once the interference is gone, because the other event comes in time.
However that approach does require constant connection, you can't start and separate the devices later on, but it's much easier to implement.
Now the interesting part, the problem I never thought of when starting this, and that was the Android 10 millisecond audio path latency problem. I'm not affiliated with superpowered, but I did use their engine in my app to deal with that problem .
To summarize :
Metronome sync over bluetooth in Android has two issues :
1 - triggering beat events simultaneously ( or within acceptable latency )
2 - The beat event should trigger sound events with minimal delay after the beat event is received
#1 is related to the original question, #2 I thought was an important addition to the original problem this question is asking.
I would use (S)NTP to check the clock drift to a public time server. After that I would just send the interval and a start time and let the devices calculate the interval individually. So you just need to sync changes and relay on the clocks of the individual devices. Together with the now known clock drift you can fix this error.
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.
I've got a clock in my widget that I'm making and I want it to update every minute in sync with the system clock. ACTION_TIME_TICK seems like the perfect solution however much of my research says it's impossible in an AppWidget while others say there are workarounds but their very vague.
I'd prefer not to do an AlarmManager as I'd have to update very frequently to make sure that it changes minutes when the system clock changes minutes and that would drain the battery more.
Is there a workaround for ACTION_TIME_TICK or what's the best way to update every minute in sync with the system clock with minimal battery drain?
Is there a workaround for ACTION_TIME_TICK
ACTION_TIME_TICK can only be registered via registerReceiver() from something that is already running. In your case, that "something" would need to be a constantly-running Service, and that's generally an anti-pattern. Users and the OS can get rid of that service when desired.
I would find a way to lightly relax the "in sync with the system clock" requirement, then use AlarmManager. After all, Android is not a RTOS, so nothing will be "in sync with the system clock" in any guaranteed sense.
Using AlarmManager, you would specify the first alarm to be the "top" of the next minute, with a period of 60 seconds and setRepeating(). Or, you would set(), scheduled for the "top" of the next minute, then schedule the next one via set() as part of your own processing, if you think you can manually correct for drift better that way.
if you just need to display it when your app runs then just update it using asyncTask
but if you need it's value even in the background then using service would be the best idea