time_tz/
interface.rs

1// Copyright (c) 2022, Yuri6037
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification,
6// are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of time-tz nor the names of its contributors
14// may be used to endorse or promote products derived from this software
15// without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29use time::{OffsetDateTime, UtcOffset};
30
31/// This trait represents a particular timezone offset.
32pub trait Offset {
33    /// Converts this timezone offset to a [UtcOffset](time::UtcOffset).
34    fn to_utc(&self) -> UtcOffset;
35
36    /// Returns the name of this offset.
37    fn name(&self) -> &str;
38
39    /// Returns true if this offset is DST in the corresponding timezone, false otherwise.
40    fn is_dst(&self) -> bool;
41}
42
43/// This trait represents a timezone provider.
44pub trait TimeZone {
45    /// The type of offset.
46    type Offset: Offset;
47
48    /// Search for the given date time offset (assuming it is UTC) in this timezone.
49    fn get_offset_utc(&self, date_time: &OffsetDateTime) -> Self::Offset;
50
51    /// Search for the given date time offset (assuming it is already local) in this timezone.
52    fn get_offset_local(&self, date_time: &OffsetDateTime) -> OffsetResult<Self::Offset>;
53
54    /// Gets the main/default offset in this timezone.
55    fn get_offset_primary(&self) -> Self::Offset;
56
57    /// Returns the name of this timezone.
58    fn name(&self) -> &str;
59}
60
61/// This represents the possible types of errors when trying to find a local offset.
62#[derive(Clone, Copy, Debug)]
63pub enum OffsetResult<T> {
64    /// The date time is not ambiguous (exactly 1 is possible).
65    Some(T),
66
67    /// The date time is ambiguous (2 are possible).
68    Ambiguous(T, T),
69
70    /// The date time is invalid.
71    None,
72}
73
74impl<T> OffsetResult<T> {
75    /// Unwraps this OffsetResult assuming ambiguity is an error.
76    pub fn unwrap(self) -> T {
77        match self {
78            OffsetResult::Some(v) => v,
79            OffsetResult::Ambiguous(_, _) => panic!("Attempt to unwrap an ambiguous offset"),
80            OffsetResult::None => panic!("Attempt to unwrap an invalid offset"),
81        }
82    }
83
84    /// Unwraps this OffsetResult resolving ambiguity by taking the first result.
85    pub fn unwrap_first(self) -> T {
86        match self {
87            OffsetResult::Some(v) => v,
88            OffsetResult::Ambiguous(v, _) => v,
89            OffsetResult::None => panic!("Attempt to unwrap an invalid offset"),
90        }
91    }
92
93    /// Unwraps this OffsetResult resolving ambiguity by taking the second result.
94    pub fn unwrap_second(self) -> T {
95        match self {
96            OffsetResult::Some(v) => v,
97            OffsetResult::Ambiguous(_, v) => v,
98            OffsetResult::None => panic!("Attempt to unwrap an invalid offset"),
99        }
100    }
101
102    /// Turns this OffsetResult into an Option assuming ambiguity is an error.
103    pub fn take(self) -> Option<T> {
104        match self {
105            OffsetResult::Some(v) => Some(v),
106            OffsetResult::Ambiguous(_, _) => None,
107            OffsetResult::None => None,
108        }
109    }
110
111    /// Turns this OffsetResult into an Option resolving ambiguity by taking the first result.
112    pub fn take_first(self) -> Option<T> {
113        match self {
114            OffsetResult::Some(v) => Some(v),
115            OffsetResult::Ambiguous(v, _) => Some(v),
116            OffsetResult::None => None,
117        }
118    }
119
120    /// Turns this OffsetResult into an Option resolving ambiguity by taking the second result.
121    pub fn take_second(self) -> Option<T> {
122        match self {
123            OffsetResult::Some(v) => Some(v),
124            OffsetResult::Ambiguous(_, v) => Some(v),
125            OffsetResult::None => None,
126        }
127    }
128
129    /// Returns true if this OffsetResult is None.
130    pub fn is_none(&self) -> bool {
131        match self {
132            OffsetResult::Some(_) => false,
133            OffsetResult::Ambiguous(_, _) => false,
134            OffsetResult::None => true,
135        }
136    }
137
138    /// Returns true if this OffsetResult is ambiguous.
139    pub fn is_ambiguous(&self) -> bool {
140        match self {
141            OffsetResult::Some(_) => false,
142            OffsetResult::Ambiguous(_, _) => true,
143            OffsetResult::None => false,
144        }
145    }
146}