You've already forked parse_datetime
mirror of
https://github.com/uutils/parse_datetime.git
synced 2026-06-10 16:13:15 -07:00
Merge pull request #168 from yuankunzhang/nanoseconds
feat: support nanoseconds
This commit is contained in:
+18
-2
@@ -190,6 +190,7 @@ pub fn parse(input: &mut &str) -> ModalResult<Vec<Item>> {
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn new_date(
|
||||
year: i32,
|
||||
month: u32,
|
||||
@@ -197,10 +198,11 @@ fn new_date(
|
||||
hour: u32,
|
||||
minute: u32,
|
||||
second: u32,
|
||||
nano: u32,
|
||||
offset: FixedOffset,
|
||||
) -> Option<DateTime<FixedOffset>> {
|
||||
let newdate = NaiveDate::from_ymd_opt(year, month, day)
|
||||
.and_then(|naive| naive.and_hms_opt(hour, minute, second))?;
|
||||
.and_then(|naive| naive.and_hms_nano_opt(hour, minute, second, nano))?;
|
||||
|
||||
Some(DateTime::<FixedOffset>::from_local(newdate, offset))
|
||||
}
|
||||
@@ -220,7 +222,8 @@ fn with_timezone_restore(
|
||||
.with_year(copy.year())?
|
||||
.with_hour(copy.hour())?
|
||||
.with_minute(copy.minute())?
|
||||
.with_second(copy.second())?;
|
||||
.with_second(copy.second())?
|
||||
.with_nanosecond(copy.nanosecond())?;
|
||||
Some(x)
|
||||
}
|
||||
|
||||
@@ -274,6 +277,7 @@ fn at_date_inner(date: Vec<Item>, at: DateTime<FixedOffset>) -> Option<DateTime<
|
||||
d.hour(),
|
||||
d.minute(),
|
||||
d.second(),
|
||||
d.nanosecond(),
|
||||
*d.offset(),
|
||||
)?;
|
||||
}
|
||||
@@ -299,6 +303,7 @@ fn at_date_inner(date: Vec<Item>, at: DateTime<FixedOffset>) -> Option<DateTime<
|
||||
hour,
|
||||
minute,
|
||||
second as u32,
|
||||
(second.fract() * 10f64.powi(9)).round() as u32,
|
||||
offset,
|
||||
)?;
|
||||
}
|
||||
@@ -320,6 +325,7 @@ fn at_date_inner(date: Vec<Item>, at: DateTime<FixedOffset>) -> Option<DateTime<
|
||||
hour,
|
||||
minute,
|
||||
second as u32,
|
||||
(second.fract() * 10f64.powi(9)).round() as u32,
|
||||
offset,
|
||||
)?;
|
||||
}
|
||||
@@ -495,6 +501,16 @@ mod tests {
|
||||
test_eq_fmt("%Y-%m-%d %H:%M:%S %:z", "Jul 17 06:14:49 2024 GMT"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"2024-07-17 06:14:49.567 +00:00",
|
||||
test_eq_fmt("%Y-%m-%d %H:%M:%S%.f %:z", "Jul 17 06:14:49.567 2024 GMT"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"2024-07-17 06:14:49.567 +00:00",
|
||||
test_eq_fmt("%Y-%m-%d %H:%M:%S%.f %:z", "Jul 17 06:14:49,567 2024 GMT"),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
"2024-07-17 06:14:49 -03:00",
|
||||
test_eq_fmt("%Y-%m-%d %H:%M:%S %:z", "Jul 17 06:14:49 2024 BRT"),
|
||||
|
||||
@@ -120,9 +120,13 @@ pub(super) fn float<'a, E>(input: &mut &'a str) -> winnow::Result<f64, E>
|
||||
where
|
||||
E: ParserError<&'a str>,
|
||||
{
|
||||
(opt(one_of(['+', '-'])), digit1, opt(preceded('.', digit1)))
|
||||
(
|
||||
opt(one_of(['+', '-'])),
|
||||
digit1,
|
||||
opt(preceded(one_of(['.', ',']), digit1)),
|
||||
)
|
||||
.void()
|
||||
.take()
|
||||
.verify_map(|s: &str| s.parse().ok())
|
||||
.verify_map(|s: &str| s.replace(",", ".").parse().ok())
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
+10
-3
@@ -41,7 +41,7 @@ use std::fmt::Display;
|
||||
|
||||
use chrono::FixedOffset;
|
||||
use winnow::{
|
||||
ascii::{digit1, float},
|
||||
ascii::digit1,
|
||||
combinator::{alt, opt, peek, preceded},
|
||||
error::{ContextError, ErrMode, StrContext, StrContextValue},
|
||||
seq,
|
||||
@@ -53,7 +53,7 @@ use winnow::{
|
||||
use crate::ParseDateTimeError;
|
||||
|
||||
use super::{
|
||||
primitive::{dec_uint, s},
|
||||
primitive::{dec_uint, float, s},
|
||||
relative,
|
||||
};
|
||||
|
||||
@@ -226,7 +226,14 @@ fn minute(input: &mut &str) -> ModalResult<u32> {
|
||||
|
||||
/// Parse a number of seconds (preceded by whitespace)
|
||||
fn second(input: &mut &str) -> ModalResult<f64> {
|
||||
s(float).verify(|x| *x < 60.0).parse_next(input)
|
||||
s(float)
|
||||
.verify(|x| *x < 60.0)
|
||||
.map(|x| {
|
||||
// Truncates the fractional part of seconds to 9 digits.
|
||||
let factor = 10f64.powi(9);
|
||||
(x * factor).trunc() / factor
|
||||
})
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
pub(crate) fn timezone(input: &mut &str) -> ModalResult<Offset> {
|
||||
|
||||
@@ -34,12 +34,10 @@ pub fn check_time(input: &str, expected: &str, format: &str, base: Option<DateTi
|
||||
#[case::full_time_with_spaces("12 : 34 : 56", "12:34:56.000000000")]
|
||||
#[case::full_time_midnight("00:00:00", "00:00:00.000000000")]
|
||||
#[case::full_time_almost_midnight("23:59:59", "23:59:59.000000000")]
|
||||
/* TODO: https://github.com/uutils/parse_datetime/issues/165
|
||||
#[case::full_time_decimal_seconds("12:34:56.666", "12:34:56.666000000")]
|
||||
#[case::full_time_decimal_seconds("12:34:56.999999999", "12:34:56.999999999")]
|
||||
#[case::full_time_decimal_seconds("12:34:56.9999999999", "12:34:56.999999999")]
|
||||
#[case::full_time_decimal_seconds_after_comma("12:34:56,666", "12:34:56.666000000")]
|
||||
*/
|
||||
#[case::without_seconds("12:34", "12:34:00.000000000")]
|
||||
fn test_time_24h_format(#[case] input: &str, #[case] expected: &str) {
|
||||
check_time(input, expected, "%H:%M:%S%.9f", None);
|
||||
@@ -54,10 +52,8 @@ fn test_time_24h_format(#[case] input: &str, #[case] expected: &str) {
|
||||
#[case::full_time_capital("12:34:56pm", "12:34:56.000000000")]
|
||||
#[case::full_time_midnight("00:00:00", "00:00:00.000000000")]
|
||||
#[case::full_time_almost_midnight("23:59:59", "23:59:59.000000000")]
|
||||
/* TODO: https://github.com/uutils/parse_datetime/issues/165
|
||||
#[case::full_time_decimal_seconds("12:34:56.666pm", "12:34:56.666000000")]
|
||||
#[case::full_time_decimal_seconds_after_comma("12:34:56,666pm", "12:34:56.666000000")]
|
||||
*/
|
||||
#[case::without_seconds("12:34pm", "12:34:00.000000000")]
|
||||
fn test_time_12h_format(#[case] input: &str, #[case] expected: &str) {
|
||||
check_time(input, expected, "%H:%M:%S%.9f", None);
|
||||
|
||||
Reference in New Issue
Block a user