Skip to content

Commit

Permalink
feat: Update Timestamp Constructor with nanoseconds (invertase#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
KKimj authored Jul 22, 2024
1 parent 68c4dd2 commit c4e1493
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/dart_firebase_admin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
unused codes.
- Fixes crash when updating users (thanks to @HeySreelal)
- Marked various classes that cannot be extended as base/final.
- Added a default constructor on `Timestamp` (thanks to @KKimj)

## 0.3.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,19 @@ String _toGoogleDateTime({required int seconds, required int nanoseconds}) {
return '${formattedDate}Z';
}

/// 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)
@immutable
final class Timestamp implements _Serializable {
Timestamp._({required this.seconds, required this.nanoseconds}) {
Timestamp({required this.seconds, required this.nanoseconds}) {
const minSeconds = -62135596800;
const maxSeconds = 253402300799;

Expand Down Expand Up @@ -63,7 +73,7 @@ final class Timestamp implements _Serializable {
/// Returns a new [Timestamp] representing the same point in time
/// as the given date.
factory Timestamp.fromDate(DateTime date) {
return Timestamp.fromMillis(date.millisecondsSinceEpoch);
return Timestamp.fromMicros(date.microsecondsSinceEpoch);
}

/// Creates a new timestamp from the given number of milliseconds.
Expand All @@ -82,7 +92,28 @@ final class Timestamp implements _Serializable {
factory Timestamp.fromMillis(int milliseconds) {
final seconds = (milliseconds / 1000).floor();
final nanos = (milliseconds - seconds * 1000) * _msToNanos;
return Timestamp._(seconds: seconds, nanoseconds: nanos);

return Timestamp(seconds: seconds, nanoseconds: nanos);
}

/// Creates a new timestamp from the given number of microseconds.
///
/// ```dart
/// final documentRef = firestore.doc('col/doc');
///
/// documentRef.set({ 'startTime': Timestamp.fromMicros(42) });
/// ```
///
/// - [microseconds]: Number of microseconds since Unix epoch
/// 1970-01-01T00:00:00Z.
///
/// Returns a new [Timestamp] representing the same point in time
/// as the given number of microseconds.
factory Timestamp.fromMicros(int microseconds) {
final seconds = (microseconds / 1000 / 1000).floor();
final nanos = (microseconds - seconds * 1000 * 1000) * _usToNanos;

return Timestamp(seconds: seconds, nanoseconds: nanos);
}

factory Timestamp._fromString(String timestampValue) {
Expand All @@ -106,13 +137,14 @@ final class Timestamp implements _Serializable {
);
}

return Timestamp._(
return Timestamp(
seconds: date.millisecondsSinceEpoch ~/ 1000,
nanoseconds: nanos,
);
}

static const _msToNanos = 1000000;
static const _usToNanos = 1000;

final int seconds;
final int nanoseconds;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:dart_firebase_admin/firestore.dart';
import 'package:test/test.dart';

void main() {
group('Timestamp', () {
test('constructor', () {
final now = DateTime.now().toUtc();
final seconds = now.millisecondsSinceEpoch ~/ 1000;
final nanoseconds =
(now.microsecondsSinceEpoch - seconds * 1000 * 1000) * 1000;

expect(
Timestamp(seconds: seconds, nanoseconds: nanoseconds),
Timestamp.fromDate(now),
);
});

test('fromDate constructor', () {
final now = DateTime.now().toUtc();
final timestamp = Timestamp.fromDate(now);

expect(timestamp.seconds, now.millisecondsSinceEpoch ~/ 1000);
});

test('fromMillis constructor', () {
final now = DateTime.now().toUtc();
final timestamp = Timestamp.fromMillis(now.millisecondsSinceEpoch);

expect(timestamp.seconds, now.millisecondsSinceEpoch ~/ 1000);
expect(
timestamp.nanoseconds,
(now.millisecondsSinceEpoch % 1000) * (1000 * 1000),
);
});

test('fromMicros constructor', () {
final now = DateTime.now().toUtc();
final timestamp = Timestamp.fromMicros(now.microsecondsSinceEpoch);

expect(timestamp.seconds, now.microsecondsSinceEpoch ~/ (1000 * 1000));
expect(
timestamp.nanoseconds,
(now.microsecondsSinceEpoch % (1000 * 1000)) * 1000,
);
});
});
}

0 comments on commit c4e1493

Please sign in to comment.