FSTTimestamp.m 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright 2017 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "Firestore/Source/Core/FSTTimestamp.h"
  17. #import "Firestore/Source/Util/FSTAssert.h"
  18. #import "Firestore/Source/Util/FSTComparison.h"
  19. NS_ASSUME_NONNULL_BEGIN
  20. static const int kNanosPerSecond = 1000000000;
  21. @implementation FSTTimestamp
  22. #pragma mark - Constructors
  23. + (instancetype)timestamp {
  24. return [FSTTimestamp timestampWithDate:[NSDate date]];
  25. }
  26. + (instancetype)timestampWithDate:(NSDate *)date {
  27. double secondsDouble;
  28. double fraction = modf(date.timeIntervalSince1970, &secondsDouble);
  29. // GCP Timestamps always have non-negative nanos.
  30. if (fraction < 0) {
  31. fraction += 1.0;
  32. secondsDouble -= 1.0;
  33. }
  34. int64_t seconds = (int64_t)secondsDouble;
  35. int32_t nanos = (int32_t)(fraction * kNanosPerSecond);
  36. return [[FSTTimestamp alloc] initWithSeconds:seconds nanos:nanos];
  37. }
  38. - (instancetype)initWithSeconds:(int64_t)seconds nanos:(int32_t)nanos {
  39. self = [super init];
  40. if (self) {
  41. FSTAssert(nanos >= 0, @"timestamp nanoseconds out of range: %d", nanos);
  42. FSTAssert(nanos < 1e9, @"timestamp nanoseconds out of range: %d", nanos);
  43. // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore supports.
  44. FSTAssert(seconds >= -62135596800L, @"timestamp seconds out of range: %lld", seconds);
  45. // This will break in the year 10,000.
  46. FSTAssert(seconds < 253402300800L, @"timestamp seconds out of range: %lld", seconds);
  47. _seconds = seconds;
  48. _nanos = nanos;
  49. }
  50. return self;
  51. }
  52. #pragma mark - NSObject methods
  53. - (BOOL)isEqual:(id)object {
  54. if (self == object) {
  55. return YES;
  56. }
  57. if (![object isKindOfClass:[FSTTimestamp class]]) {
  58. return NO;
  59. }
  60. return [self isEqualToTimestamp:(FSTTimestamp *)object];
  61. }
  62. - (NSUInteger)hash {
  63. return (NSUInteger)((self.seconds >> 32) ^ self.seconds ^ self.nanos);
  64. }
  65. - (NSString *)description {
  66. return [NSString
  67. stringWithFormat:@"<FSTTimestamp: seconds=%lld nanos=%d>", self.seconds, self.nanos];
  68. }
  69. /** Implements NSCopying without actually copying because timestamps are immutable. */
  70. - (id)copyWithZone:(NSZone *_Nullable)zone {
  71. return self;
  72. }
  73. #pragma mark - Public methods
  74. - (NSDate *)approximateDateValue {
  75. NSTimeInterval interval = (NSTimeInterval)self.seconds + ((NSTimeInterval)self.nanos) / 1e9;
  76. return [NSDate dateWithTimeIntervalSince1970:interval];
  77. }
  78. - (BOOL)isEqualToTimestamp:(FSTTimestamp *)other {
  79. return [self compare:other] == NSOrderedSame;
  80. }
  81. - (NSString *)ISO8601String {
  82. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  83. formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss";
  84. formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
  85. NSDate *secondsDate = [NSDate dateWithTimeIntervalSince1970:self.seconds];
  86. NSString *secondsString = [formatter stringFromDate:secondsDate];
  87. FSTAssert(secondsString.length == 19, @"Invalid ISO string: %@", secondsString);
  88. NSString *nanosString = [NSString stringWithFormat:@"%09d", self.nanos];
  89. return [NSString stringWithFormat:@"%@.%@Z", secondsString, nanosString];
  90. }
  91. - (NSComparisonResult)compare:(FSTTimestamp *)other {
  92. NSComparisonResult result = FSTCompareInt64s(self.seconds, other.seconds);
  93. if (result != NSOrderedSame) {
  94. return result;
  95. }
  96. return FSTCompareInt32s(self.nanos, other.nanos);
  97. }
  98. @end
  99. NS_ASSUME_NONNULL_END