1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// This file is part of ICU4X. For terms of use, please see the file
// called LICENSE at the top level of the ICU4X source tree
// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).

mod common;
mod error;
pub mod hour_cycle;
mod item;
pub mod reference;
pub mod runtime;

use crate::fields;
pub use error::PatternError;
pub use hour_cycle::CoarseHourCycle;
use icu_provider::prelude::*;
pub use item::{GenericPatternItem, PatternItem};

/// The granularity of time represented in a pattern item.
/// Ordered from least granular to most granular for comparison.
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, yoke::Yokeable, zerofrom::ZeroFrom,
)]
#[cfg_attr(
    feature = "datagen",
    derive(serde::Serialize, databake::Bake),
    databake(path = icu_datetime::pattern),
)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[non_exhaustive]
pub enum TimeGranularity {
    None,
    Hours,
    Minutes,
    Seconds,
    Nanoseconds,
}

impl Default for TimeGranularity {
    fn default() -> Self {
        Self::None
    }
}

impl TimeGranularity {
    /// Returns [`true`] if the most granular time being displayed will align with
    /// the top of the hour, otherwise returns [`false`].
    /// e.g. `12:00:00` is at the top of the hour for any display granularity.
    /// e.g. `12:00:05` is only at the top of the hour if the seconds are not displayed.
    pub fn is_top_of_hour(self, minute: u8, second: u8, nanosecond: u32) -> bool {
        match self {
            Self::None | Self::Hours => true,
            Self::Minutes => minute == 0,
            Self::Seconds => minute + second == 0,
            Self::Nanoseconds => minute as u32 + second as u32 + nanosecond == 0,
        }
    }

    #[inline]
    pub(crate) fn from_ordinal(ordinal: u8) -> TimeGranularity {
        use TimeGranularity::*;
        match ordinal {
            1 => Hours,
            2 => Minutes,
            3 => Seconds,
            4 => Nanoseconds,
            _ => None,
        }
    }

    #[inline]
    pub(crate) const fn ordinal(self) -> u8 {
        use TimeGranularity::*;
        match self {
            None => 0,
            Hours => 1,
            Minutes => 2,
            Seconds => 3,
            Nanoseconds => 4,
        }
    }
}

impl From<&PatternItem> for TimeGranularity {
    /// Retrieves the granularity of time represented by a [`PatternItem`].
    /// If the [`PatternItem`] is not time-related, returns [`None`].
    fn from(item: &PatternItem) -> Self {
        match item {
            PatternItem::Field(field) => match field.symbol {
                fields::FieldSymbol::Hour(_) => Self::Hours,
                fields::FieldSymbol::Minute => Self::Minutes,
                fields::FieldSymbol::Second(s) => match s {
                    fields::Second::FractionalSecond => Self::Nanoseconds,
                    fields::Second::Millisecond | fields::Second::Second => Self::Seconds,
                },
                _ => Self::None,
            },
            _ => Self::None,
        }
    }
}