Merge pull request #2591 from thomasvl/objc_timestamps_take2

Timestamp helper fix, Duration helper cleanup.
pull/2317/head
Thomas Van Lenten 8 years ago committed by GitHub
commit eed9951991
  1. 17
      objectivec/GPBWellKnownTypes.h
  2. 52
      objectivec/GPBWellKnownTypes.m
  3. 162
      objectivec/Tests/GPBWellKnownTypesTest.m

@ -112,16 +112,27 @@ typedef NS_ENUM(NSInteger, GPBWellKnownTypesErrorCode) {
* @note: Not all second/nanos combinations can be represented in a * @note: Not all second/nanos combinations can be represented in a
* NSTimeInterval, so getting this could be a lossy transform. * NSTimeInterval, so getting this could be a lossy transform.
**/ **/
@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970; @property(nonatomic, readwrite) NSTimeInterval timeInterval;
/** /**
* Initializes a GPBDuration with the given NSTimeInterval. * Initializes a GPBDuration with the given NSTimeInterval.
* *
* @param timeIntervalSince1970 Time interval to configure the GPBDuration with. * @param timeInterval Time interval to configure the GPBDuration with.
* *
* @return A newly initialized GPBDuration. * @return A newly initialized GPBDuration.
**/ **/
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970; - (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval;
// These next two methods are deprecated because GBPDuration has no need of a
// "base" time. The older methods were about symmetry with GBPTimestamp, but
// the unix epoch usage is too confusing.
/** Deprecated, use timeInterval instead. */
@property(nonatomic, readwrite) NSTimeInterval timeIntervalSince1970
__attribute__((deprecated("Use timeInterval")));
/** Deprecated, use initWithTimeInterval: instead. */
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970
__attribute__((deprecated("Use initWithTimeInterval:")));
@end @end

@ -41,15 +41,25 @@ NSString *const GPBWellKnownTypesErrorDomain =
static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/"; static NSString *kTypePrefixGoogleApisCom = @"type.googleapis.com/";
static NSTimeInterval TimeIntervalSince1970FromSecondsAndNanos(int64_t seconds, static NSTimeInterval TimeIntervalFromSecondsAndNanos(int64_t seconds,
int32_t nanos) { int32_t nanos) {
return seconds + (NSTimeInterval)nanos / 1e9; return seconds + (NSTimeInterval)nanos / 1e9;
} }
static int32_t SecondsAndNanosFromTimeIntervalSince1970(NSTimeInterval time, static int32_t SecondsAndNanosFromTimeInterval(NSTimeInterval time,
int64_t *outSeconds) { int64_t *outSeconds,
BOOL nanosMustBePositive) {
NSTimeInterval seconds; NSTimeInterval seconds;
NSTimeInterval nanos = modf(time, &seconds); NSTimeInterval nanos = modf(time, &seconds);
if (nanosMustBePositive && (nanos < 0)) {
// Per Timestamp.proto, nanos is non-negative and "Negative second values with
// fractions must still have non-negative nanos values that count forward in
// time. Must be from 0 to 999,999,999 inclusive."
--seconds;
nanos = 1.0 + nanos;
}
nanos *= 1e9; nanos *= 1e9;
*outSeconds = (int64_t)seconds; *outSeconds = (int64_t)seconds;
return (int32_t)nanos; return (int32_t)nanos;
@ -88,8 +98,8 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
if ((self = [super init])) { if ((self = [super init])) {
int64_t seconds; int64_t seconds;
int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970( int32_t nanos = SecondsAndNanosFromTimeInterval(
timeIntervalSince1970, &seconds); timeIntervalSince1970, &seconds, YES);
self.seconds = seconds; self.seconds = seconds;
self.nanos = nanos; self.nanos = nanos;
} }
@ -105,13 +115,13 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
} }
- (NSTimeInterval)timeIntervalSince1970 { - (NSTimeInterval)timeIntervalSince1970 {
return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos); return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
} }
- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { - (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
int64_t seconds; int64_t seconds;
int32_t nanos = int32_t nanos =
SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds); SecondsAndNanosFromTimeInterval(timeIntervalSince1970, &seconds, YES);
self.seconds = seconds; self.seconds = seconds;
self.nanos = nanos; self.nanos = nanos;
} }
@ -122,29 +132,41 @@ static NSString *ParseTypeFromURL(NSString *typeURLString) {
@implementation GPBDuration (GBPWellKnownTypes) @implementation GPBDuration (GBPWellKnownTypes)
- (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { - (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval {
if ((self = [super init])) { if ((self = [super init])) {
int64_t seconds; int64_t seconds;
int32_t nanos = SecondsAndNanosFromTimeIntervalSince1970( int32_t nanos = SecondsAndNanosFromTimeInterval(
timeIntervalSince1970, &seconds); timeInterval, &seconds, NO);
self.seconds = seconds; self.seconds = seconds;
self.nanos = nanos; self.nanos = nanos;
} }
return self; return self;
} }
- (NSTimeInterval)timeIntervalSince1970 { - (instancetype)initWithTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
return TimeIntervalSince1970FromSecondsAndNanos(self.seconds, self.nanos); return [self initWithTimeInterval:timeIntervalSince1970];
} }
- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 { - (NSTimeInterval)timeInterval {
return TimeIntervalFromSecondsAndNanos(self.seconds, self.nanos);
}
- (void)setTimeInterval:(NSTimeInterval)timeInterval {
int64_t seconds; int64_t seconds;
int32_t nanos = int32_t nanos =
SecondsAndNanosFromTimeIntervalSince1970(timeIntervalSince1970, &seconds); SecondsAndNanosFromTimeInterval(timeInterval, &seconds, NO);
self.seconds = seconds; self.seconds = seconds;
self.nanos = nanos; self.nanos = nanos;
} }
- (NSTimeInterval)timeIntervalSince1970 {
return self.timeInterval;
}
- (void)setTimeIntervalSince1970:(NSTimeInterval)timeIntervalSince1970 {
self.timeInterval = timeIntervalSince1970;
}
@end @end
#pragma mark - GPBAny #pragma mark - GPBAny

@ -32,11 +32,9 @@
#import <XCTest/XCTest.h> #import <XCTest/XCTest.h>
#import "GPBTestUtilities.h"
#import "google/protobuf/AnyTest.pbobjc.h" #import "google/protobuf/AnyTest.pbobjc.h"
// A basically random interval into the future for testing with.
static const NSTimeInterval kFutureOffsetInterval = 15000;
// Nanosecond time accuracy // Nanosecond time accuracy
static const NSTimeInterval kTimeAccuracy = 1e-9; static const NSTimeInterval kTimeAccuracy = 1e-9;
@ -46,59 +44,117 @@ static const NSTimeInterval kTimeAccuracy = 1e-9;
@implementation WellKnownTypesTest @implementation WellKnownTypesTest
- (void)testTimeStamp { - (void)testTimeStamp {
// Test Creation. // Test negative and positive values.
NSDate *date = [NSDate date]; NSTimeInterval values[] = {
GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date]; -428027599.483999967, -1234567.0, -0.5, 0, 0.75, 54321.0, 2468086,483999967
NSDate *timeStampDate = timeStamp.date; };
for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
// Comparing timeIntervals instead of directly comparing dates because date NSTimeInterval value = values[i];
// equality requires the time intervals to be exactly the same, and the
// timeintervals go through a bit of floating point error as they are // Test Creation - date.
// converted back and forth from the internal representation. NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];
XCTAssertEqualWithAccuracy(date.timeIntervalSince1970, GPBTimestamp *timeStamp = [[GPBTimestamp alloc] initWithDate:date];
timeStampDate.timeIntervalSince1970,
kTimeAccuracy); XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
@"Offset %f - Date: %@", (double)value, date);
NSTimeInterval time = [date timeIntervalSince1970]; XCTAssertLessThan(timeStamp.nanos, 1e9,
GPBTimestamp *timeStamp2 = @"Offset %f - Date: %@", (double)value, date);
[[GPBTimestamp alloc] initWithTimeIntervalSince1970:time];
NSTimeInterval durationTime = timeStamp2.timeIntervalSince1970; // Comparing timeIntervals instead of directly comparing dates because date
XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); // equality requires the time intervals to be exactly the same, and the
[timeStamp release]; // timeintervals go through a bit of floating point error as they are
// converted back and forth from the internal representation.
// Test Mutation. XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; kTimeAccuracy,
timeStamp2.date = date; @"Offset %f - Date: %@", (double)value, date);
timeStampDate = timeStamp2.date; [timeStamp release];
XCTAssertEqualWithAccuracy(date.timeIntervalSince1970,
timeStampDate.timeIntervalSince1970, // Test Creation - timeIntervalSince1970.
kTimeAccuracy); timeStamp = [[GPBTimestamp alloc] initWithTimeIntervalSince1970:value];
time = date.timeIntervalSince1970; XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
timeStamp2.timeIntervalSince1970 = time; @"Offset %f - Date: %@", (double)value, date);
durationTime = timeStamp2.timeIntervalSince1970; XCTAssertLessThan(timeStamp.nanos, 1e9,
XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); @"Offset %f - Date: %@", (double)value, date);
[timeStamp2 release];
XCTAssertEqualWithAccuracy(value, timeStamp.timeIntervalSince1970,
kTimeAccuracy,
@"Offset %f - Date: %@", (double)value, date);
[timeStamp release];
// Test Mutation - date.
timeStamp = [[GPBTimestamp alloc] init];
timeStamp.date = date;
XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
@"Offset %f - Date: %@", (double)value, date);
XCTAssertLessThan(timeStamp.nanos, 1e9,
@"Offset %f - Date: %@", (double)value, date);
XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
kTimeAccuracy,
@"Offset %f - Date: %@", (double)value, date);
[timeStamp release];
// Test Mutation - timeIntervalSince1970.
timeStamp = [[GPBTimestamp alloc] init];
timeStamp.timeIntervalSince1970 = value;
XCTAssertGreaterThanOrEqual(timeStamp.nanos, 0,
@"Offset %f - Date: %@", (double)value, date);
XCTAssertLessThan(timeStamp.nanos, 1e9,
@"Offset %f - Date: %@", (double)value, date);
XCTAssertEqualWithAccuracy(value, timeStamp.date.timeIntervalSince1970,
kTimeAccuracy,
@"Offset %f - Date: %@", (double)value, date);
[timeStamp release];
}
} }
- (void)testDuration { - (void)testDuration {
// Test Creation. // Test negative and positive values.
NSTimeInterval time = [[NSDate date] timeIntervalSince1970]; NSTimeInterval values[] = { -1000.0001, -500.0, -0.5, 0, 0.75, 1000.0, 2000.0002 };
GPBDuration *duration = for (size_t i = 0; i < GPBARRAYSIZE(values); ++i) {
[[GPBDuration alloc] initWithTimeIntervalSince1970:time]; NSTimeInterval value = values[i];
NSTimeInterval durationTime = duration.timeIntervalSince1970;
XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); // Test Creation.
[duration release]; GPBDuration *duration =
[[GPBDuration alloc] initWithTimeInterval:value];
// Test Mutation. XCTAssertEqualWithAccuracy(value, duration.timeInterval, kTimeAccuracy,
GPBDuration *duration2 = @"For interval %f", (double)value);
[[GPBDuration alloc] initWithTimeIntervalSince1970:time]; if (value > 0) {
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:kFutureOffsetInterval]; XCTAssertGreaterThanOrEqual(duration.seconds, 0,
time = date.timeIntervalSince1970; @"For interval %f", (double)value);
duration2.timeIntervalSince1970 = time; XCTAssertGreaterThanOrEqual(duration.nanos, 0,
durationTime = duration2.timeIntervalSince1970; @"For interval %f", (double)value);
XCTAssertEqualWithAccuracy(time, durationTime, kTimeAccuracy); } else {
[duration2 release]; XCTAssertLessThanOrEqual(duration.seconds, 0,
@"For interval %f", (double)value);
XCTAssertLessThanOrEqual(duration.nanos, 0,
@"For interval %f", (double)value);
}
[duration release];
// Test Mutation.
duration = [[GPBDuration alloc] init];
duration.timeInterval = value;
XCTAssertEqualWithAccuracy(value, duration.timeInterval, kTimeAccuracy,
@"For interval %f", (double)value);
if (value > 0) {
XCTAssertGreaterThanOrEqual(duration.seconds, 0,
@"For interval %f", (double)value);
XCTAssertGreaterThanOrEqual(duration.nanos, 0,
@"For interval %f", (double)value);
} else {
XCTAssertLessThanOrEqual(duration.seconds, 0,
@"For interval %f", (double)value);
XCTAssertLessThanOrEqual(duration.nanos, 0,
@"For interval %f", (double)value);
}
[duration release];
}
} }
- (void)testAnyHelpers { - (void)testAnyHelpers {

Loading…
Cancel
Save