Compare commits
17 Commits
e9c994a755
...
6a5ec31d8e
Author | SHA1 | Date |
---|---|---|
Bradlee Speice | 6a5ec31d8e | |
bors[bot] | 23f50fb62b | |
Bradlee Speice | f1ca602e9f | |
bors[bot] | 899cd88280 | |
Bradlee Speice | a08bb2d9d7 | |
bors[bot] | af6c3238c4 | |
Bradlee Speice | b098f54f8b | |
Bradlee Speice | 61022c323e | |
Bradlee Speice | 4079b3ce2f | |
Bradlee Speice | 3e03b188b4 | |
bspeice | 7147677926 | |
Bradlee Speice | 22b6a321e6 | |
Bradlee Speice | 9edc2a3102 | |
bspeice | 245f746c8c | |
bspeice | 5782a573bc | |
Matthieu Guilbert | e895fbd9f3 | |
Bradlee Speice | 2a2f1e7fbd |
125
.travis.yml
125
.travis.yml
|
@ -1,109 +1,40 @@
|
|||
# Based on the "trust" template v0.1.2
|
||||
# https://github.com/japaric/trust/tree/v0.1.2
|
||||
|
||||
dist: trusty
|
||||
language: rust
|
||||
services: docker
|
||||
sudo: required
|
||||
addons:
|
||||
chrome: stable
|
||||
|
||||
env:
|
||||
global:
|
||||
- CRATE_NAME=dtparse
|
||||
|
||||
matrix:
|
||||
jobs:
|
||||
include:
|
||||
# Android
|
||||
- env: TARGET=aarch64-linux-android DISABLE_TESTS=1
|
||||
- env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
|
||||
- env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
|
||||
- env: TARGET=i686-linux-android DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-linux-android DISABLE_TESTS=1
|
||||
- rust: stable
|
||||
os: linux
|
||||
- rust: 1.28.0
|
||||
os: linux
|
||||
env: DISABLE_TOOLS=true
|
||||
- rust: stable
|
||||
os: osx
|
||||
- rust: stable-msvc
|
||||
os: windows
|
||||
- rust: stable
|
||||
os: windows
|
||||
|
||||
# iOS
|
||||
- env: TARGET=aarch64-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=armv7-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=armv7s-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=i386-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=x86_64-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
cache:
|
||||
- cargo
|
||||
|
||||
# Linux
|
||||
- env: TARGET=aarch64-unknown-linux-gnu
|
||||
- env: TARGET=arm-unknown-linux-gnueabi
|
||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
||||
- env: TARGET=i686-unknown-linux-gnu
|
||||
- env: TARGET=i686-unknown-linux-musl
|
||||
- env: TARGET=mips-unknown-linux-gnu
|
||||
- env: TARGET=mips64-unknown-linux-gnuabi64
|
||||
- env: TARGET=mips64el-unknown-linux-gnuabi64
|
||||
- env: TARGET=mipsel-unknown-linux-gnu
|
||||
- env: TARGET=powerpc-unknown-linux-gnu
|
||||
- env: TARGET=powerpc64-unknown-linux-gnu
|
||||
- env: TARGET=powerpc64le-unknown-linux-gnu
|
||||
- env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
- env: TARGET=x86_64-unknown-linux-musl
|
||||
|
||||
# OSX
|
||||
- env: TARGET=i686-apple-darwin
|
||||
os: osx
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
|
||||
# *BSD
|
||||
- env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
|
||||
|
||||
# Windows
|
||||
- env: TARGET=x86_64-pc-windows-gnu
|
||||
|
||||
# Nightly and Beta
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
rust: nightly
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: beta
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
rust: beta
|
||||
|
||||
# Historical Rust versions
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: 1.28.0
|
||||
|
||||
before_install:
|
||||
- set -e
|
||||
- rustup self update
|
||||
|
||||
install:
|
||||
- sh ci/install.sh
|
||||
- source ~/.cargo/env || true
|
||||
before_script:
|
||||
- rustup show
|
||||
# CMake doesn't like the `sh.exe` provided by Git being in PATH
|
||||
- if [[ "$TRAVIS_OS_NAME" == "windows" ]]; then rm "C:/Program Files/Git/usr/bin/sh.exe"; fi
|
||||
- if [[ "$DISABLE_TOOLS" == "" ]]; then rustup component add clippy; rustup component add rustfmt; fi
|
||||
|
||||
script:
|
||||
- bash ci/script.sh
|
||||
- if [[ "$DISABLE_TOOLS" == "" ]]; then cargo clippy --all && cargo fmt --all -- --check; fi
|
||||
|
||||
after_script: set +e
|
||||
|
||||
cache: cargo
|
||||
before_cache:
|
||||
# Travis can't cache files that are not readable by "others"
|
||||
- chmod -R a+r $HOME/.cargo
|
||||
# For default build, split up compilation and tests so we can track build times
|
||||
- cargo test --no-run
|
||||
- cargo test
|
||||
- cargo test --release --no-run
|
||||
- cargo test --release
|
||||
|
||||
branches:
|
||||
only:
|
||||
# release tags
|
||||
- /^v\d+\.\d+\.\d+.*$/
|
||||
- master
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
- staging
|
||||
- trying
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "dtparse"
|
||||
version = "1.0.3"
|
||||
version = "1.1.0"
|
||||
authors = ["Bradlee Speice <bradlee@speice.io>"]
|
||||
description = "A dateutil-compatible timestamp parser for Rust"
|
||||
repository = "https://github.com/bspeice/dtparse.git"
|
||||
|
@ -10,7 +10,6 @@ license = "Apache-2.0"
|
|||
|
||||
[badges]
|
||||
travis-ci = { repository = "bspeice/dtparse" }
|
||||
appveyor = { repository = "bspeice/dtparse" }
|
||||
maintenance = { status = "passively-maintained" }
|
||||
|
||||
[lib]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# dtparse
|
||||
|
||||
[![travisci](https://travis-ci.org/bspeice/dtparse.svg?branch=master)](https://travis-ci.org/bspeice/dtparse)
|
||||
[![appveyor](https://ci.appveyor.com/api/projects/status/r4de76tg9utfjva1/branch/master?svg=true)](https://ci.appveyor.com/project/bspeice/dtparse/branch/master)
|
||||
[![crates.io](https://img.shields.io/crates/v/dtparse.svg)](https://crates.io/crates/dtparse)
|
||||
[![docs.rs](https://docs.rs/dtparse/badge.svg)](https://docs.rs/dtparse/)
|
||||
|
||||
|
|
121
appveyor.yml
121
appveyor.yml
|
@ -1,121 +0,0 @@
|
|||
# Appveyor configuration template for Rust using rustup for Rust installation
|
||||
# https://github.com/starkat99/appveyor-rust
|
||||
|
||||
## Operating System (VM environment) ##
|
||||
|
||||
# Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets.
|
||||
os: Visual Studio 2017
|
||||
|
||||
## Build Matrix ##
|
||||
|
||||
# This configuration will setup a build for each channel & target combination (12 windows
|
||||
# combinations in all).
|
||||
#
|
||||
# There are 3 channels: stable, beta, and nightly.
|
||||
#
|
||||
# Alternatively, the full version may be specified for the channel to build using that specific
|
||||
# version (e.g. channel: 1.5.0)
|
||||
#
|
||||
# The values for target are the set of windows Rust build targets. Each value is of the form
|
||||
#
|
||||
# ARCH-pc-windows-TOOLCHAIN
|
||||
#
|
||||
# Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker
|
||||
# toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for
|
||||
# a description of the toolchain differences.
|
||||
# See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of
|
||||
# toolchains and host triples.
|
||||
#
|
||||
# Comment out channel/target combos you do not wish to build in CI.
|
||||
#
|
||||
# You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands
|
||||
# and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly
|
||||
# channels to enable unstable features when building for nightly. Or you could add additional
|
||||
# matrix entries to test different combinations of features.
|
||||
environment:
|
||||
matrix:
|
||||
|
||||
### MSVC Toolchains ###
|
||||
|
||||
# Stable 64-bit MSVC
|
||||
- channel: stable
|
||||
target: x86_64-pc-windows-msvc
|
||||
# Stable 32-bit MSVC
|
||||
- channel: stable
|
||||
target: i686-pc-windows-msvc
|
||||
# Beta 64-bit MSVC
|
||||
- channel: beta
|
||||
target: x86_64-pc-windows-msvc
|
||||
# Beta 32-bit MSVC
|
||||
- channel: beta
|
||||
target: i686-pc-windows-msvc
|
||||
# Nightly 64-bit MSVC
|
||||
- channel: nightly
|
||||
target: x86_64-pc-windows-msvc
|
||||
#cargoflags: --features "unstable"
|
||||
# Nightly 32-bit MSVC
|
||||
- channel: nightly
|
||||
target: i686-pc-windows-msvc
|
||||
#cargoflags: --features "unstable"
|
||||
|
||||
### GNU Toolchains ###
|
||||
|
||||
# Stable 64-bit GNU
|
||||
- channel: stable
|
||||
target: x86_64-pc-windows-gnu
|
||||
# Stable 32-bit GNU
|
||||
- channel: stable
|
||||
target: i686-pc-windows-gnu
|
||||
# Beta 64-bit GNU
|
||||
- channel: beta
|
||||
target: x86_64-pc-windows-gnu
|
||||
# Beta 32-bit GNU
|
||||
- channel: beta
|
||||
target: i686-pc-windows-gnu
|
||||
# Nightly 64-bit GNU
|
||||
- channel: nightly
|
||||
target: x86_64-pc-windows-gnu
|
||||
#cargoflags: --features "unstable"
|
||||
# Nightly 32-bit GNU
|
||||
- channel: nightly
|
||||
target: i686-pc-windows-gnu
|
||||
#cargoflags: --features "unstable"
|
||||
|
||||
### Allowed failures ###
|
||||
|
||||
# See Appveyor documentation for specific details. In short, place any channel or targets you wish
|
||||
# to allow build failures on (usually nightly at least is a wise choice). This will prevent a build
|
||||
# or test failure in the matching channels/targets from failing the entire build.
|
||||
matrix:
|
||||
allow_failures:
|
||||
- channel: nightly
|
||||
|
||||
# If you only care about stable channel build failures, uncomment the following line:
|
||||
#- channel: beta
|
||||
|
||||
## Install Script ##
|
||||
|
||||
# This is the most important part of the Appveyor configuration. This installs the version of Rust
|
||||
# specified by the 'channel' and 'target' environment variables from the build matrix. This uses
|
||||
# rustup to install Rust.
|
||||
#
|
||||
# For simple configurations, instead of using the build matrix, you can simply set the
|
||||
# default-toolchain and default-host manually here.
|
||||
install:
|
||||
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||
- rustup-init -yv --default-toolchain %channel% --default-host %target%
|
||||
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
|
||||
- rustc -vV
|
||||
- cargo -vV
|
||||
|
||||
## Build Script ##
|
||||
|
||||
# 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents
|
||||
# the "directory does not contain a project or solution file" error.
|
||||
build: false
|
||||
|
||||
# Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs
|
||||
#directly or perform other testing commands. Rust will automatically be placed in the PATH
|
||||
# environment variable.
|
||||
test_script:
|
||||
- cargo test --verbose %cargoflags%
|
|
@ -0,0 +1,4 @@
|
|||
status = [
|
||||
"continuous-integration/travis-ci/push",
|
||||
]
|
||||
delete_merged_branches = true
|
|
@ -81,7 +81,7 @@ tests = {
|
|||
'Thu Sep 25 10:36:28 BRST 2003', '1996.07.10 AD at 15:08:56 PDT',
|
||||
'Tuesday, April 12, 1952 AD 3:30:42pm PST',
|
||||
'November 5, 1994, 8:15:30 am EST', '1994-11-05T08:15:30-05:00',
|
||||
'1994-11-05T08:15:30Z', '1976-07-04T00:01:02Z',
|
||||
'1994-11-05T08:15:30Z', '1976-07-04T00:01:02Z', '1986-07-05T08:15:30z',
|
||||
'Tue Apr 4 00:22:12 PDT 1995'
|
||||
],
|
||||
'test_fuzzy_tzinfo': [
|
||||
|
|
95
src/lib.rs
95
src/lib.rs
|
@ -1,4 +1,5 @@
|
|||
#![deny(missing_docs)]
|
||||
#![cfg_attr(test, allow(unknown_lints))]
|
||||
#![cfg_attr(test, deny(warnings))]
|
||||
|
||||
//! # dtparse
|
||||
|
@ -90,6 +91,8 @@ use rust_decimal::Decimal;
|
|||
use rust_decimal::Error as DecimalError;
|
||||
use std::cmp::min;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
use std::vec::Vec;
|
||||
|
@ -144,8 +147,18 @@ pub enum ParseError {
|
|||
/// Parser unable to make sense of year/month/day parameters in the time string;
|
||||
/// please report to maintainer as the timestring likely exposes a bug in implementation
|
||||
YearMonthDayError(&'static str),
|
||||
/// Parser unable to find any date/time-related content in the supplied string
|
||||
NoDate,
|
||||
}
|
||||
|
||||
impl fmt::Display for ParseError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseError {}
|
||||
|
||||
type ParseResult<I> = Result<I, ParseError>;
|
||||
|
||||
pub(crate) fn tokenize(parse_string: &str) -> Vec<String> {
|
||||
|
@ -155,16 +168,15 @@ pub(crate) fn tokenize(parse_string: &str) -> Vec<String> {
|
|||
|
||||
/// Utility function for `ParserInfo` that helps in constructing
|
||||
/// the attributes that make up the `ParserInfo` container
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(get_unwrap))] // Recommended suggestion of &vec[0] doesn't compile
|
||||
pub fn parse_info(vec: Vec<Vec<&str>>) -> HashMap<String, usize> {
|
||||
let mut m = HashMap::new();
|
||||
|
||||
if vec.len() == 1 {
|
||||
for (i, val) in vec.get(0).unwrap().into_iter().enumerate() {
|
||||
for (i, val) in vec.get(0).unwrap().iter().enumerate() {
|
||||
m.insert(val.to_lowercase(), i);
|
||||
}
|
||||
} else {
|
||||
for (i, val_vec) in vec.into_iter().enumerate() {
|
||||
for (i, val_vec) in vec.iter().enumerate() {
|
||||
for val in val_vec {
|
||||
m.insert(val.to_lowercase(), i);
|
||||
}
|
||||
|
@ -337,7 +349,9 @@ impl ParserInfo {
|
|||
res.year = Some(self.convertyear(y, res.century_specified))
|
||||
};
|
||||
|
||||
if res.tzoffset == Some(0) && res.tzname.is_none() || res.tzname == Some("Z".to_owned()) {
|
||||
if (res.tzoffset == Some(0) && res.tzname.is_none())
|
||||
|| (res.tzname == Some("Z".to_owned()) || res.tzname == Some("z".to_owned()))
|
||||
{
|
||||
res.tzname = Some("UTC".to_owned());
|
||||
res.tzoffset = Some(0);
|
||||
} else if res.tzoffset != Some(0)
|
||||
|
@ -506,7 +520,7 @@ impl YMD {
|
|||
))
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(needless_return))]
|
||||
#[allow(clippy::needless_return)]
|
||||
fn resolve_ymd(
|
||||
&mut self,
|
||||
yearfirst: bool,
|
||||
|
@ -612,6 +626,31 @@ struct ParsingResult {
|
|||
any_unused_tokens: Vec<String>,
|
||||
}
|
||||
|
||||
macro_rules! option_len {
|
||||
($o:expr) => {{
|
||||
if $o.is_some() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
impl ParsingResult {
|
||||
fn len(&self) -> usize {
|
||||
option_len!(self.year)
|
||||
+ option_len!(self.month)
|
||||
+ option_len!(self.day)
|
||||
+ option_len!(self.weekday)
|
||||
+ option_len!(self.hour)
|
||||
+ option_len!(self.minute)
|
||||
+ option_len!(self.second)
|
||||
+ option_len!(self.microsecond)
|
||||
+ option_len!(self.tzname)
|
||||
+ option_len!(self.ampm)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parser is responsible for doing the actual work of understanding a time string.
|
||||
/// The root level `parse` function is responsible for constructing a default `Parser`
|
||||
/// and triggering its behavior.
|
||||
|
@ -660,7 +699,7 @@ impl Parser {
|
|||
/// timezone name support (i.e. "EST", "BRST") is not available by default
|
||||
/// at the moment, they must be added through `tzinfos` at the moment in
|
||||
/// order to be resolved.
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] // Need to release a 2.0 for changing public API
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn parse(
|
||||
&self,
|
||||
timestr: &str,
|
||||
|
@ -679,6 +718,10 @@ impl Parser {
|
|||
let (res, tokens) =
|
||||
self.parse_with_tokens(timestr, dayfirst, yearfirst, fuzzy, fuzzy_with_tokens)?;
|
||||
|
||||
if res.len() == 0 {
|
||||
return Err(ParseError::NoDate);
|
||||
}
|
||||
|
||||
let naive = self.build_naive(&res, &default_ts)?;
|
||||
|
||||
if !ignoretz {
|
||||
|
@ -689,7 +732,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity))] // Imitating Python API is priority
|
||||
#[allow(clippy::cognitive_complexity)] // Imitating Python API is priority
|
||||
fn parse_with_tokens(
|
||||
&self,
|
||||
timestr: &str,
|
||||
|
@ -736,11 +779,11 @@ impl Parser {
|
|||
// Jan-01[-99]
|
||||
let sep = &l[i + 1];
|
||||
// TODO: This seems like a very unsafe unwrap
|
||||
ymd.append(l[i + 2].parse::<i32>().unwrap(), &l[i + 2], None)?;
|
||||
ymd.append(l[i + 2].parse::<i32>()?, &l[i + 2], None)?;
|
||||
|
||||
if i + 3 < len_l && &l[i + 3] == sep {
|
||||
// Jan-01-99
|
||||
ymd.append(l[i + 4].parse::<i32>().unwrap(), &l[i + 4], None)?;
|
||||
ymd.append(l[i + 4].parse::<i32>()?, &l[i + 4], None)?;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
|
@ -803,17 +846,17 @@ impl Parser {
|
|||
// TODO: check that l[i + 1] is integer?
|
||||
if len_li == 4 {
|
||||
// -0300
|
||||
hour_offset = Some(l[i + 1][..2].parse::<i32>().unwrap());
|
||||
min_offset = Some(l[i + 1][2..4].parse::<i32>().unwrap());
|
||||
hour_offset = Some(l[i + 1][..2].parse::<i32>()?);
|
||||
min_offset = Some(l[i + 1][2..4].parse::<i32>()?);
|
||||
} else if i + 2 < len_l && l[i + 2] == ":" {
|
||||
// -03:00
|
||||
hour_offset = Some(l[i + 1].parse::<i32>().unwrap());
|
||||
min_offset = Some(l[i + 3].parse::<i32>().unwrap());
|
||||
hour_offset = Some(l[i + 1].parse::<i32>()?);
|
||||
min_offset = Some(l[i + 3].parse::<i32>()?);
|
||||
i += 2;
|
||||
} else if len_li <= 2 {
|
||||
// -[0]3
|
||||
let range_len = min(l[i + 1].len(), 2);
|
||||
hour_offset = Some(l[i + 1][..range_len].parse::<i32>().unwrap());
|
||||
hour_offset = Some(l[i + 1][..range_len].parse::<i32>()?);
|
||||
min_offset = Some(0);
|
||||
}
|
||||
|
||||
|
@ -875,9 +918,10 @@ impl Parser {
|
|||
&& tzname.is_none()
|
||||
&& tzoffset.is_none()
|
||||
&& token.len() <= 5
|
||||
&& all_ascii_upper
|
||||
&& (all_ascii_upper || self.info.utczone.contains_key(token))
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_unwrap)]
|
||||
fn ampm_valid(&self, hour: Option<i32>, ampm: Option<bool>, fuzzy: bool) -> ParseResult<bool> {
|
||||
let mut val_is_ampm = !(fuzzy && ampm.is_some());
|
||||
|
||||
|
@ -981,6 +1025,7 @@ impl Parser {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_unwrap)]
|
||||
fn parse_numeric_token(
|
||||
&self,
|
||||
tokens: &[String],
|
||||
|
@ -1017,9 +1062,9 @@ impl Parser {
|
|||
let s = &tokens[idx];
|
||||
|
||||
if ymd.len() == 0 && tokens[idx].find('.') == None {
|
||||
ymd.append(s[0..2].parse::<i32>().unwrap(), &s[0..2], None)?;
|
||||
ymd.append(s[2..4].parse::<i32>().unwrap(), &s[2..4], None)?;
|
||||
ymd.append(s[4..6].parse::<i32>().unwrap(), &s[4..6], None)?;
|
||||
ymd.append(s[0..2].parse::<i32>()?, &s[0..2], None)?;
|
||||
ymd.append(s[2..4].parse::<i32>()?, &s[2..4], None)?;
|
||||
ymd.append(s[4..6].parse::<i32>()?, &s[4..6], None)?;
|
||||
} else {
|
||||
// 19990101T235959[.59]
|
||||
res.hour = s[0..2].parse::<i32>().ok();
|
||||
|
@ -1032,13 +1077,9 @@ impl Parser {
|
|||
} else if vec![8, 12, 14].contains(&len_li) {
|
||||
// YYMMDD
|
||||
let s = &tokens[idx];
|
||||
ymd.append(
|
||||
s[..4].parse::<i32>().unwrap(),
|
||||
&s[..4],
|
||||
Some(YMDLabel::Year),
|
||||
)?;
|
||||
ymd.append(s[4..6].parse::<i32>().unwrap(), &s[4..6], None)?;
|
||||
ymd.append(s[6..8].parse::<i32>().unwrap(), &s[6..8], None)?;
|
||||
ymd.append(s[..4].parse::<i32>()?, &s[..4], Some(YMDLabel::Year))?;
|
||||
ymd.append(s[4..6].parse::<i32>()?, &s[4..6], None)?;
|
||||
ymd.append(s[6..8].parse::<i32>()?, &s[6..8], None)?;
|
||||
|
||||
if len_li > 8 {
|
||||
res.hour = Some(s[8..10].parse::<i32>()?);
|
||||
|
@ -1080,7 +1121,7 @@ impl Parser {
|
|||
{
|
||||
// TODO: There's got to be a better way of handling the condition above
|
||||
let sep = &tokens[idx + 1];
|
||||
ymd.append(value_repr.parse::<i32>().unwrap(), &value_repr, None)?;
|
||||
ymd.append(value_repr.parse::<i32>()?, &value_repr, None)?;
|
||||
|
||||
if idx + 2 < len_l && !info.jump_index(&tokens[idx + 2]) {
|
||||
if let Ok(val) = tokens[idx + 2].parse::<i32>() {
|
||||
|
@ -1202,6 +1243,7 @@ impl Parser {
|
|||
hms_idx
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_unwrap)]
|
||||
fn parse_hms(
|
||||
&self,
|
||||
idx: usize,
|
||||
|
@ -1261,7 +1303,6 @@ impl Parser {
|
|||
(minute, second)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] // Need Vec type because of mutability in the function that calls us
|
||||
fn recombine_skipped(&self, skipped_idxs: Vec<usize>, tokens: Vec<String>) -> Vec<String> {
|
||||
let mut skipped_tokens: Vec<String> = vec![];
|
||||
|
||||
|
|
|
@ -17,26 +17,34 @@ fn test_fuzz() {
|
|||
parse("2..\x00\x000d\x00+\x010d\x01\x00\x00\x00+"),
|
||||
Err(ParseError::UnrecognizedFormat)
|
||||
);
|
||||
// OverflowError: Python int too large to convert to C long
|
||||
// assert_eq!(parse("8888884444444888444444444881"), Err(ParseError::AmPmWithoutHour));
|
||||
|
||||
let default = NaiveDate::from_ymd(2016, 6, 29).and_hms(0, 0, 0);
|
||||
let p = Parser::default();
|
||||
let res = p
|
||||
.parse(
|
||||
"\x0D\x31",
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
Some(&default),
|
||||
false,
|
||||
&HashMap::new(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(res.0, default);
|
||||
let res = p.parse(
|
||||
"\x0D\x31",
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
Some(&default),
|
||||
false,
|
||||
&HashMap::new(),
|
||||
);
|
||||
assert_eq!(res, Err(ParseError::NoDate));
|
||||
|
||||
assert_eq!(
|
||||
parse("\x2D\x2D\x32\x31\x38\x6D"),
|
||||
Err(ParseError::ImpossibleTimestamp("Invalid minute"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn large_int() {
|
||||
let parse_result = parse("1412409095009.jpg");
|
||||
assert!(parse_result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_string() {
|
||||
assert_eq!(parse(""), Err(ParseError::NoDate))
|
||||
}
|
||||
|
|
|
@ -3348,6 +3348,33 @@ fn test_parse_ignoretz6() {
|
|||
|
||||
#[test]
|
||||
fn test_parse_ignoretz7() {
|
||||
let info = ParserInfo::default();
|
||||
let pdt = PyDateTime {
|
||||
year: 1986,
|
||||
month: 7,
|
||||
day: 5,
|
||||
hour: 8,
|
||||
minute: 15,
|
||||
second: 30,
|
||||
micros: 0,
|
||||
tzo: None,
|
||||
};
|
||||
parse_and_assert(
|
||||
pdt,
|
||||
info,
|
||||
"1986-07-05T08:15:30z",
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
None,
|
||||
true,
|
||||
&HashMap::new(),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ignoretz8() {
|
||||
let info = ParserInfo::default();
|
||||
let pdt = PyDateTime {
|
||||
year: 1995,
|
||||
|
|
Loading…
Reference in New Issue