# Parsing Dates and Times
**Trivet** supports parsing and writing of time and date strings in [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) format. For example: `1969-07-20T20:17:00Z` represents 20 July 1969, 8:17 PM UTC, the date and time of the first Moon landing.
Dates and times have the following representation.
```ebnf
date-fullyear = 4DIGIT
date-month = 2DIGIT ; 01-12
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
; month/year
time-hour = 2DIGIT ; 00-23
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
; rules
time-secfrac = "." 1*DIGIT
time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset
partial-time = time-hour ":" time-minute ":" time-second
[time-secfrac]
full-date = date-fullyear "-" date-month "-" date-mday
full-time = partial-time time-offset
date-time = full-date "T" full-time
```
Note that whitespace is not allowed _except_ for a single space in lieu of a `T` between a date and a time. While dates are fairly self-explanatory and follow the year-month-day form with leading zeros, times are more complex. A time has the basic form `HH:MM:SS`, though the seconds can be omitted. A fractional second is allowed with precision up to femtoseconds (1e-15) and a time zone offset of the form `+HH:MM` or `-HH:MM` may be applied, or `Z` can be used to indicate UTC.
For instance, 3:21 PM eastern daylight time could be written `15:21:00-04:00` or `19:21:00Z` (or using other offsets).
## Representing Dates and/or Times
Dates can be represented with the `trivet::parsers::datetime::Date` structure. Similarly, times can be represented with the `trivet::parsers::datetime::Time` structure. Typically you will want to enclose either (or perhaps both) in a variant of `trivet::parsers::datetime::DateTime`. The following encodes the date of the Apollo landing mentioned above, and then prints it.
```rust,ignore
{{#include ../../examples/book_datetime_apollo.rs}}
```
This code produces the following output.
```text
1969-07-20T20:17:00Z
```
## Detecting Dates and Times in the Stream
Date and time parsing is handled by the `trivet::parsers::datetime` module.
Because dates and times start with digits, there are special methods to detect when a date or time is present in the stream.
| `datetime::is_date(&mut Parser) -> bool` | Return `true` if the upcoming characters in the stream appear to be a date |
| `datetime::is_time(&mut Parser) -> bool` | Return `true` if the upcoming characters in the stream appear to be a time |
These methods are only approximate because they only check the structure of the upcoming characters, and not the validitiy of the date or time. So `9184-99-00` would satisfy the `is_date(parser)` check, but is clearly not a valid date. Validation is performed when the date or time is actually parsed.
## Parsing Dates and/or Times
Parsing of dates and/or times is handled by the `trivet::parsers::datetime::parse_date_time(&mut Parser) -> DateTime` function. This parses a date, time, or potentially both, from the stream. It does not parse any leading or trailing whitespace. It performs some validation of dates.
- Months must be in the range `01` to `12`, and days must be appropriate for the given month, so `1992-02-30` is rejected, as is `1900-02-29` (that was not a leap year even though it is divisible by 4). `2000-02-29` is accepted.
- Hours must be in the range `00` to `23`, minutes must be in the range `00` to `59`, and seconds must be in the range `00` to `59`. The fractional seconds, if included, must not be empty. The offset must be either `Z` for UTC, omitted for "local time," or a correct hour and minute offset.
- If both a date and time are given, then the date must be given first, followed by the time separated by either a single space or the character `T`.
The following is a small interactive program that reads lines of text and then reports how each is handled by **Trivet**. You can use it to explore the parsing of dates and times. Note that this program always tries to parse the text as a date and/or time, regardles of the results of `is_date(&mut Parser)` and `is_time(&mut Parser)`.
```rust,ignore
{{#include ../../examples/book_datetime_tester.rs}}
```