inrease MAX_DURATION to 9999y 364d 23:59:59.9 (#128)

This commit is contained in:
Jens Krause 2025-10-13 14:09:16 +02:00 committed by GitHub
parent 51f83e5b06
commit d2f41e04e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 193 additions and 9 deletions

View File

@ -6,6 +6,7 @@
- (event) New `event` screen to count custom date times in the future or past. [#117](https://github.com/sectore/timr-tui/pull/117), [#120](https://github.com/sectore/timr-tui/pull/120), [#122](https://github.com/sectore/timr-tui/pull/122), [#123](https://github.com/sectore/timr-tui/pull/123), [#124](https://github.com/sectore/timr-tui/pull/124), [#125](https://github.com/sectore/timr-tui/pull/125)
- (screens) switch by `←` or `→` keys [#127](https://github.com/sectore/timr-tui/pull/127)
- (duration) inrease `MAX_DURATION` to `9999y 364d 23:59:59.9` [#128](https://github.com/sectore/timr-tui/pull/128)
### Breaking change

View File

@ -31,9 +31,9 @@ pub const ONE_YEAR: Duration =
// ^ https://www.math.net/days-in-a-year
const DAYS_PER_YEAR: u64 = 365; // ignore leap year of 366 days
// max. 999y 364d 23:59:59.9 (1000 years - 1 decisecond)
// max. 9999y 364d 23:59:59.9 (10k years - 1 decisecond)
pub const MAX_DURATION: Duration = ONE_YEAR
.saturating_mul(1000)
.saturating_mul(10000)
.saturating_sub(ONE_DECI_SECOND);
/// Trait for duration types that can be displayed in clock widgets.
@ -678,11 +678,11 @@ mod tests {
);
// MAX_DURATION clamping
assert_eq!(parse_long_duration("1000y").unwrap(), MAX_DURATION);
assert_eq!(parse_long_duration("10000y").unwrap(), MAX_DURATION);
assert_eq!(
parse_long_duration("999y 364d 23:59:59").unwrap(),
parse_long_duration("9999y 364d 23:59:59").unwrap(),
Duration::from_secs(
999 * YEAR_IN_SECONDS
9999 * YEAR_IN_SECONDS
+ 364 * DAY_IN_SECONDS
+ 23 * HOUR_IN_SECONDS
+ 59 * MINUTE_IN_SECONDS

View File

@ -11,6 +11,7 @@ use ratatui::{
widgets::{StatefulWidget, Widget},
};
use crate::widgets::clock_elements::FOUR_DIGITS_WIDTH;
use crate::{
common::{ClockTypeId, Style as DigitStyle},
duration::{
@ -88,10 +89,19 @@ pub enum Format {
YyyDHhMmSs,
YyyDdHhMmSs,
YyyDddHhMmSs,
YyyyDHhMmSs,
YyyyDdHhMmSs,
YyyyDddHhMmSs,
}
pub fn format_by_duration<D: ClockDuration>(d: &D) -> Format {
if d.years() >= 100 && d.days_mod() >= 100 {
if d.years() >= 1000 && d.days_mod() >= 100 {
Format::YyyyDddHhMmSs
} else if d.years() >= 1000 && d.days_mod() >= 10 {
Format::YyyyDdHhMmSs
} else if d.years() >= 1000 && d.days() >= 1 {
Format::YyyyDHhMmSs
} else if d.years() >= 100 && d.days_mod() >= 100 {
Format::YyyDddHhMmSs
} else if d.years() >= 100 && d.days_mod() >= 10 {
Format::YyyDdHhMmSs
@ -140,7 +150,10 @@ pub fn time_by_format(format: &Format) -> Time {
| Format::YyDHhMmSs
| Format::YyyDddHhMmSs
| Format::YyyDdHhMmSs
| Format::YyyDHhMmSs => Time::Years,
| Format::YyyDHhMmSs
| Format::YyyyDddHhMmSs
| Format::YyyyDdHhMmSs
| Format::YyyyDHhMmSs => Time::Years,
Format::DddHhMmSs | Format::DdHhMmSs | Format::DHhMmSs => Time::Days,
Format::HhMmSs | Format::HMmSs => Time::Hours,
Format::MmSs | Format::MSs => Time::Minutes,
@ -677,6 +690,48 @@ pub fn clock_horizontal_lengths(format: &Format, with_decis: bool) -> Vec<u16> {
const LABEL_WIDTH: u16 = DIGIT_LABEL_WIDTH + DIGIT_SPACE_WIDTH;
match format {
Format::YyyyDddHhMmSs => add_decis(
vec![
FOUR_DIGITS_WIDTH, // y_y_y_y
LABEL_WIDTH, // _l__
THREE_DIGITS_WIDTH, // d_d_d
LABEL_WIDTH, // _l__
TWO_DIGITS_WIDTH, // h_h
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // m_m
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // s_s
],
with_decis,
),
Format::YyyyDdHhMmSs => add_decis(
vec![
FOUR_DIGITS_WIDTH, // y_y_y_y
LABEL_WIDTH, // _l__
TWO_DIGITS_WIDTH, // d_d
LABEL_WIDTH, // _l__
TWO_DIGITS_WIDTH, // h_h
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // m_m
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // s_s
],
with_decis,
),
Format::YyyyDHhMmSs => add_decis(
vec![
FOUR_DIGITS_WIDTH, // y_y_y_y
LABEL_WIDTH, // _l__
DIGIT_WIDTH, // d
LABEL_WIDTH, // _l__
TWO_DIGITS_WIDTH, // h_h
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // m_m
COLON_WIDTH, // :
TWO_DIGITS_WIDTH, // s_s
],
with_decis,
),
Format::YyyDddHhMmSs => add_decis(
vec![
THREE_DIGITS_WIDTH, // y_y_y
@ -922,6 +977,20 @@ pub fn render_clock<D: ClockDuration>(area: Rect, buf: &mut Buffer, state: Rende
let edit_secs = matches!(editable_time, Some(Time::Seconds));
let edit_decis = matches!(editable_time, Some(Time::Decis));
let render_four_digits = |d1, d2, d3, d4, editable, area, buf: &mut Buffer| {
let [a1, a2, a3, a4] = Layout::horizontal(Constraint::from_lengths([
DIGIT_WIDTH + DIGIT_SPACE_WIDTH,
DIGIT_WIDTH + DIGIT_SPACE_WIDTH,
DIGIT_WIDTH + DIGIT_SPACE_WIDTH,
DIGIT_WIDTH,
]))
.areas(area);
Digit::new(d1, editable, symbol).render(a1, buf);
Digit::new(d2, editable, symbol).render(a2, buf);
Digit::new(d3, editable, symbol).render(a3, buf);
Digit::new(d4, editable, symbol).render(a4, buf);
};
let render_three_digits = |d1, d2, d3, editable, area, buf: &mut Buffer| {
let [a1, a2, a3] = Layout::horizontal(Constraint::from_lengths([
DIGIT_WIDTH + DIGIT_SPACE_WIDTH,
@ -952,6 +1021,18 @@ pub fn render_clock<D: ClockDuration>(area: Rect, buf: &mut Buffer, state: Rende
Dot::new(symbol).render(area, buf);
};
let render_yyyy = |area, buf| {
render_four_digits(
(duration.years() / 1000) % 10,
(duration.years() / 100) % 10,
(duration.years() / 10) % 10,
duration.years() % 10,
edit_years,
area,
buf,
);
};
let render_yyy = |area, buf| {
render_three_digits(
(duration.years() / 100) % 10,
@ -1065,6 +1146,90 @@ pub fn render_clock<D: ClockDuration>(area: Rect, buf: &mut Buffer, state: Rende
};
match format {
Format::YyyyDddHhMmSs if with_decis => {
let [y_y_y_y, ly, d_d_d, ld, h_h, c_hm, m_m, c_ms, s_s, dot, ds] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_ddd(d_d_d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
render_dot(dot, buf);
render_ds(ds, buf);
}
Format::YyyyDddHhMmSs => {
let [y_y_y_y, ly, d_d_d, ld, h_h, c_hm, m_m, c_ms, s_s] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_ddd(d_d_d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
}
Format::YyyyDdHhMmSs if with_decis => {
let [y_y_y_y, ly, d_d, ld, h_h, c_hm, m_m, c_ms, s_s, dot, ds] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_dd(d_d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
render_dot(dot, buf);
render_ds(ds, buf);
}
Format::YyyyDdHhMmSs => {
let [y_y_y_y, ly, d_d, ld, h_h, c_hm, m_m, c_ms, s_s] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_dd(d_d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
}
Format::YyyyDHhMmSs if with_decis => {
let [y_y_y_y, ly, d, ld, h_h, c_hm, m_m, c_ms, s_s, dot, ds] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_d(d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
render_dot(dot, buf);
render_ds(ds, buf);
}
Format::YyyyDHhMmSs => {
let [y_y_y_y, ly, d, ld, h_h, c_hm, m_m, c_ms, s_s] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);
render_yyyy(y_y_y_y, buf);
render_label_y(ly, buf);
render_d(d, buf);
render_label_d(ld, buf);
render_hh(h_h, buf);
render_colon(c_hm, buf);
render_mm(m_m, buf);
render_colon(c_ms, buf);
render_ss(s_s, buf);
}
Format::YyyDddHhMmSs if with_decis => {
let [y_y_y, ly, d_d_d, ld, h_h, c_hm, m_m, c_ms, s_s, dot, ds] =
Layout::horizontal(Constraint::from_lengths(widths)).areas(area);

View File

@ -8,8 +8,8 @@ pub const DIGIT_SIZE: usize = 5;
pub const DIGIT_WIDTH: u16 = DIGIT_SIZE as u16;
pub const DIGIT_HEIGHT: u16 = DIGIT_SIZE as u16 + 1 /* border height */;
pub const TWO_DIGITS_WIDTH: u16 = DIGIT_WIDTH + DIGIT_SPACE_WIDTH + DIGIT_WIDTH; // digit-space-digit
pub const THREE_DIGITS_WIDTH: u16 =
DIGIT_WIDTH + DIGIT_SPACE_WIDTH + DIGIT_WIDTH + DIGIT_SPACE_WIDTH + DIGIT_WIDTH; // digit-space-digit-space-digit
pub const THREE_DIGITS_WIDTH: u16 = TWO_DIGITS_WIDTH + DIGIT_SPACE_WIDTH + DIGIT_WIDTH; // digit-space-digit-space-digit
pub const FOUR_DIGITS_WIDTH: u16 = THREE_DIGITS_WIDTH + DIGIT_SPACE_WIDTH + DIGIT_WIDTH; // digit-space-digit-space-digit-space-digit
pub const COLON_WIDTH: u16 = 4; // incl. padding left + padding right
pub const DOT_WIDTH: u16 = 4; // incl. padding left + padding right
pub const DIGIT_SPACE_WIDTH: u16 = 1; // space between digits

View File

@ -202,6 +202,24 @@ fn test_format_by_duration_boundaries() {
format_by_duration::<DurationEx>(&(100 * ONE_YEAR + 100 * ONE_DAY).into()),
Format::YyyDddHhMmSs
);
// YyyDdHhMmSs
assert_eq!(
format_by_duration::<DurationEx>(&(1000 * ONE_YEAR + 10 * ONE_DAY).into()),
Format::YyyyDdHhMmSs
);
// YyyyDdHhMmSs
assert_eq!(
format_by_duration::<DurationEx>(
&(1000 * ONE_YEAR + (100 * ONE_DAY).saturating_sub(ONE_SECOND)).into()
),
Format::YyyyDdHhMmSs
);
// YyyyDddHhMmSs
assert_eq!(
format_by_duration::<DurationEx>(&(1000 * ONE_YEAR + 100 * ONE_DAY).into()),
Format::YyyyDddHhMmSs
);
}
#[test]