@@ -32,14 +32,26 @@ use super::primitive::{dec_uint, s};
3232/// - Negative timestamps are represented by a negative `second` value and a
3333/// positive `nanosecond` value.
3434#[ derive( Debug , PartialEq ) ]
35- pub ( crate ) struct Timestamp {
36- pub ( crate ) second : i64 ,
37- pub ( crate ) nanosecond : u32 ,
35+ pub ( super ) struct Timestamp {
36+ second : i64 ,
37+ nanosecond : u32 ,
38+ }
39+
40+ impl TryFrom < Timestamp > for jiff:: Timestamp {
41+ type Error = & ' static str ;
42+
43+ fn try_from ( ts : Timestamp ) -> Result < Self , Self :: Error > {
44+ jiff:: Timestamp :: new (
45+ ts. second ,
46+ i32:: try_from ( ts. nanosecond ) . map_err ( |_| "nanosecond value exceeds i32::MAX" ) ?,
47+ )
48+ . map_err ( |_| "timestamp value is out of valid range" )
49+ }
3850}
3951
4052/// Parse a timestamp in the form of `@1234567890` or `@-1234567890.12345` or
4153/// `@1234567890,12345`.
42- pub ( crate ) fn parse ( input : & mut & str ) -> ModalResult < Timestamp > {
54+ pub ( super ) fn parse ( input : & mut & str ) -> ModalResult < Timestamp > {
4355 ( s ( "@" ) , opt ( s ( one_of ( [ '-' , '+' ] ) ) ) , sec_and_nsec)
4456 . verify_map ( |( _, sign, ( sec, nsec) ) | {
4557 let sec = i64:: try_from ( sec) . ok ( ) ?;
@@ -78,84 +90,46 @@ pub(super) fn sec_and_nsec(input: &mut &str) -> ModalResult<(u64, u32)> {
7890mod tests {
7991 use super :: * ;
8092
81- #[ test]
82- fn sec_and_nsec_test ( ) {
83- let mut input = "1234567890" ;
84- assert_eq ! ( sec_and_nsec( & mut input) . unwrap( ) , ( 1234567890 , 0 ) ) ;
85-
86- let mut input = "1234567890.12345" ;
87- assert_eq ! ( sec_and_nsec( & mut input) . unwrap( ) , ( 1234567890 , 123450000 ) ) ;
88-
89- let mut input = "1234567890,12345" ;
90- assert_eq ! ( sec_and_nsec( & mut input) . unwrap( ) , ( 1234567890 , 123450000 ) ) ;
93+ fn ts ( second : i64 , nanosecond : u32 ) -> Timestamp {
94+ Timestamp { second, nanosecond }
95+ }
9196
92- let mut input = "1234567890.1234567890123" ;
93- assert_eq ! ( sec_and_nsec( & mut input) . unwrap( ) , ( 1234567890 , 123456789 ) ) ;
97+ #[ test]
98+ fn parse_sec_and_nsec ( ) {
99+ for ( input, expected) in [
100+ ( "1234567890" , ( 1234567890 , 0 ) ) , // only seconds
101+ ( "1234567890.12345" , ( 1234567890 , 123450000 ) ) , // seconds and nanoseconds, '.' as floating point
102+ ( "1234567890,12345" , ( 1234567890 , 123450000 ) ) , // seconds and nanoseconds, ',' as floating point
103+ ( "1234567890.1234567890123" , ( 1234567890 , 123456789 ) ) , // nanoseconds with more than 9 digits, truncated
104+ ] {
105+ let mut s = input;
106+ assert_eq ! ( sec_and_nsec( & mut s) . unwrap( ) , expected, "{input}" ) ;
107+ }
108+
109+ for input in [
110+ ".1234567890" , // invalid: no leading seconds
111+ "-1234567890" , // invalid: negative input not allowed
112+ ] {
113+ let mut s = input;
114+ assert ! ( sec_and_nsec( & mut s) . is_err( ) , "{input}" ) ;
115+ }
94116 }
95117
96118 #[ test]
97119 fn timestamp ( ) {
98- let mut input = "@1234567890" ;
99- assert_eq ! (
100- parse( & mut input) . unwrap( ) ,
101- Timestamp {
102- second: 1234567890 ,
103- nanosecond: 0 ,
104- }
105- ) ;
106-
107- let mut input = "@ 1234567890" ;
108- assert_eq ! (
109- parse( & mut input) . unwrap( ) ,
110- Timestamp {
111- second: 1234567890 ,
112- nanosecond: 0 ,
113- }
114- ) ;
115-
116- let mut input = "@ -1234567890" ;
117- assert_eq ! (
118- parse( & mut input) . unwrap( ) ,
119- Timestamp {
120- second: -1234567890 ,
121- nanosecond: 0 ,
122- }
123- ) ;
124-
125- let mut input = "@ - 1234567890" ;
126- assert_eq ! (
127- parse( & mut input) . unwrap( ) ,
128- Timestamp {
129- second: -1234567890 ,
130- nanosecond: 0 ,
131- }
132- ) ;
133-
134- let mut input = "@1234567890.12345" ;
135- assert_eq ! (
136- parse( & mut input) . unwrap( ) ,
137- Timestamp {
138- second: 1234567890 ,
139- nanosecond: 123450000 ,
140- }
141- ) ;
142-
143- let mut input = "@1234567890,12345" ;
144- assert_eq ! (
145- parse( & mut input) . unwrap( ) ,
146- Timestamp {
147- second: 1234567890 ,
148- nanosecond: 123450000 ,
149- }
150- ) ;
151-
152- let mut input = "@-1234567890.12345" ;
153- assert_eq ! (
154- parse( & mut input) . unwrap( ) ,
155- Timestamp {
156- second: -1234567891 ,
157- nanosecond: 876550000 ,
158- }
159- ) ;
120+ for ( input, expected) in [
121+ ( "@1234567890" , ts ( 1234567890 , 0 ) ) , // positive seconds, no nanoseconds
122+ ( "@ 1234567890" , ts ( 1234567890 , 0 ) ) , // space after '@', positive seconds, no nanoseconds
123+ ( "@-1234567890" , ts ( -1234567890 , 0 ) ) , // negative seconds, no nanoseconds
124+ ( "@ -1234567890" , ts ( -1234567890 , 0 ) ) , // space after '@', negative seconds, no nanoseconds
125+ ( "@ - 1234567890" , ts ( -1234567890 , 0 ) ) , // space after '@' and after '-', negative seconds, no nanoseconds
126+ ( "@1234567890.12345" , ts ( 1234567890 , 123450000 ) ) , // positive seconds with nanoseconds, '.' as floating point
127+ ( "@1234567890,12345" , ts ( 1234567890 , 123450000 ) ) , // positive seconds with nanoseconds, ',' as floating point
128+ ( "@-1234567890.12345" , ts ( -1234567891 , 876550000 ) ) , // negative seconds with nanoseconds, '.' as floating point
129+ ( "@1234567890.1234567890123" , ts ( 1234567890 , 123456789 ) ) , // nanoseconds with more than 9 digits, truncated
130+ ] {
131+ let mut s = input;
132+ assert_eq ! ( parse( & mut s) . unwrap( ) , expected, "{input}" ) ;
133+ }
160134 }
161135}
0 commit comments