From 3b3f6129e6ddea199451a99e2d49a90924431733 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Thu, 29 Sep 2022 21:29:45 -0700 Subject: [PATCH] backend: allow negative timestamps in commits and operations I was reading a draft of "Git Rev News: Edition 91" [1] where Peff mentions some unfinished patches to allow negative timestamps in Git. So I figured I should add support for that before I forget. I haven't checked if libgit2 supports it, so it might be that our Git backend still doesn't support it after this patch. [1] https://github.com/git/git.github.io/blob/master/rev_news/drafts/edition-91.md --- lib/src/backend.rs | 4 ++-- lib/src/git_backend.rs | 4 ++-- lib/src/protos/op_store.proto | 2 +- lib/src/protos/store.proto | 2 +- lib/src/protos/working_copy.proto | 2 +- lib/src/working_copy.rs | 3 ++- src/commands.rs | 4 ++-- src/template_parser.rs | 4 ++-- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/src/backend.rs b/lib/src/backend.rs index 2c9e03da8..5fc7e9d01 100644 --- a/lib/src/backend.rs +++ b/lib/src/backend.rs @@ -226,7 +226,7 @@ pub enum Phase { } #[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)] -pub struct MillisSinceEpoch(pub u64); +pub struct MillisSinceEpoch(pub i64); #[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord)] pub struct Timestamp { @@ -244,7 +244,7 @@ impl Timestamp { datetime: chrono::DateTime, ) -> Self { Self { - timestamp: MillisSinceEpoch(datetime.timestamp_millis() as u64), + timestamp: MillisSinceEpoch(datetime.timestamp_millis()), tz_offset: datetime.offset().local_minus_utc() / 60, } } diff --git a/lib/src/git_backend.rs b/lib/src/git_backend.rs index 9649218be..612bb4d45 100644 --- a/lib/src/git_backend.rs +++ b/lib/src/git_backend.rs @@ -101,7 +101,7 @@ impl GitBackend { fn signature_from_git(signature: git2::Signature) -> Signature { let name = signature.name().unwrap_or("").to_owned(); let email = signature.email().unwrap_or("").to_owned(); - let timestamp = MillisSinceEpoch((signature.when().seconds() * 1000) as u64); + let timestamp = MillisSinceEpoch(signature.when().seconds() * 1000); let tz_offset = signature.when().offset_minutes(); Signature { name, @@ -117,7 +117,7 @@ fn signature_to_git(signature: &Signature) -> git2::Signature { let name = &signature.name; let email = &signature.email; let time = git2::Time::new( - (signature.timestamp.timestamp.0 / 1000) as i64, + signature.timestamp.timestamp.0.div_euclid(1000), signature.timestamp.tz_offset, ); git2::Signature::new(name, email, &time).unwrap() diff --git a/lib/src/protos/op_store.proto b/lib/src/protos/op_store.proto index 37b9af483..2c7be5cca 100644 --- a/lib/src/protos/op_store.proto +++ b/lib/src/protos/op_store.proto @@ -78,7 +78,7 @@ message Operation { // TODO: Share with store.proto? Do we even need the timezone here? message Timestamp { - uint64 millis_since_epoch = 1; + int64 millis_since_epoch = 1; int32 tz_offset = 2; } diff --git a/lib/src/protos/store.proto b/lib/src/protos/store.proto index 29c8df99b..7f119c989 100644 --- a/lib/src/protos/store.proto +++ b/lib/src/protos/store.proto @@ -47,7 +47,7 @@ message Commit { string description = 5; message Timestamp { - uint64 millis_since_epoch = 1; + int64 millis_since_epoch = 1; int32 tz_offset = 2; } message Signature { diff --git a/lib/src/protos/working_copy.proto b/lib/src/protos/working_copy.proto index 862e7786d..0e36baa4f 100644 --- a/lib/src/protos/working_copy.proto +++ b/lib/src/protos/working_copy.proto @@ -24,7 +24,7 @@ enum FileType { } message FileState { - uint64 mtime_millis_since_epoch = 1; + int64 mtime_millis_since_epoch = 1; uint64 size = 2; FileType file_type = 3; // Set only if file_type is Conflict diff --git a/lib/src/working_copy.rs b/lib/src/working_copy.rs index 347c3b573..a6ea71bcf 100644 --- a/lib/src/working_copy.rs +++ b/lib/src/working_copy.rs @@ -222,7 +222,8 @@ fn mtime_from_metadata(metadata: &Metadata) -> MillisSinceEpoch { .expect("mtime before unix epoch"); MillisSinceEpoch( - u64::try_from(since_epoch.as_millis()).expect("mtime billions of years into the future"), + i64::try_from(since_epoch.as_millis()) + .expect("mtime billions of years into the future or past"), ) } diff --git a/src/commands.rs b/src/commands.rs index b04ff72ae..040beb06c 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -3685,8 +3685,8 @@ fn cmd_bench( fn format_timestamp(timestamp: &Timestamp) -> String { let utc = Utc .timestamp( - timestamp.timestamp.0 as i64 / 1000, - (timestamp.timestamp.0 % 1000) as u32 * 1000000, + timestamp.timestamp.0.div_euclid(1000), + (timestamp.timestamp.0.rem_euclid(1000)) as u32 * 1000000, ) .with_timezone(&FixedOffset::east(timestamp.tz_offset * 60)); utc.format("%Y-%m-%d %H:%M:%S.%3f %:z").to_string() diff --git a/src/template_parser.rs b/src/template_parser.rs index d0566856d..436856c60 100644 --- a/src/template_parser.rs +++ b/src/template_parser.rs @@ -101,8 +101,8 @@ impl TemplateProperty for SignatureTimestamp { fn extract(&self, context: &Signature) -> String { let utc = Utc .timestamp( - context.timestamp.timestamp.0 as i64 / 1000, - (context.timestamp.timestamp.0 % 1000) as u32 * 1000000, + context.timestamp.timestamp.0.div_euclid(1000), + context.timestamp.timestamp.0.rem_euclid(1000) as u32 * 1000000, ) .with_timezone(&FixedOffset::east(context.timestamp.tz_offset * 60)); utc.format("%Y-%m-%d %H:%M:%S.%3f %:z").to_string()