I\'m looking for a reliable way to get the time. It can\'t be tampered with and it needs to work offline. So no internet time , no user time setup in settings and no BSD u
Even if you can get hold of the time from GPS you should be aware that GPS time is not quite the same as UTC. The GPS receiver in the iPhone might take care of that for you though.
This works to get the GPS time:
#import <CoreLocation/CoreLocation.h>
CLLocation* gps = [[CLLocation alloc]
initWithLatitude:(CLLocationDegrees) 0.0
longitude:(CLLocationDegrees) 0.0];
NSDate* now = gps.timestamp;
It doesn't seem to be tamper-proof though.
I tried this code on an iPhone 4 in airplane mode (iOS 6.1), and even then it gives a time all right. But unfortunately this time seems to change with the system clock. Ugh.
Funny thing that I found (still in airplane mode) is that if you tamper with the system clock (after turning to off
Time & Date's Set Automatically
), and then turn Set Automatically
back to on
, the machine restores the real (original) time without a hitch. this works even after cycling the phone's power. So it seems that there is something like a tamper-proof time the device maintains internally. But how to access this?
P.S. A discussion of this from 2010. The author of the penultimate comment tried this in a fallout shelter: so it's clear the phone is not getting the pristine time from any external source.
Found a few more posts (here, here and here) about another kind of time measure: system kernel boot time. It's accessed through a call something like this: sysctlbyname("kern.boottime", &boottime, &size, NULL, 0);
. Unfortunately it too changes with the user-adjusted data and time, even without reboot. Another function gettimeofday()
is similarly dependent on user-defined time.
NSDate and it's CF counterpart are all based on the user controllable time, and thereby aren't tamper proof.
As far as I know, there is no open API for either GPS time or carrier time directly. However, you can check the mach_absolute_time to get untampered time since last boot up, and perhaps use it to at least be aware of how much time has passed since the app has been awoken (without having the potential for that time to be tampered with while the app is running).
mach_absolute_time depends on the processor of the device. It returns ticks since the device was last rebooted (otherwise known as uptime). In order to get it in a human readable form, you have to modify it by the result from mach_timebase_info (a ratio), which will return billionth of seconds (or nanoseconds). To make this more usable I use a function like the one below:
#include <mach/mach_time.h>
int getUptimeInMilliseconds()
{
static const int64_t kOneMillion = 1000 * 1000;
static mach_timebase_info_data_t s_timebase_info;
if (s_timebase_info.denom == 0) {
(void) mach_timebase_info(&s_timebase_info);
}
// mach_absolute_time() returns billionth of seconds,
// so divide by one million to get milliseconds
return (int)((mach_absolute_time() * s_timebase_info.numer) / (kOneMillion * s_timebase_info.denom));
}
The gold standard of timekeeping are the various government time observatories in the U.S. and worldwide. They provide Atomic time. That is used world wide. Apple should be using that. If the want to sync w/ the cell towers, there should be an Alternate internal time. If the tower or GPS system malfunctions all are left with incorrect time.
This gets you the current date and time:
NSDate *now = [NSDate date];
This will be as reliable as you can get. The internal clock on the iPhone will be updated when it can get access to an NTP server. If the phone uses GPS as a time sync source it'll also be used to update the same system-wide clock which is accessible via the above method.
The CoreFoundation equivalent is something like:
CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
Which returns the CoreFoundation equivalent of the normal UNIX seconds-since-epoch timestamp.