'Get Date and Time from Apple Server
I'm developing an app that can only be used during a certain time of the day. I can't get the local device time because the user can easily change the device time thereby allowing access to the application for any time of the day.
Is there a way to get the current date and time from an Apple server (or if not,) is there any other way?
Solution 1:[1]
- (NSDate *) CurrentDate
{
if ([self hasInternetConnectivity]) // this tests Internet connectivity based off Apple's Reachability sample code
{
NSSURL * scriptUrl = [NSURL URLWithString: @"http:// <yoursite>. Com / <the 2 line php script>. Php"];
NSData * data = [NSData dataWithContentsOfURL: scriptUrl];
if (data! = nil) {
NSString * tempString = [NSString stringWithUTF8String: [data bytes]];
NSDate * currDate = [NSDate dateWithTimeIntervalSince1970: [tempString doubleValue]];
NSLog (@ "String returned from the site is:% @ and date is:% @", tempString, [currDate description]);
return currDate;
}
else {
NSLog (@ "nsdata download failed");
return [NSDate date];
}
}
else {
NSLog (@ "InternetConnectivity failed");
return [NSDate date];
}
}
Solution 2:[2]
You can use that open source to get time from default NTP server, or choose your server: https://github.com/huynguyencong/NHNetworkTime
[[NHNetworkClock sharedNetworkClock] syncWithComplete:^{
NSLog(@"%s - Time synced %@", __PRETTY_FUNCTION__, [NSDate networkDate]);
}];
And use:
NSDate *networkDate = [NSDate networkDate];
Solution 3:[3]
I believe your requirement can be met by some web services which return json data.
One of them are jsontest.com: http://date.jsontest.com. Here is what it returns:
{
"time": "02:11:29 AM",
"milliseconds_since_epoch": 1513563089492,
"date": "12-18-2017"
}
The "milliseconds_since_epoch" represents milliseconds since 1970, so it's easy to convert to Date,by using Date.init(timeIntervalSince1970: milliseconds_since_epoch/1000). Then we can use Calendar class to get local time.
Solution 4:[4]
Karan's answer had some typos, and also failed to check for a response of "0" instead of just "nil". (I implemented it in my app and I got several false-positives from weak connections or unauthorized networks.)
I've adapted it below, and added the corresponding server code for those who don't know what Karan was referring to. This is implemented as a category method in an NSDate extension, so you can call it using [NSDate verifiedDate];
+(NSDate*)verifiedDate {
if([self hasInternetConnectivity]) {
NSURL *scriptUrl = [NSURL URLWithString:@"http://[yourwebsite].com/timestamp.php"];
NSData *data = [NSData dataWithContentsOfURL: scriptUrl];
if(data != nil) {
NSString *tempString = [NSString stringWithUTF8String:[data bytes]];
if([tempString doubleValue] > 946684800) { // Date is at least later than 2000 AD, or else something went wrong
NSDate *currDate = [NSDate dateWithTimeIntervalSince1970:[tempString doubleValue]];
NSLog(@"verifiedDate: String returned from the site is: %@ and date is: %@", tempString, [currDate description]);
return currDate;
} else {
NSLog(@"verifiedDate: Server returned false timestamp (%@)", tempString);
return [NSDate date];
}
} else {
NSLog(@"verifiedDate: NSData download failed");
return [NSDate date];
}
} else {
NSLog(@"verifiedDate: InternetConnectivity failed");
return [NSDate date];
}
}
And here's the server code, stored in your server's root folder as "timestamp.php"
<?php
echo(time());
?>
Solution 5:[5]
Here is my code, using 2 different web services in case one of them is down:
NSString *urlString = [NSString stringWithFormat:@"http://date.jsontest.com"];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
NSError *error;
NSNumber *milliSecondsSince1970 = nil;
if (data != nil) {
NSDictionary *json =[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
milliSecondsSince1970 = [json valueForKey:@"milliseconds_since_epoch"];
NSLog(@"milliSecondsSince1970 = %@", milliSecondsSince1970);
}
else {
urlString = [NSString stringWithFormat:@"https://currentmillis.com/time/seconds-since-unix-epoch.php"];
url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
data = [[NSData alloc] initWithContentsOfURL:url];
if (data!=nil) {
NSString *dbleStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
double dble = [dbleStr doubleValue]*1000;
milliSecondsSince1970 = [NSNumber numberWithDouble:dble];
NSLog(@"milliSecondsSince1970 currentMillis = %@", milliSecondsSince1970);
}
else {
double dateIntervalInSecondsSince1970 = [NSDate date].timeIntervalSince1970*1000;
milliSecondsSince1970 = [NSNumber numberWithDouble:dateIntervalInSecondsSince1970] ;
NSLog(@"milliSecondsSince1970 NSDate = %@", milliSecondsSince1970);
}
}
Solution 6:[6]
If you don’t want use other web services you can validate the receipt every time the user opens the app , apple will return to you a json file which includes current gmt , I use the receipt to check for subscription status and I fetch the time from this file
Solution 7:[7]
Here is a minimalistic function that gets the timestamp from apple's ntp server. It gets the time from time.apple.com without any additional libraries.
+ (NSDate *)lsDateFromOnlineServer
{
struct hostent *server = gethostbyname("time.apple.com");
if (!server)
return nil;
int udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udpSocket < 0)
return nil;
struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;
setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
struct sockaddr_in socketAddress = {0};
socketAddress.sin_family = AF_INET;
socketAddress.sin_port = htons(123);
memcpy(&socketAddress.sin_addr, server->h_addr_list[0], server->h_length);
if (connect(udpSocket, (struct sockaddr *)&socketAddress, sizeof(socketAddress)) < 0) {
close(udpSocket);
return nil;
}
unsigned char ntpPacket[48] = {0};
ntpPacket[0] = 0x1B;
if (write(udpSocket, &ntpPacket, sizeof(ntpPacket)) < 0) {
close(udpSocket);
return nil;
}
if (read(udpSocket, &ntpPacket, sizeof(ntpPacket)) < 0) {
close(udpSocket);
return nil;
}
close(udpSocket);
NSTimeInterval ntpTimestampDelta = 2208988800u;
NSTimeInterval ntpTimestamp = ntohl(*((uint32_t *)(ntpPacket + 40)));
NSTimeInterval ntpOverflowDelta = ntpTimestamp < ntpTimestampDelta ? 0xFFFFFFFF : 0;
if (ntpTimestamp == 0)
return nil;
NSTimeInterval timestamp = ntpTimestamp - ntpTimestampDelta + ntpOverflowDelta;
return [NSDate dateWithTimeIntervalSince1970:timestamp];
}
Note that it uses synchronous socket so you might want to use it from a background thread. Also it is included in my library with various extensions: LSCategories
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Duck |
| Solution 2 | huync |
| Solution 3 | Eric Yuan |
| Solution 4 | Nerrolken |
| Solution 5 | |
| Solution 6 | ???????? ????? |
| Solution 7 |
