Skip to content

Commit

Permalink
fix parse bug
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuxiujia committed Aug 13, 2022
1 parent 33fc051 commit 6baad96
Show file tree
Hide file tree
Showing 13 changed files with 212 additions and 135 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fastdate"
version = "0.1.21"
version = "0.1.22"
edition = "2021"
description = "Rust fast date carte"
readme = "Readme.md"
Expand Down
5 changes: 3 additions & 2 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ fn bench_date_parse_z(b: &mut Bencher) {
fn bench_date_parse_parse(b: &mut Bencher) {
b.iter(|| {
std::hint::black_box({
DateTime::parse("YYYY-MM-DD hh:mm:ss.000000","2022-12-13 11:12:14.123456").expect("TODO: panic message");
DateTime::parse("YYYY-MM-DD hh:mm:ss.000000", "2022-12-13 11:12:14.123456")
.expect("TODO: panic message");
});
});
}
Expand Down Expand Up @@ -107,4 +108,4 @@ fn bench_timestamp(b: &mut Bencher) {
let _ = now.unix_timestamp();
});
});
}
}
45 changes: 15 additions & 30 deletions src/date.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{get_digit_unchecked, DateTime};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{DateTime, get_digit_unchecked};

use crate::error::Error as Error;
use crate::error::Error;

/// Log timestamp type.
///
Expand Down Expand Up @@ -39,7 +39,7 @@ impl Date {

match bytes.get_unchecked(4) {
b'-' => (),
_ => ()//return Err(Error::E("InvalidCharDateSep".to_string())),
_ => (), //return Err(Error::E("InvalidCharDateSep".to_string())),
}

let m1 = get_digit_unchecked!(bytes, 5, "InvalidCharMonth");
Expand All @@ -48,7 +48,7 @@ impl Date {

match bytes.get_unchecked(7) {
b'-' => (),
_ => ()//return Err(Error::E("InvalidCharDateSep".to_string())),
_ => (), //return Err(Error::E("InvalidCharDateSep".to_string())),
}

let d1 = get_digit_unchecked!(bytes, 8, "InvalidCharDay");
Expand Down Expand Up @@ -128,15 +128,22 @@ impl Display for Date {
}

impl Serialize for Date {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de> Deserialize<'de> for Date {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
Date::from_str(&String::deserialize(deserializer)?).map_err(|e| D::Error::custom(e.to_string()))
Date::from_str(&String::deserialize(deserializer)?)
.map_err(|e| D::Error::custom(e.to_string()))
}
}

Expand All @@ -149,25 +156,3 @@ impl From<DateTime> for Date {
}
}
}


#[cfg(test)]
mod tests {
use std::str::FromStr;
use crate::{Date, DateTime};

#[test]
fn test_date() {
let d = Date::from_str("2022-12-13 11:12:13.123456").unwrap();
println!("{}", d);
assert_eq!("2022-12-13".to_string(), d.to_string());
}

#[test]
fn test_ser() {
let d = DateTime::from_str("2022-12-13 11:12:13").unwrap();
println!("{}", d);
let v=serde_json::to_string(&d).unwrap();

}
}
62 changes: 43 additions & 19 deletions src/datetime.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use crate::error::Error;
use crate::sys::Timespec;
use crate::{Date, Time};
use once_cell::sync::Lazy;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::cmp;
use std::fmt::{self, Display, Formatter};
use std::ops::{Add, Deref, Sub};
use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use once_cell::sync::Lazy;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{Date, Time};
use crate::error::Error as Error;
use crate::sys::Timespec;

/// Obtain the offset of Utc time and Local time in seconds, using Lazy only once to improve performance
pub static GLOBAL_OFFSET: Lazy<i32> = Lazy::new(|| Timespec::now().local().tm_utcoff);
Expand Down Expand Up @@ -288,6 +288,15 @@ impl Sub<&Duration> for DateTime {
}
}

impl Sub<DateTime> for DateTime {
type Output = Duration;

fn sub(self, rhs: DateTime) -> Self::Output {
let nano = self.unix_timestamp_nano() - rhs.unix_timestamp_nano();
Duration::from_nanos(nano as u64)
}
}

impl From<SystemTime> for DateTime {
fn from(v: SystemTime) -> DateTime {
let dur = v
Expand Down Expand Up @@ -394,11 +403,9 @@ impl From<DateTime> for SystemTime {
v.sec as u64 + v.min as u64 * 60 + v.hour as u64 * 3600 + days * 86400,
);
if v.micro > 0 {
UNIX_EPOCH
+ sec + Duration::from_micros(v.micro as u64)
UNIX_EPOCH + sec + Duration::from_micros(v.micro as u64)
} else {
UNIX_EPOCH
+ sec - Duration::from_micros(v.micro as u64)
UNIX_EPOCH + sec - Duration::from_micros(v.micro as u64)
}
}
}
Expand Down Expand Up @@ -465,21 +472,33 @@ impl FromStr for DateTime {
let remin_bytes = remin_str.as_bytes();
if remin_str.len() == 3 {
if remin_bytes[0] == b'+' || remin_bytes[0] == b'Z' {
offset_sec += ((remin_bytes[1] - b'0') as i32 * 10 + (remin_bytes[2] - b'0') as i32) * 3600;
offset_sec += ((remin_bytes[1] - b'0') as i32 * 10
+ (remin_bytes[2] - b'0') as i32)
* 3600;
} else if remin_bytes[0] == b'-' {
offset_sec -= ((remin_bytes[1] - b'0') as i32 * 10 + (remin_bytes[2] - b'0') as i32) * 3600;
offset_sec -= ((remin_bytes[1] - b'0') as i32 * 10
+ (remin_bytes[2] - b'0') as i32)
* 3600;
}
} else if remin_str.len() == 6 {
if remin_bytes[0] == b'+' || remin_bytes[0] == b'Z' {
//hour
offset_sec += ((remin_bytes[1] - b'0') as i32 * 10 + (remin_bytes[2] - b'0') as i32) * 3600;
offset_sec += ((remin_bytes[1] - b'0') as i32 * 10
+ (remin_bytes[2] - b'0') as i32)
* 3600;
//min
offset_sec += ((remin_bytes[4] - b'0') as i32 * 10 + (remin_bytes[5] - b'0') as i32) * 60;
offset_sec += ((remin_bytes[4] - b'0') as i32 * 10
+ (remin_bytes[5] - b'0') as i32)
* 60;
} else if remin_bytes[0] == b'-' {
//hour
offset_sec -= ((remin_bytes[1] - b'0') as i32 * 10 + (remin_bytes[2] - b'0') as i32) * 3600;
offset_sec -= ((remin_bytes[1] - b'0') as i32 * 10
+ (remin_bytes[2] - b'0') as i32)
* 3600;
//min
offset_sec -= ((remin_bytes[4] - b'0') as i32 * 10 + (remin_bytes[5] - b'0') as i32) * 60;
offset_sec -= ((remin_bytes[4] - b'0') as i32 * 10
+ (remin_bytes[5] - b'0') as i32)
* 60;
}
}
}
Expand All @@ -489,7 +508,7 @@ impl FromStr for DateTime {
date = date.sub(Duration::from_secs(offset_sec.abs() as u64));
}
if bytes[bytes.len() - 1] == 'Z' as u8 {
date.set_offset(crate::offset_sec());//append offset
date.set_offset(crate::offset_sec()); //append offset
}
}
Ok(date)
Expand Down Expand Up @@ -553,15 +572,20 @@ fn is_leap_year(y: u16) -> bool {
y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
}


impl Serialize for DateTime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}

impl<'de> Deserialize<'de> for DateTime {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let s = String::deserialize(deserializer)?;
DateTime::from_str(&s).map_err(|e| D::Error::custom(e))
Expand Down
2 changes: 0 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ impl From<std::string::String> for Error {
}
}


impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
return match self {
Expand All @@ -42,4 +41,3 @@ impl Default for Error {
Error::E(String::new())
}
}

11 changes: 6 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
pub mod sys;
#![allow(unused_assignments)]

pub mod error;
pub mod sys;

mod date;
mod time;
mod datetime;
mod time;
pub use date::*;
pub use time::*;
pub use datetime::*;

pub use time::*;

// get a character from the bytes as as a decimal
macro_rules! get_digit {
Expand All @@ -28,4 +29,4 @@ macro_rules! get_digit_unchecked {
}
};
}
pub(crate) use get_digit_unchecked;
pub(crate) use get_digit_unchecked;
17 changes: 12 additions & 5 deletions src/sys/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ pub struct Timespec {
impl Timespec {
/// Constructs a timespec representing the current time in UTC.
pub fn now() -> Timespec {
let st =
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
Timespec { sec: st.as_secs() as i64, nsec: st.subsec_nanos() as i32 }
let st = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time before Unix epoch");
Timespec {
sec: st.as_secs() as i64,
nsec: st.subsec_nanos() as i32,
}
}

/// Converts this timespec into the system's local time.
Expand Down Expand Up @@ -104,6 +108,9 @@ impl Tm {
0 => inner::utc_tm_to_time(self),
_ => inner::local_tm_to_time(self),
};
Timespec { sec: sec, nsec: self.tm_nsec }
Timespec {
sec: sec,
nsec: self.tm_nsec,
}
}
}
}
12 changes: 6 additions & 6 deletions src/sys/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
panic!("localtime_r failed: {}", io::Error::last_os_error());
}
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
let gmtoff = {
let gmtoff = {
tzset();
// < 0 means we don't know; assume we're not in DST.
if out.tm_isdst == 0 {
Expand All @@ -98,17 +98,17 @@ pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
}
};
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
let gmtoff = out.tm_gmtoff;
let gmtoff = out.tm_gmtoff;
tm_to_rust_tm(&out, gmtoff as i32, tm);
}
}

pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 {
#[cfg(not(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "nacl",
target_os = "solaris",
target_os = "illumos"
all(target_os = "android", target_pointer_width = "32"),
target_os = "nacl",
target_os = "solaris",
target_os = "illumos"
)))]
use libc::timegm;
#[cfg(all(target_os = "android", target_pointer_width = "32"))]
Expand Down
23 changes: 19 additions & 4 deletions src/sys/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC;

fn time_to_file_time(sec: i64) -> FILETIME {
let t = ((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH) as u64;
FILETIME { dwLowDateTime: t as DWORD, dwHighDateTime: (t >> 32) as DWORD }
FILETIME {
dwLowDateTime: t as DWORD,
dwHighDateTime: (t >> 32) as DWORD,
}
}

fn file_time_as_u64(ft: &FILETIME) -> u64 {
Expand Down Expand Up @@ -94,7 +97,11 @@ pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
let mut utc = mem::zeroed();
let mut local = mem::zeroed();
call!(FileTimeToSystemTime(&ft, &mut utc));
call!(SystemTimeToTzSpecificLocalTime(0 as *const _, &mut utc, &mut local));
call!(SystemTimeToTzSpecificLocalTime(
0 as *const _,
&mut utc,
&mut local
));
system_time_to_tm(&local, tm);

let local = system_time_to_file_time(&local);
Expand All @@ -106,7 +113,11 @@ pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
// SystemTimeToTzSpecificLocalTime already applied the biases so
// check if it non standard
tm.tm_utcoff = (local_sec - sec) as i32;
tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 0 } else { 1 };
tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) {
0
} else {
1
};
}
}

Expand All @@ -124,7 +135,11 @@ pub fn local_tm_to_time(tm: &Tm) -> i64 {
let mut ft = mem::zeroed();
let mut utc = mem::zeroed();
let mut sys_time = tm_to_system_time(tm);
call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, &mut sys_time, &mut utc));
call!(TzSpecificLocalTimeToSystemTime(
0 as *mut _,
&mut sys_time,
&mut utc
));
call!(SystemTimeToFileTime(&utc, &mut ft));
file_time_to_unix_seconds(&ft)
}
Expand Down
Loading

0 comments on commit 6baad96

Please sign in to comment.