Skip to content

Commit 5cc0c69

Browse files
committed
Add crate for integration with the AWS SDK for Rust
1 parent d6959a2 commit 5cc0c69

File tree

8 files changed

+277
-0
lines changed

8 files changed

+277
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ members = [
3535
"crates/jiff-icu",
3636
"crates/jiff-sqlx",
3737
"crates/jiff-static",
38+
"crates/jiff-aws",
3839
"crates/jiff-tzdb",
3940
"crates/jiff-tzdb-platform",
4041
"examples/*",

crates/jiff-aws/COPYING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This project is dual-licensed under the Unlicense and MIT licenses.
2+
3+
You may use this code under the terms of either license.

crates/jiff-aws/Cargo.toml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
[package]
2+
name = "jiff-aws"
3+
version = "0.1.0" #:version
4+
authors = ["Andrew Gallant <[email protected]>"]
5+
license = "Unlicense OR MIT"
6+
homepage = "https://github.com/BurntSushi/jiff/tree/master/crates/jiff-aws"
7+
repository = "https://github.com/BurntSushi/jiff"
8+
documentation = "https://docs.rs/jiff-aws"
9+
description = "Integration for Jiff with The AWS SDK for Rust"
10+
categories = ["date-and-time"]
11+
keywords = ["date", "time", "jiff", "aws", "zone"]
12+
workspace = "../.."
13+
edition = "2021"
14+
rust-version = "1.70"
15+
include = ["/src/*.rs", "/*.dat", "COPYING", "LICENSE-MIT", "UNLICENSE"]
16+
17+
[lib]
18+
name = "jiff_aws"
19+
bench = false
20+
path = "src/lib.rs"
21+
22+
[features]
23+
default = ["std"]
24+
std = ["alloc", "jiff/std"]
25+
alloc = ["jiff/alloc"]
26+
27+
[dependencies]
28+
aws-smithy-types = "1.2"
29+
jiff = { version = "0.2.0", path = "../..", default-features = false }
30+
31+
[dev-dependencies]
32+
jiff = { version = "0.2.0", path = "../..", default-features = true }

crates/jiff-aws/LICENSE-MIT

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 Andrew Gallant
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

crates/jiff-aws/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
jiff-aws
2+
=========
3+
This crate provides traits and methods to [`jiff`] that implement some basic
4+
conversion methods to/from the datetime types used in
5+
the [AWS SDK for Rust](https://aws.amazon.com/sdk-for-rust/).
6+

crates/jiff-aws/UNLICENSE

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <http://unlicense.org/>

crates/jiff-aws/src/lib.rs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*!
2+
This crate provides type convertion for [Jiff](jiff) and
3+
Aws Smithy Type [DateTime] used
4+
in the [AWS SDK for Rust](https://aws.amazon.com/sdk-for-rust/).
5+
6+
```
7+
use jiff_aws::ConvertAwsDateTime;
8+
use jiff_aws::ConvertJiffTypes;
9+
use jiff::Timestamp;
10+
use jiff::Zoned;
11+
use aws_smithy_types::DateTime;
12+
13+
let datetime = DateTime::from_secs_and_nanos(1627680004,123000000);
14+
let timestamp: Timestamp = datetime.try_into_timestamp().unwrap();
15+
assert_eq!( "2021-07-30T21:20:04.123Z".parse::<Timestamp>().unwrap(), timestamp);
16+
17+
let timestamp = Timestamp::try_from_aws(datetime).unwrap();
18+
assert_eq!( "2021-07-30T21:20:04.123Z".parse::<Timestamp>().unwrap(), timestamp);
19+
20+
let zoned = datetime.try_into_zoned().unwrap();
21+
assert_eq!( "2021-07-30T21:20:04.123+00:00[UTC]".parse::<Zoned>().unwrap(), zoned);
22+
23+
let zoned = Zoned::try_from_aws(datetime).unwrap();
24+
assert_eq!( "2021-07-30T21:20:04.123+00:00[UTC]".parse::<Zoned>().unwrap(), zoned);
25+
26+
let other: DateTime = timestamp.into_aws_datetime();
27+
assert_eq!(datetime, other);
28+
29+
let other = DateTime::from_timestamp(timestamp);
30+
assert_eq!(datetime, other);
31+
32+
let other: DateTime = zoned.clone().into_aws_datetime();
33+
assert_eq!(datetime, other);
34+
35+
let other = DateTime::from_zoned(zoned);
36+
assert_eq!(datetime, other);
37+
38+
```
39+
*/
40+
41+
use aws_smithy_types::DateTime;
42+
use jiff::{tz::TimeZone, Timestamp, Zoned};
43+
pub use traits::{ConvertAwsDateTime, ConvertJiffTypes};
44+
mod traits;
45+
46+
impl ConvertAwsDateTime for Timestamp {
47+
type Error = jiff::Error;
48+
49+
fn into_aws_datetime(self) -> DateTime {
50+
DateTime::from_timestamp(self)
51+
}
52+
53+
fn try_from_aws(value: DateTime) -> Result<Self, Self::Error> {
54+
jiff::Timestamp::new(value.secs(), value.subsec_nanos() as i32)
55+
}
56+
}
57+
58+
impl ConvertAwsDateTime for Zoned {
59+
type Error = jiff::Error;
60+
61+
fn into_aws_datetime(self) -> DateTime {
62+
DateTime::from_zoned(self)
63+
}
64+
65+
fn try_from_aws(value: DateTime) -> Result<Self, Self::Error> {
66+
let timestamp =
67+
jiff::Timestamp::new(value.secs(), value.subsec_nanos() as i32)?;
68+
Ok(timestamp.to_zoned(TimeZone::UTC))
69+
}
70+
}
71+
72+
impl ConvertJiffTypes for DateTime {
73+
type Error = jiff::Error;
74+
75+
fn from_timestamp(timestamp: Timestamp) -> Self {
76+
let (seconds, nanos) = if timestamp.subsec_nanosecond() < 0 {
77+
(
78+
timestamp.as_second() - 1,
79+
(1_000_000_000 + timestamp.subsec_nanosecond()) as u32,
80+
)
81+
} else {
82+
(timestamp.as_second(), timestamp.subsec_nanosecond() as u32)
83+
};
84+
85+
DateTime::from_secs_and_nanos(seconds, nanos)
86+
}
87+
88+
fn from_zoned(zoned: Zoned) -> Self {
89+
let timestamp = zoned.timestamp();
90+
Self::from_timestamp(timestamp)
91+
}
92+
93+
fn try_into_zoned(self) -> Result<Zoned, Self::Error> {
94+
Zoned::try_from_aws(self)
95+
}
96+
97+
fn try_into_timestamp(self) -> Result<Timestamp, Self::Error> {
98+
Timestamp::try_from_aws(self)
99+
}
100+
}
101+
102+
#[cfg(test)]
103+
mod tests {
104+
use crate::{traits::ConvertJiffTypes, ConvertAwsDateTime};
105+
use aws_smithy_types::DateTime;
106+
use jiff::{Timestamp, ToSpan};
107+
108+
#[test]
109+
fn epoch() -> Result<(), jiff::Error> {
110+
//Epoch
111+
let ts = Timestamp::UNIX_EPOCH;
112+
let dt = ts.into_aws_datetime();
113+
assert_eq!(DateTime::from_secs_and_nanos(0, 0), dt);
114+
115+
//Roundtrip Epoch
116+
let ts2 = dt.try_into_timestamp()?;
117+
assert_eq!(Timestamp::UNIX_EPOCH, ts2);
118+
119+
Ok(())
120+
}
121+
122+
#[test]
123+
fn epoch_minus_one_nano() -> Result<(), jiff::Error> {
124+
// Epoch -1 nanosecond
125+
let ts = Timestamp::UNIX_EPOCH - 1.nanosecond();
126+
let dt = ts.into_aws_datetime();
127+
assert_eq!(DateTime::from_secs_and_nanos(-1, 999_999_999), dt);
128+
129+
// Roundtrip -1 nanosecond
130+
let ts2 = dt.try_into_timestamp()?;
131+
assert_eq!(Timestamp::UNIX_EPOCH - 1.nanosecond(), ts2);
132+
133+
Ok(())
134+
}
135+
136+
#[test]
137+
fn epoch_minus_one_sec() -> Result<(), jiff::Error> {
138+
// Epoch -1 second
139+
let ts = Timestamp::UNIX_EPOCH - 1.second();
140+
let dt = ts.into_aws_datetime();
141+
assert_eq!(DateTime::from_secs_and_nanos(-1, 0), dt);
142+
143+
// Roundtrip epoch -1 second
144+
let ts2 = dt.try_into_timestamp()?;
145+
assert_eq!(Timestamp::UNIX_EPOCH - 1.second(), ts2);
146+
147+
Ok(())
148+
}
149+
150+
#[test]
151+
fn epoch_plus_1_sec_1_nano() -> Result<(), jiff::Error> {
152+
// Epoch + 1 second and 1 nanosecond
153+
let ts = Timestamp::UNIX_EPOCH + 1.second() + 1.nanosecond();
154+
let dt = ts.into_aws_datetime();
155+
assert_eq!(DateTime::from_secs_and_nanos(1, 1), dt);
156+
157+
// Roundtrip epoch + 1 second and 1 nanosecond
158+
let ts2 = dt.try_into_timestamp()?;
159+
assert_eq!(Timestamp::UNIX_EPOCH + 1.second() + 1.nanosecond(), ts2);
160+
161+
Ok(())
162+
}
163+
}

crates/jiff-aws/src/traits.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use aws_smithy_types::DateTime;
2+
use jiff::{Timestamp, Zoned};
3+
4+
/// A trait for adding methods to convert types into the [Jiff](jiff) types
5+
/// [Timestamp](jiff::Timestamp) and [Zoned](jiff::Zoned)
6+
pub trait ConvertJiffTypes: Sized {
7+
type Error;
8+
/// Infallibly creates a value of type `Self` from a Jiff [`Timestamp`](jiff::Timestamp)
9+
fn from_timestamp(value: Timestamp) -> Self;
10+
/// Infallibly creates a value of type `Self` from a Jiff [`Zoned`](jiff::Zoned)
11+
fn from_zoned(value: Zoned) -> Self;
12+
/// Fallibly creates a Jiff [`Zoned`](jiff::Zoned) (in TimeZone UTC) from `Self`
13+
fn try_into_zoned(self) -> Result<Zoned, Self::Error>;
14+
/// Fallibly creates a Jiff [`Timestamp`](jiff::Timestamp) from `Self`
15+
fn try_into_timestamp(self) -> Result<Timestamp, Self::Error>;
16+
}
17+
18+
/// A trait for adding methods to convert types into the aws smithy type [DateTime](aws_smithy_types::DateTime)
19+
pub trait ConvertAwsDateTime: Sized {
20+
type Error;
21+
/// Infallibly converts a value of type `Self` to a value of type Aws Smithy
22+
/// [`DateTime`](aws_smithy_types::DateTime).
23+
fn into_aws_datetime(self) -> DateTime;
24+
25+
/// Fallibly converts a value of Aws Smithy type [`DateTime`](aws_smithy_types::DateTime) to a value of type `Self`.
26+
fn try_from_aws(value: DateTime) -> Result<Self, Self::Error>;
27+
}

0 commit comments

Comments
 (0)