diff --git a/Cargo.toml b/Cargo.toml index 397f661..7078dd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ aes = "0.8.3" base64 = "0.21.2" blockhash = "0.5.0" cbc = { version = "0.1.2", features = ["std"] } +chrono = "0.4.26" cipher = "0.4.4" des = "0.8.1" hex = "0.4.3" diff --git a/README.md b/README.md index fd99f0a..1d767b4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能: - [x] MD5 散列算法 - [x] 图像感知散列算法 - 唯一序列号生成器 - - [ ] 改进版雪花 ID 生成器(短主机精简日期版) + - [ ] 冰雹 ID 生成器(短主机精简日期版雪花 ID) - [x] UUID 生成器 - [x] short UUID 生成器 - 签名算法 @@ -36,5 +36,7 @@ Rust 中可以使用的常用辅助功能工具箱。主要配备以下功能: - 序列化算法 - [x] Base64 算法 - [x] Hex 直转 +- 常用工具函数 + - [x] 日期时间函数 本工具箱仅可支持于 Rust 程序中使用,可以编译为`rlib`或者`dylib`。 diff --git a/src/lib.rs b/src/lib.rs index b637022..b953130 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,4 +5,5 @@ pub mod hash; pub mod serial_code; pub mod serialize; pub mod signature; +pub mod time; pub mod verifiy_code; diff --git a/src/time/mod.rs b/src/time/mod.rs new file mode 100644 index 0000000..e721c6a --- /dev/null +++ b/src/time/mod.rs @@ -0,0 +1,147 @@ +use chrono::{DateTime, Datelike, Duration, FixedOffset, NaiveDate, NaiveDateTime, Utc}; + +/// 获取一个类型为`chrono::DateTime`类型的当前日期时间的实例。时间时区将自动被设置为东八区。 +pub fn now_asia_shanghai() -> DateTime { + let utc_now = Utc::now(); + shift_to_asia_shanghai(utc_now) +} + +/// 将一个类型为`chrono::DateTime`类型的日期时间转换到指定时区的时间实例。 +pub fn shift_tz(datetime: DateTime, zone: i64) -> DateTime { + if zone.is_positive() { + datetime.with_timezone( + &FixedOffset::east_opt(Duration::hours(zone.abs()).num_seconds() as i32).unwrap(), + ) + } else { + datetime.with_timezone( + &FixedOffset::west_opt(Duration::hours(zone.abs()).num_seconds() as i32).unwrap(), + ) + } +} + +/// 将一个类型为`chrono::DateTime`类型的日期时间转换到东八区的时间实例。 +pub fn shift_to_asia_shanghai(datetime: DateTime) -> DateTime { + shift_tz(datetime, 8) +} + +/// 直接给一个原生日期时间附加东八区的时区信息。 +pub fn attach_asia_shanghai(datetime: NaiveDateTime) -> DateTime { + DateTime::::from_local( + datetime, + FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(), + ) +} + +/// 从一个64位时间戳生成东八区的时间实例。这个函数主要用于处理使用`timestamp`方法直接返回的时间戳。 +/// +/// - `timestamp`:64位时间戳。 +pub fn from_utc_timestamp(timestamp: i64) -> DateTime { + let request_time = NaiveDateTime::from_timestamp_micros(timestamp).unwrap(); + DateTime::::from_utc( + request_time, + FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(), + ) +} + +/// 根据指定的日期生成一个时间对象,如果给定的日期不合法将返回空白内容。 +/// +/// - `year`:日期的年份。 +/// - `month`:日期的月份,从`1`开始。 +/// - `day`:日期的天数。 +pub fn date(year: i32, month: u32, day: u32) -> Option { + NaiveDate::from_ymd_opt(year, month, day) +} + +/// 根据指定日期生成一个指定日期最开始时间的时间,精度为毫秒。 +/// +/// - `year`:指定日期的年份。 +/// - `month`:指定日期的月份,从`1`开始。 +/// - `day`:指定日期的天数。 +pub fn date_beginning(year: i32, month: u32, day: u32) -> Option> { + let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(); + NaiveDate::from_ymd_opt(year, month, day) + .map(|d| d.and_hms_micro_opt(0, 0, 0, 0).unwrap()) + .map(|dt| DateTime::::from_local(dt, timezone)) +} + +/// 根据给定的日期,返回其当天最开始的时间,精度为毫秒。 +/// +/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。 +pub fn begin_of_date(date: NaiveDate) -> Option> { + let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(); + date.and_hms_micro_opt(0, 0, 0, 0) + .map(|dt| DateTime::::from_local(dt, timezone)) +} + +/// 根据给定的日期,返回其当天即将结束的时间,精度为毫秒。 +/// +/// - `date`:给定的原始日期,注意:原始日期将被消耗掉。 +pub fn end_of_date(date: NaiveDate) -> Option> { + let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(); + date.and_hms_micro_opt(23, 59, 59, 999_999) + .map(|dt| DateTime::::from_local(dt, timezone)) +} + +/// 根据指定日期生成一个指定日期结束时间的时间,精度为毫秒。 +/// +/// - `year`:指定日期的年份。 +/// - `month`:指定日期的月份,从`1`开始。 +/// - `day`:指定日期的天数。 +pub fn date_ending(year: i32, month: u32, day: u32) -> Option> { + let timezone = FixedOffset::east_opt(Duration::hours(8).num_seconds() as i32).unwrap(); + NaiveDate::from_ymd_opt(year, month, day) + .map(|d| d.and_hms_micro_opt(23, 59, 59, 999_999).unwrap()) + .map(|dt| DateTime::::from_local(dt, timezone)) +} + +/// 返回两个日期之间的月份差值。 +/// +/// - `control`:基准月份。 +/// - `test`:测试月份。 +pub fn difference_month(control: NaiveDate, test: NaiveDate) -> i32 { + let difference_year = test.year() - control.year(); + let difference_month = (test.month() - control.month()) as i32; + difference_year * 12 + difference_month +} + +/// 测试指定月份是否是基准月份的前一个月份。 +/// +/// - `control`:基准月份。 +/// - `test`:待测试的指定月份。 +pub fn is_previous_month(control: NaiveDate, test: NaiveDate) -> bool { + difference_month(control, test) == 1 +} + +/// 测试指定月份是否是基准月份的下一个月份。 +/// +/// - `control`:基准月份。 +/// - `test`:待测试的指定月份。 +pub fn is_next_month(control: NaiveDate, test: NaiveDate) -> bool { + difference_month(control, test) == -1 +} + +/// 生成符合Postgresql中日期类型最小值的日期。 +pub fn min_date() -> NaiveDate { + NaiveDate::from_ymd_opt(1970, 1, 1).unwrap() +} + +/// 生成符合Postgresql中日期类型最小值的日期时间。 +pub fn min_datetime() -> DateTime { + NaiveDate::from_ymd_opt(1970, 1, 1) + .map(begin_of_date) + .flatten() + .unwrap() +} + +/// 生成符合Postgresql中日期类型最大值的日期。 +pub fn max_date() -> NaiveDate { + NaiveDate::from_ymd_opt(2099, 12, 31).unwrap() +} + +/// 生成符合Postgresql中日期类型最大值的日期时间。 +pub fn max_datetime() -> DateTime { + NaiveDate::from_ymd_opt(2099, 12, 31) + .map(end_of_date) + .flatten() + .unwrap() +}