Skip to content

feat: add weekday access and business day arithmetic #56

Description

@ZialeHub

Summary

Date currently derefs to chrono::NaiveDate, so date.weekday() technically compiles — but it returns chrono::Weekday, not a timeflow type. This breaks the library's stated goal of being a full replacement for chrono: consumers must still import chrono just to work with the result of a basic weekday query.

Beyond weekday access, business day arithmetic (skipping weekends) is one of the most frequently needed capabilities in scheduling, HR, financial, and project-management applications, and it is entirely absent today.


Proposed API

Weekday type

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Weekday {
    Monday = 1,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

impl Weekday {
    pub fn is_weekend(self) -> bool { matches!(self, Self::Saturday | Self::Sunday) }
    pub fn is_business_day(self) -> bool { !self.is_weekend() }
}

Methods on Date and DateTime

// Weekday access
date.weekday() -> Weekday
date.is_weekend() -> bool
date.is_business_day() -> bool

// Navigation
date.next_business_day()? -> Date    // skip to next Mon–Fri (same day if already business day... or next?)
date.prev_business_day()? -> Date
date.next_weekday(Weekday::Monday)? -> Date  // next occurrence of a specific weekday

// Arithmetic
date.add_business_days(5)?  -> Date  // skip weekends while counting
date.sub_business_days(3)?  -> Date

// Counting
date.business_days_until(&other)? -> i64  // count Mon–Fri days between two dates

Behaviour Specification

next_business_day()

Returns the next Monday–Friday date strictly after self. If self is already a business day, it still advances to the next one. Use if date.is_business_day() { date } else { date.next_business_day()? } to get "current or next" semantics.

add_business_days(n)

Counts forward n weekdays, skipping Saturdays and Sundays. For example:

2024-10-11 (Friday) + 1 business day = 2024-10-14 (Monday)
2024-10-11 (Friday) + 3 business days = 2024-10-16 (Wednesday)

business_days_until(&other)

Returns a signed count (negative if other is in the past). Counts only Mon–Fri days in the interval [min(self, other), max(self, other)].


Implementation Notes

  • Weekday should implement From<chrono::Weekday> and Into<chrono::Weekday> for interop with downstream chrono code.
  • next_business_day has a worst case of iterating 2 days forward (from Friday → Monday), so no loop performance concern.
  • add_business_days(n) can be computed arithmetically: n / 5 full weeks + remaining days, adjusting for weekend crossings. Alternatively, a small loop over days is acceptable for typical n values.
  • This feature is gated by the date feature.
  • No external dependency required — pure calendar arithmetic over NaiveDate.

Acceptance Criteria

  • Weekday enum defined with all 7 days, is_weekend(), is_business_day()
  • From<chrono::Weekday> and Into<chrono::Weekday> implemented for Weekday
  • Date::weekday() returns timeflow::Weekday (not chrono::Weekday)
  • is_weekend() and is_business_day() available on Date and DateTime
  • next_business_day, prev_business_day, next_weekday implemented on Date
  • add_business_days, sub_business_days implemented
  • business_days_until implemented with correct signed semantics
  • Edge cases tested: Friday + 1 biz day → Monday, Friday + 5 biz days → next Friday, dates spanning public holidays (note: no public holiday support needed in this issue)
  • Weekday added to prelude
  • Doc comments with examples on all public methods

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-domainbusiness logic / coreB-ideaDiscussion; or implementation attempt, to be reviewed before further work

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions