Skip to content

RFC3339

Canonical source: protos/lib/datetime/RFC3339.protos at locked revision e99b712ecf658a527b1fe82c8beba2c1286d8dc9.

// THE LICENSED WORK IS PROVIDED UNDER THE TERMS OF THE ADAPTIVE PUBLIC LICENSE
// ("LICENSE") AS FIRST COMPLETED BY: Guillermo Adrián Molina. ANY USE, PUBLIC
// DISPLAY, PUBLIC PERFORMANCE, REPRODUCTION OR DISTRIBUTION OF, OR PREPARATION OF
// DERIVATIVE WORKS BASED ON, THE LICENSED WORK CONSTITUTES RECIPIENT'S ACCEPTANCE
// OF THIS LICENSE AND ITS TERMS, WHETHER OR NOT SUCH RECIPIENT READS THE TERMS OF
// THE LICENSE. "LICENSED WORK" AND "RECIPIENT" ARE DEFINED IN THE LICENSE. A COPY
// OF THE LICENSE IS LOCATED IN THE TEXT FILE ENTITLED "LICENSE.TXT" ACCOMPANYING
// THE CONTENTS OF THIS FILE. IF A COPY OF THE LICENSE DOES NOT ACCOMPANY THIS
// FILE, A COPY OF THE LICENSE MAY ALSO BE OBTAINED AT THE FOLLOWING WEB SITE:
// https://github.com/guillermomolina/protos
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
// the specific language governing rights and limitations under the License.
//! A bounded RFC 3339 Internet timestamp adapter for
//! `std:datetime/OffsetDateTime`. It accepts and writes only timestamps that
//! LIB013 represents exactly:
//!
//! ```text
//! YYYY-MM-DDTHH:MM:SS[.fraction]OFFSET
//! ```
//!
//! The year is exactly four digits, `0000` through `9999`; month, day, hour,
//! minute, and second are exactly two digits; `T` is uppercase; the fraction
//! is absent or one through nine digits; and `OFFSET` is uppercase `Z` or a
//! numeric `+HH:MM` or `-HH:MM`.
//!
//! RFC 3339 features with no exact LIB013 value are rejected rather than
//! normalized: lowercase `t` and `z`, leap-second `:60` labels (LIB013 has no
//! leap seconds), ten or more fraction digits (precision is exactly
//! nanoseconds and nothing is rounded), and `-00:00`, whose RFC 3339 meaning
//! of a known UTC instant with an unknown local offset cannot be held by an
//! offset date-time without losing information. Numeric offsets have minute
//! resolution only, so second-resolution offsets and negative or expanded
//! years are not RFC 3339 text even though `std:datetime/ISO8601` writes
//! them.
//!
//! Every timestamp accepted here is also accepted by `std:datetime/ISO8601`
//! with the same meaning, so this adapter enforces its narrower grammar and
//! then shares that profile's construction through the value modules. It has
//! no time-zone, time-zone database, locale, or clock authority.
/// Parses `text` as exactly `YYYY-MM-DDTHH:MM:SS[.fraction]` followed by `Z`
/// or `±HH:MM`, and answers a fresh `std:datetime/OffsetDateTime` holding the
/// local date-time and offset as written. A non-String argument, any other
/// form, `-00:00`, second `60`, ten or more fraction digits, an offset outside
/// `std:datetime/Offset`'s range, or an invalid date or time signals an Error.
parseOffsetDateTime: (text) => {
ISO8601: import("std:datetime/ISO8601")
String.recognizes(text).ifFalse(() => {
Error().signal()
})
// The shortest timestamp is `YYYY-MM-DDTHH:MM:SSZ`.
size: text.size()
(size >= 20).ifFalse(() => {
Error().signal()
})
// A signed year is never RFC 3339 text; ISO8601 then requires the
// remaining year to be exactly four digits.
((text[0] == "-") || (text[0] == "+")).ifTrue(() => {
Error().signal()
})
// The offset is exactly `Z` or the six scalars `±HH:MM`. ISO8601 parses
// the offset from the first sign after `T`, so a longer offset spelling
// that would place a sign six scalars from the end is rejected there.
zulu: text[size - 1] == "Z"
numeric: ((text[size - 6] == "+") || (text[size - 6] == "-")) && (text[size - 3] == ":")
(zulu || numeric).ifFalse(() => {
Error().signal()
})
ISO8601.parseOffsetDateTime(text)
}
/// Answers the canonical RFC 3339 text of `value`, a value recognized by
/// `std:datetime/OffsetDateTime`: the four-digit-year local date-time with an
/// uppercase `T`, mandatory seconds, and the fraction written as in
/// `std:datetime/ISO8601`, followed by `Z` for a zero offset or `±HH:MM`. The
/// value is written as stored and never normalized to UTC. Any other
/// argument, a negative year, or an offset that is not a whole number of
/// minutes signals an Error; the value itself remains valid and the offset is
/// never rounded.
formatOffsetDateTime: (value) => {
ISO8601: import("std:datetime/ISO8601")
OffsetDateTime: import("std:datetime/OffsetDateTime")
OffsetDateTime.recognizes(value).ifFalse(() => {
Error().signal()
})
(value.dateTime.date.year >= 0).ifFalse(() => {
Error().signal()
})
((value.offset.seconds % 60) == 0).ifFalse(() => {
Error().signal()
})
ISO8601.formatOffsetDateTime(value)
}

← datetime family · Standard-library source