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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// This is free and unencumbered software released into the public domain.
use crateTimezoneOffset;
use fmt;
/// A validated XSD 1.1 `gMonth` with an optional timezone.
///
/// Available without allocation or date/time features. Formatting can target a
/// fixed-capacity `core::fmt::Write` buffer; writer errors are propagated.
/// Construction, parsing, and formatting require neither `alloc`
/// nor `jiff`. Serde and Borsh support each require only their own feature,
/// which implies `alloc` but does not enable date/time support.
/// Formatting writes `--mm` followed by the optional offset, using `Z` for UTC.
/// Equality, ordering, and
/// hashing are structural. An absent timezone is distinct from explicit UTC.
/// `Ord` compares the month first, then the optional signed minute count, with
/// absence before any present offset. This total order is for Rust collections,
/// not XSD temporal value comparison: it performs no timezone normalization and
/// does not express uncertainty from an absent timezone. `Eq` and `Hash` use
/// the same fields. No XSD semantic comparison operation is provided yet.
///
/// ```
/// use xsd::{primitive::GMonth, TimezoneOffset};
/// let january = GMonth::new(1).unwrap();
/// let utc = january.with_timezone(Some(TimezoneOffset::UTC));
/// assert_ne!(january, utc);
/// assert!(january < utc); // structural ordering only
/// ```
///
/// This replaces the raw `u8` alias: use [`Self::new`] for checked construction
/// and [`Self::month`] to retrieve the field.
/// Parsing follows XSD 1.1 `--mm` syntax; legacy trailing hyphens (`--mm--`)
/// are rejected. Use [`crate::parse_g_month`] to parse the optional timezone.
/// Parsed values do not retain RDF lexical identity: `--01Z`, `--01+00:00`,
/// and `--01-00:00` become the same value. RDF applications must retain original
/// lexical strings and datatype identifiers separately when term identity matters.
///
/// With `serde`, the representation is now a struct with `month` (an integer)
/// and `timezone` (optional signed minutes), replacing the former bare integer.
/// Deserialization validates both fields. The enclosing `PrimitiveValue` enum
/// retains its `GMonth` tag; consumers of the former payload must migrate.
/// A missing `timezone` field decodes as absent. Round trips retain the month,
/// offset, and enclosing enum tags, but cannot recover original lexical spelling.
/// Invalid months and offsets are rejected even inside the value wrappers.
///
/// Explicit JSON conversion on [`crate::PrimitiveValue`] or [`crate::Value`]
/// (requires `serde`) instead emits the formatted XSD string. Recover the value
/// with [`crate::parse`] and [`crate::G_MONTH`], not Serde deserialization of
/// the wrapper. The string preserves the month and optional offset, but carries
/// no datatype tag and normalizes signed zero offsets to `Z`.
/// Explicit BSON conversion (requires `bson`, hence `std`) uses the same XSD
/// string, not a BSON date-time or integer month. Reparse with [`crate::G_MONTH`]
/// to recover the value; a string literal with the same text has identical BSON.
///
/// With `borsh`, the type-local version-1 encoding is a version byte `1`, a
/// `u8` month, then `Option<TimezoneOffset>`: tag `0` for absent, or tag `1`
/// followed by little-endian `i16` minutes. This is 3 or 5 bytes with no datatype
/// tag. It replaces the raw alias's single-byte encoding; decode legacy data as
/// `u8` and validate with [`Self::new`] before re-encoding. Decoding rejects
/// unknown versions, invalid months, option tags, and out-of-range offsets.
///
/// See: <https://www.w3.org/TR/xmlschema-2/#gMonth>