taskchampion: Add time.utc_timestamp function.

Add a function that returns a Timestamp from an i64. One advantage is
improved readability since this function is guaranteed to return a
`LocalResult::Single`. Anther advantage is that it will panic if
something other than a LocalResult::Single is returned by chrono, which
shouldn't be possible for UTC timestamps which can't have DST ambiguity.
This commit is contained in:
ryneeverett 2023-02-05 14:54:56 -05:00 committed by Dustin J. Mitchell
parent 5a4b981b6c
commit 1c4e103904
6 changed files with 34 additions and 36 deletions

View file

@ -1,7 +1,8 @@
//! Trait implementations for a few atomic types
use crate::traits::*;
use taskchampion::chrono::{offset::LocalResult, prelude::*};
use taskchampion::chrono::{DateTime, Utc};
use taskchampion::utc_timestamp;
impl PassByValue for usize {
type RustType = usize;
@ -21,9 +22,7 @@ impl PassByValue for libc::time_t {
unsafe fn from_ctype(self) -> Option<DateTime<Utc>> {
if self != 0 {
if let LocalResult::Single(ts) = Utc.timestamp_opt(self, 0) {
return Some(ts);
}
return Some(utc_timestamp(self));
}
None
}

View file

@ -5,8 +5,7 @@ use std::convert::TryFrom;
use std::ops::Deref;
use std::ptr::NonNull;
use std::str::FromStr;
use taskchampion::chrono::{offset::LocalResult, TimeZone, Utc};
use taskchampion::{Annotation, Tag, Task, TaskMut, Uuid};
use taskchampion::{utc_timestamp, Annotation, Tag, Task, TaskMut, Uuid};
/// A task, as publicly exposed by this library.
///
@ -760,9 +759,7 @@ pub unsafe extern "C" fn tc_task_remove_annotation(task: *mut TCTask, entry: i64
wrap_mut(
task,
|task| {
if let LocalResult::Single(ts) = Utc.timestamp_opt(entry, 0) {
task.remove_annotation(ts)?;
}
task.remove_annotation(utc_timestamp(entry))?;
Ok(TCResult::Ok)
},
TCResult::Error,

View file

@ -63,7 +63,7 @@ pub use errors::Error;
pub use replica::Replica;
pub use server::{Server, ServerConfig};
pub use storage::StorageConfig;
pub use task::{Annotation, Status, Tag, Task, TaskMut};
pub use task::{utc_timestamp, Annotation, Status, Tag, Task, TaskMut};
pub use workingset::WorkingSet;
/// Re-exported type from the `uuid` crate, for ease of compatibility for consumers of this crate.

View file

@ -1,14 +1,12 @@
#![allow(clippy::module_inception)]
use chrono::prelude::*;
mod annotation;
mod status;
mod tag;
mod task;
mod time;
pub use annotation::Annotation;
pub use status::Status;
pub use tag::Tag;
pub use task::{Task, TaskMut};
pub type Timestamp = DateTime<Utc>;
pub use time::{utc_timestamp, Timestamp};

View file

@ -1,10 +1,10 @@
use super::tag::{SyntheticTag, TagInner};
use super::{Annotation, Status, Tag, Timestamp};
use super::{utc_timestamp, Annotation, Status, Tag, Timestamp};
use crate::depmap::DependencyMap;
use crate::errors::{Error, Result};
use crate::replica::Replica;
use crate::storage::TaskMap;
use chrono::{offset::LocalResult, prelude::*};
use chrono::prelude::*;
use log::trace;
use std::convert::AsRef;
use std::convert::TryInto;
@ -136,7 +136,7 @@ impl Task {
.unwrap_or("")
}
pub fn get_entry(&self) -> Option<DateTime<Utc>> {
pub fn get_entry(&self) -> Option<Timestamp> {
self.get_timestamp(Prop::Entry.as_ref())
}
@ -149,7 +149,7 @@ impl Task {
/// Get the wait time. If this value is set, it will be returned, even
/// if it is in the past.
pub fn get_wait(&self) -> Option<DateTime<Utc>> {
pub fn get_wait(&self) -> Option<Timestamp> {
self.get_timestamp(Prop::Wait.as_ref())
}
@ -227,15 +227,10 @@ impl Task {
self.taskmap.iter().filter_map(|(k, v)| {
if let Some(ts) = k.strip_prefix("annotation_") {
if let Ok(ts) = ts.parse::<i64>() {
if let LocalResult::Single(entry) = Utc.timestamp_opt(ts, 0) {
return Some(Annotation {
entry,
entry: utc_timestamp(ts),
description: v.to_owned(),
});
} else {
// ignore an invalid timestamp
return None;
}
}
// note that invalid "annotation_*" are ignored
}
@ -278,7 +273,7 @@ impl Task {
}
/// Get the modification time for this task.
pub fn get_modified(&self) -> Option<DateTime<Utc>> {
pub fn get_modified(&self) -> Option<Timestamp> {
self.get_timestamp(Prop::Modified.as_ref())
}
@ -313,12 +308,10 @@ impl Task {
|| key.starts_with("dep_")
}
fn get_timestamp(&self, property: &str) -> Option<DateTime<Utc>> {
fn get_timestamp(&self, property: &str) -> Option<Timestamp> {
if let Some(ts) = self.taskmap.get(property) {
if let Ok(ts) = ts.parse() {
if let LocalResult::Single(entry) = Utc.timestamp_opt(ts, 0) {
return Some(entry);
}
return Some(utc_timestamp(ts));
}
// if the value does not parse as an integer, default to None
}
@ -366,15 +359,15 @@ impl<'r> TaskMut<'r> {
self.set_string(Prop::Priority.as_ref(), Some(priority))
}
pub fn set_entry(&mut self, entry: Option<DateTime<Utc>>) -> Result<()> {
pub fn set_entry(&mut self, entry: Option<Timestamp>) -> Result<()> {
self.set_timestamp(Prop::Entry.as_ref(), entry)
}
pub fn set_wait(&mut self, wait: Option<DateTime<Utc>>) -> Result<()> {
pub fn set_wait(&mut self, wait: Option<Timestamp>) -> Result<()> {
self.set_timestamp(Prop::Wait.as_ref(), wait)
}
pub fn set_modified(&mut self, modified: DateTime<Utc>) -> Result<()> {
pub fn set_modified(&mut self, modified: Timestamp) -> Result<()> {
self.set_timestamp(Prop::Modified.as_ref(), Some(modified))
}
@ -548,7 +541,7 @@ impl<'r> TaskMut<'r> {
self.set_value(property, value)
}
fn set_timestamp(&mut self, property: &str, value: Option<DateTime<Utc>>) -> Result<()> {
fn set_timestamp(&mut self, property: &str, value: Option<Timestamp>) -> Result<()> {
self.set_string(property, value.map(|v| v.timestamp().to_string()))
}

View file

@ -0,0 +1,11 @@
use chrono::{offset::LocalResult, DateTime, TimeZone, Utc};
pub type Timestamp = DateTime<Utc>;
pub fn utc_timestamp(secs: i64) -> Timestamp {
match Utc.timestamp_opt(secs, 0) {
LocalResult::Single(tz) => tz,
// The other two variants are None and Ambiguous, which both are caused by DST.
_ => unreachable!("We're requesting UTC so daylight saving time isn't a factor."),
}
}