blob: 027f5a55ed76b09993320da05e7f4e17de63188a [file] [log] [blame]
// Copyright 2018, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of cloud_firestore;
const int _kThousand = 1000;
const int _kMillion = 1000000;
const int _kBillion = 1000000000;
void _check(bool expr, String name, int value) {
if (!expr) {
throw ArgumentError("Timestamp $name out of range: $value");
}
}
/// A Timestamp represents a point in time independent of any time zone or calendar,
/// represented as seconds and fractions of seconds at nanosecond resolution in UTC
/// Epoch time. It is encoded using the Proleptic Gregorian Calendar which extends
/// the Gregorian calendar backwards to year one. It is encoded assuming all minutes
/// are 60 seconds long, i.e. leap seconds are "smeared" so that no leap second table
/// is needed for interpretation. Range is from 0001-01-01T00:00:00Z to
/// 9999-12-31T23:59:59.999999999Z. By restricting to that range, we ensure that we
/// can convert to and from RFC 3339 date strings.
///
/// For more information, see [the reference timestamp definition](https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto)
class Timestamp implements Comparable<Timestamp> {
Timestamp(this._seconds, this._nanoseconds) {
_validateRange(_seconds, _nanoseconds);
}
factory Timestamp.fromMillisecondsSinceEpoch(int milliseconds) {
final int seconds = (milliseconds / _kThousand).floor();
final int nanoseconds = (milliseconds - seconds * _kThousand) * _kMillion;
return Timestamp(seconds, nanoseconds);
}
factory Timestamp.fromMicrosecondsSinceEpoch(int microseconds) {
final int seconds = (microseconds / _kMillion).floor();
final int nanoseconds = (microseconds - seconds * _kMillion) * _kThousand;
return Timestamp(seconds, nanoseconds);
}
factory Timestamp.fromDate(DateTime date) {
return Timestamp.fromMicrosecondsSinceEpoch(date.microsecondsSinceEpoch);
}
factory Timestamp.now() {
return Timestamp.fromMicrosecondsSinceEpoch(
DateTime.now().microsecondsSinceEpoch);
}
final int _seconds;
final int _nanoseconds;
static const int _kStartOfTime = -62135596800;
static const int _kEndOfTime = 253402300800;
int get seconds => _seconds;
int get nanoseconds => _nanoseconds;
int get millisecondsSinceEpoch =>
(seconds * _kThousand + nanoseconds / _kMillion).floor();
int get microsecondsSinceEpoch =>
(seconds * _kMillion + nanoseconds / _kThousand).floor();
DateTime toDate() {
return DateTime.fromMicrosecondsSinceEpoch(microsecondsSinceEpoch);
}
@override
int get hashCode => hashValues(seconds, nanoseconds);
@override
bool operator ==(dynamic o) =>
o is Timestamp && o.seconds == seconds && o.nanoseconds == nanoseconds;
@override
int compareTo(Timestamp other) {
if (seconds == other.seconds) {
return nanoseconds.compareTo(other.nanoseconds);
}
return seconds.compareTo(other.seconds);
}
@override
String toString() {
return "Timestamp(seconds=$seconds, nanoseconds=$nanoseconds)";
}
static void _validateRange(int seconds, int nanoseconds) {
_check(nanoseconds >= 0, 'nanoseconds', nanoseconds);
_check(nanoseconds < _kBillion, 'nanoseconds', nanoseconds);
_check(seconds >= _kStartOfTime, 'seconds', seconds);
_check(seconds < _kEndOfTime, 'seconds', seconds);
}
}