Skip to content

Instantly share code, notes, and snippets.

@henrik
Created March 14, 2010 09:59
Show Gist options
  • Save henrik/331897 to your computer and use it in GitHub Desktop.
Save henrik/331897 to your computer and use it in GitHub Desktop.
AKServerTime (Obj-C/Cocoa). Keeps track of server time, adjusting for time zone/time sync diffs and accounting for latency.
// AKServerTime
// By Henrik Nyh <http://henrik.nyh.se> 2010-03-14 under the MIT license.
//
// Keeps track of the current server time, adjusting for differences in
// time zone/time sync between client and server, and accounting for latency.
//
// The latency adjustment is pessimistic: if we get 12:00:25 back with a latency
// of 5 seconds, we know the current server time is between 12:00:25 (5 sec req,
// 0 sec res) and 12:00:30 (0 sec req, 5 sec res). We assume it is 12:00:30 so
// that trusting the server time may make you early, but never late.
//
// This is a singleton class: get it with [AKServerTime sharedServerTime].
#import <Foundation/Foundation.h>
@interface AKServerTime : NSObject {
NSTimeInterval _offset;
NSTimeInterval _latency;
}
+ (id)sharedServerTime;
- (void)syncWithClientDate:(NSDate *)clientDate serverDate:(NSDate *)serverDate andLatency:(NSTimeInterval)latency;
- (NSDate *)date;
@end
#import "AKServerTime.h"
static AKServerTime *sharedServerTime = nil;
@implementation AKServerTime
#pragma mark -
#pragma mark Date
- (void)syncWithClientDate:(NSDate *)clientDate serverDate:(NSDate *)serverDate andLatency:(NSTimeInterval)latency {
NSDate *pessimisticServerDate = [serverDate addTimeInterval:latency];
NSTimeInterval offset = [pessimisticServerDate timeIntervalSinceDate:clientDate];
// If we've synced with smaller latency before, and the offset is not
// large enough (under 5 seconds) to suspect something like a DST change,
// keep the old value as more reliable.
if (_latency && _latency < latency && (fabs(offset-latency) < 5.0)) {
NSLog(@"SERVER TIME: higher latency at %f, remaining offset small at %f - keep old value", latency, fabs(offset-latency));
} else {
_latency = latency;
_offset = offset;
}
NSLog(@"SERVER TIME: local now %@ server now %@ (latency %f, offset %f)",
[NSDate date], [self date], _latency, _offset);
}
- (NSDate *)date {
return [[NSDate date] addTimeInterval:_offset];
}
#pragma mark -
#pragma mark Singleton
// http://iphone.galloway.me.uk/iphone-sdktutorials/singleton-classes/
+ (id)sharedServerTime {
@synchronized(self) {
if(sharedServerTime == nil)
[[self alloc] init];
}
return sharedServerTime;
}
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if(sharedServerTime == nil) {
sharedServerTime = [super allocWithZone:zone];
return sharedServerTime;
}
}
return nil;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
// never release
}
- (id)autorelease {
return self;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment