diff options
author | Konstantin Varlamov <var-const@users.noreply.github.com> | 2018-02-20 17:33:57 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-20 17:33:57 -0500 |
commit | 14ea068f5fd03a658017f8472a4078a727fabc3a (patch) | |
tree | 56696c49546e2147ec1b8ebdeba24dd292f0c951 /Firestore/Source/API | |
parent | de00de25deebc35c4c7167135d5b1f29a7d9fe6f (diff) |
Make FSTTimestamp into a public Firestore class (#698)
- FSTTimestamp is now FIRTimestamp, under Firestore/Source/{Public,API}. This is a temporary solution; eventually, FIRTimestamp is supposed to live somewhere under Firebase;
- move most internal Timestamp methods to the public header (the only exception is ISOString).
Diffstat (limited to 'Firestore/Source/API')
-rw-r--r-- | Firestore/Source/API/FIRTimestamp+Internal.h | 35 | ||||
-rw-r--r-- | Firestore/Source/API/FIRTimestamp.m | 152 | ||||
-rw-r--r-- | Firestore/Source/API/FSTUserDataConverter.mm | 5 |
3 files changed, 190 insertions, 2 deletions
diff --git a/Firestore/Source/API/FIRTimestamp+Internal.h b/Firestore/Source/API/FIRTimestamp+Internal.h new file mode 100644 index 0000000..48e38b2 --- /dev/null +++ b/Firestore/Source/API/FIRTimestamp+Internal.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRTimestamp.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Internal FIRTimestamp API we don't want exposed in our public header files. */ +@interface FIRTimestamp (Internal) + +/** + * Converts the given date to an ISO 8601 timestamp string, useful for rendering in JSON. + * + * ISO 8601 dates times in UTC look like this: "1912-04-14T23:40:00.000000000Z". + * + * @see http://www.ecma-international.org/ecma-262/6.0/#sec-date-time-string-format + */ +- (NSString *)ISO8601String; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FIRTimestamp.m b/Firestore/Source/API/FIRTimestamp.m new file mode 100644 index 0000000..489b921 --- /dev/null +++ b/Firestore/Source/API/FIRTimestamp.m @@ -0,0 +1,152 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Firestore/Source/API/FIRTimestamp+Internal.h" + +NS_ASSUME_NONNULL_BEGIN + +static const int kNanosPerSecond = 1000000000; + +@implementation FIRTimestamp (Internal) + +#pragma mark - Internal public methods + +- (NSString *)ISO8601String { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss"; + formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; + NSDate *secondsDate = [NSDate dateWithTimeIntervalSince1970:self.seconds]; + NSString *secondsString = [formatter stringFromDate:secondsDate]; + if (secondsString.length != 19) { + [NSException raise:@"Invalid ISO string" format:@"Invalid ISO string: %@", secondsString]; + } + + NSString *nanosString = [NSString stringWithFormat:@"%09d", self.nanoseconds]; + return [NSString stringWithFormat:@"%@.%@Z", secondsString, nanosString]; +} + +@end + +@implementation FIRTimestamp + +#pragma mark - Constructors + ++ (instancetype)timestampWithDate:(NSDate *)date { + double secondsDouble; + double fraction = modf(date.timeIntervalSince1970, &secondsDouble); + // GCP Timestamps always have non-negative nanos. + if (fraction < 0) { + fraction += 1.0; + secondsDouble -= 1.0; + } + int64_t seconds = (int64_t)secondsDouble; + int32_t nanos = (int32_t)(fraction * kNanosPerSecond); + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanos]; +} + ++ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanoseconds]; +} + ++ (instancetype)timestamp { + return [FIRTimestamp timestampWithDate:[NSDate date]]; +} + +- (instancetype)initWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + self = [super init]; + if (self) { + if (nanoseconds < 0) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + if (nanoseconds >= 1e9) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + // Midnight at the beginning of 1/1/1 is the earliest timestamp supported. + if (seconds < -62135596800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + // This will break in the year 10,000. + if (seconds >= 253402300800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + + _seconds = seconds; + _nanoseconds = nanoseconds; + } + return self; +} + +#pragma mark - NSObject methods + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FIRTimestamp class]]) { + return NO; + } + return [self isEqualToTimestamp:(FIRTimestamp *)object]; +} + +- (NSUInteger)hash { + return (NSUInteger)((self.seconds >> 32) ^ self.seconds ^ self.nanoseconds); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"FIRTimestamp: seconds=%lld nanoseconds=%d>", self.seconds, + self.nanoseconds]; +} + +/** Implements NSCopying without actually copying because timestamps are immutable. */ +- (id)copyWithZone:(NSZone *_Nullable)zone { + return self; +} + +#pragma mark - Public methods + +- (NSDate *)approximateDateValue { + NSTimeInterval interval = (NSTimeInterval)self.seconds + ((NSTimeInterval)self.nanoseconds) / 1e9; + return [NSDate dateWithTimeIntervalSince1970:interval]; +} + +- (NSComparisonResult)compare:(FIRTimestamp *)other { + if (self.seconds < other.seconds) { + return NSOrderedAscending; + } else if (self.seconds > other.seconds) { + return NSOrderedDescending; + } + + if (self.nanoseconds < other.nanoseconds) { + return NSOrderedAscending; + } else if (self.nanoseconds > other.nanoseconds) { + return NSOrderedDescending; + } + return NSOrderedSame; +} + +#pragma mark - Private methods + +- (BOOL)isEqualToTimestamp:(FIRTimestamp *)other { + return [self compare:other] == NSOrderedSame; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/API/FSTUserDataConverter.mm b/Firestore/Source/API/FSTUserDataConverter.mm index 80d4625..f97aea1 100644 --- a/Firestore/Source/API/FSTUserDataConverter.mm +++ b/Firestore/Source/API/FSTUserDataConverter.mm @@ -16,13 +16,14 @@ #import "Firestore/Source/API/FSTUserDataConverter.h" +#import "FIRTimestamp.h" + #import "FIRGeoPoint.h" #import "Firestore/Source/API/FIRDocumentReference+Internal.h" #import "Firestore/Source/API/FIRFieldPath+Internal.h" #import "Firestore/Source/API/FIRFieldValue+Internal.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRSetOptions+Internal.h" -#import "Firestore/Source/Core/FSTTimestamp.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTFieldValue.h" #import "Firestore/Source/Model/FSTMutation.h" @@ -536,7 +537,7 @@ typedef NS_ENUM(NSInteger, FSTUserDataSource) { return [FSTStringValue stringValue:input]; } else if ([input isKindOfClass:[NSDate class]]) { - return [FSTTimestampValue timestampValue:[FSTTimestamp timestampWithDate:input]]; + return [FSTTimestampValue timestampValue:[FIRTimestamp timestampWithDate:input]]; } else if ([input isKindOfClass:[FIRGeoPoint class]]) { return [FSTGeoPointValue geoPointValue:input]; |