Skip to content

Commit

Permalink
Add elapsed_years to Date and DateTime (#557)
Browse files Browse the repository at this point in the history
Co-authored-by: Cecile Tonglet <cecile.tonglet@cecton.com>
Co-authored-by: Milo <50248166+Milo123459@users.noreply.github.com>
  • Loading branch information
3 people committed Jun 8, 2022
1 parent 3a7d0e4 commit 1d33cbc
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Expand Up @@ -39,3 +39,4 @@ Steve Klabnik <steve@steveklabnik.com>
Tom Gallacher <tomgallacher23@gmail.com>
klutzy <klutzytheklutzy@gmail.com>
kud1ing <github@kudling.de>
Yohan Boogaert <yozhgoor@outlook.com>
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@ Versions with only mechanical changes will be omitted from the following list.
* Fix `DurationRound` is not TZ aware (#495)
* Implement `DurationRound` for `NaiveDateTime`
* Add `DateTime::from_local()` to construct from given local date and time (#572)
* Add a function that calculates the number of years elapsed between now and a given `Date` or `DateTime` (#557)
* Correct build for wasm32-unknown-emscripten target (#568)
* Change `Local::now()` and `Utc::now()` documentation from "current date" to "current date and time" (#647)
* Fix `duration_round` panic on rounding by `Duration::zero()` (#658)
Expand Down
41 changes: 41 additions & 0 deletions src/date.rs
Expand Up @@ -275,6 +275,24 @@ impl<Tz: TimeZone> Date<Tz> {
pub fn naive_local(&self) -> NaiveDate {
self.date
}

/// Retrieves the elapsed years from now to the given [`Date`].
#[cfg(feature = "clock")]
pub fn elapsed_years(&self) -> u32 {
let now = Utc::today().with_timezone(&self.timezone());

let years = if (now.month(), now.day()) < (self.month(), self.day()) {
now.year() - self.year() - 1
} else {
now.year() - self.year()
};

if years.is_positive() {
years as u32
} else {
0
}
}
}

/// Maps the local date to other date with given conversion function.
Expand Down Expand Up @@ -498,3 +516,26 @@ where
write!(f, "{}{}", self.naive_local(), self.offset)
}
}

#[cfg(test)]
mod tests {
use crate::consts::f64;
use crate::offset::Utc;
use crate::oldtime::Duration;

#[test]
#[cfg(feature = "clock")]
fn test_years_elapsed() {
// This is always at least one year because 1 year = 52.1775 weeks.
let one_year_ago =
Utc::today() - Duration::weeks((f64::WEEKS_PER_YEAR * 1.5).ceil() as i64);
// A bit more than 2 years.
let two_year_ago =
Utc::today() - Duration::weeks((f64::WEEKS_PER_YEAR * 2.5).ceil() as i64);

assert_eq!(one_year_ago.elapsed_years(), 1);
assert_eq!(two_year_ago.elapsed_years(), 2);
// if the given Date is later than now, the function will always return 0.
assert_eq!((Utc::today() + Duration::weeks(12)).elapsed_years(), 0);
}
}
18 changes: 18 additions & 0 deletions src/datetime/mod.rs
Expand Up @@ -355,6 +355,24 @@ impl<Tz: TimeZone> DateTime<Tz> {
pub fn naive_local(&self) -> NaiveDateTime {
self.datetime + self.offset.fix()
}

/// Retrieve the elapsed years from now to the given [`DateTime`].
#[cfg(feature = "clock")]
pub fn elapsed_years(&self) -> u32 {
let now = Utc::now().with_timezone(&self.timezone());

let years =
if (now.month(), now.day(), now.time()) < (self.month(), self.day(), self.time()) {
now.year() - self.year() - 1
} else {
now.year() - self.year()
};
if years.is_positive() {
years as u32
} else {
0
}
}
}

impl Default for DateTime<Utc> {
Expand Down
17 changes: 17 additions & 0 deletions src/datetime/tests.rs
@@ -1,6 +1,8 @@
use std::time::{SystemTime, UNIX_EPOCH};

use super::DateTime;
#[cfg(feature = "clock")]
use crate::consts::f64;
use crate::naive::{NaiveDate, NaiveTime};
#[cfg(feature = "clock")]
use crate::offset::Local;
Expand Down Expand Up @@ -407,3 +409,18 @@ fn test_datetime_from_local() {
assert_eq!(datetime_east, datetime_utc.with_timezone(&timezone_east));
assert_eq!(datetime_west, datetime_utc.with_timezone(&timezone_west));
}

#[test]
#[cfg(feature = "clock")]
fn test_years_elapsed() {
// This is always at least one year because 1 year = 52.1775 weeks.
let one_year_ago = Utc::today() - Duration::weeks((f64::WEEKS_PER_YEAR * 1.5).ceil() as i64);
// A bit more than 2 years.
let two_year_ago = Utc::today() - Duration::weeks((f64::WEEKS_PER_YEAR * 2.5).ceil() as i64);

assert_eq!(one_year_ago.elapsed_years(), 1);
assert_eq!(two_year_ago.elapsed_years(), 2);

// If the given DateTime is later than now, the function will always return 0.
assert_eq!((Utc::today() + Duration::weeks(12)).elapsed_years(), 0);
}
14 changes: 14 additions & 0 deletions src/lib.rs
Expand Up @@ -508,6 +508,20 @@ pub use month::{Month, ParseMonthError};
mod traits;
pub use traits::{Datelike, Timelike};

/// Constants that can be used by all components.
pub mod consts {
/// Constants of type `f32`.
pub mod f32 {
/// Number of weeks in a year.
pub const WEEKS_PER_YEAR: f32 = 52.1775;
}
/// Constants of type `f64`.
pub mod f64 {
/// Number of weeks in a year.
pub const WEEKS_PER_YEAR: f64 = 52.1775;
}
}

#[cfg(feature = "__internal_bench")]
#[doc(hidden)]
pub use naive::__BenchYearFlags;
Expand Down

0 comments on commit 1d33cbc

Please sign in to comment.