Skip to content

Add date_type and time_type sub-types to stdlib_datetime#1179

Open
JAi-SATHVIK wants to merge 2 commits intofortran-lang:masterfrom
JAi-SATHVIK:add-date-time-types
Open

Add date_type and time_type sub-types to stdlib_datetime#1179
JAi-SATHVIK wants to merge 2 commits intofortran-lang:masterfrom
JAi-SATHVIK:add-date-time-types

Conversation

@JAi-SATHVIK
Copy link
Copy Markdown
Contributor

Follows up on issue #1147 (#1147 (comment))

I added two new types to make working with dates and times easier:

date_type: For calendar dates only (Year, Month, Day).
time_type: For clock times only (Hours, Minutes, Seconds).

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 11, 2026

Codecov Report

❌ Patch coverage is 92.38965% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.87%. Comparing base (a21a7d6) to head (fcdab92).
⚠️ Report is 7 commits behind head on master.

Files with missing lines Patch % Lines
src/datetime/stdlib_datetime.f90 82.51% 50 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1179      +/-   ##
==========================================
+ Coverage   68.81%   69.87%   +1.05%     
==========================================
  Files         408      408              
  Lines       13726    14374     +648     
  Branches     1552     1700     +148     
==========================================
+ Hits         9446    10044     +598     
- Misses       4280     4330      +50     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jalvesz jalvesz requested a review from Copilot April 16, 2026 18:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds date_type and time_type sub-types to stdlib_datetime to support date-only / time-only workflows, including constructors, parsing/formatting helpers, UTC conversion, and operator overloads, with expanded unit test coverage.

Changes:

  • Introduces new derived types date_type and time_type, plus constructors (date, time_of_day) and extractors (get_date, get_time).
  • Adds parse_date/format_date and parse_time/format_time, plus operator overloads for date/time arithmetic and comparisons.
  • Extends the datetime test suite with focused unit tests and basic integration tests for composing/decomposing datetime_type.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
src/datetime/stdlib_datetime.f90 Implements date_type/time_type APIs (construct/parse/format/operators/UTC helpers).
test/datetime/test_datetime.f90 Adds unit + integration tests covering new date/time sub-types and helpers.
Comments suppressed due to low confidence (2)

src/datetime/stdlib_datetime.f90:1181

  • day_of_year_dt (and the new day_of_year_date) return 0 for an invalid month, but the public interface documentation states the return is in 1–366. Either update the contract/docs to include the 0 sentinel, or enforce validity earlier and keep the return range consistent with the documented behavior.
        !! Return the ordinal day of the year (1-366)
        !! for a datetime_type.
        type(datetime_type), intent(in) :: dt
        integer :: doy
        integer, parameter :: cum(12) = &
            [0,31,59,90,120,151,181,212,243,273,304,334]
        ! Guard against invalid month values
        if (dt%month < 1 .or. dt%month > 12) then
            doy = 0
            return
        end if

src/datetime/stdlib_datetime.f90:1219

  • day_of_week_dt (and day_of_week_date) return 0 for an invalid month, but the public interface documentation promises ISO weekday values in 1–7. Either document the 0 sentinel explicitly or enforce input validity so callers can rely on the documented range.
        !! Return ISO weekday (1=Monday ... 7=Sunday)
        !! for a datetime_type.
        type(datetime_type), intent(in) :: dt
        integer :: dow
        integer :: y, w
        integer, parameter :: t(12) = &
            [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
        ! Guard against invalid month values
        if (dt%month < 1 .or. dt%month > 12) then
            dow = 0
            return
        end if

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/datetime/stdlib_datetime.f90 Outdated
Comment thread src/datetime/stdlib_datetime.f90 Outdated
slen = len_trim(str)

! Require exactly YYYY-MM-DD (10 characters)
if (slen < 10) then
Comment thread src/datetime/stdlib_datetime.f90 Outdated
if (present(stat)) stat = 1
return
end if
t%millisecond = nint(ms_frac * 1000.0_dp)
Comment on lines +399 to +410
pure function date_plus_td(d, td) result(res)
!! version: experimental
!!
!! date + timedelta -> date (adds whole days only).
type(date_type), intent(in) :: d
type(timedelta_type), intent(in) :: td
type(date_type) :: res
integer(int64) :: total_days
total_days = days_from_civil(d%year, d%month, d%day) &
+ int(td%days, int64)
call civil_from_days(total_days, &
res%year, res%month, res%day)
Comment on lines +1051 to +1060
subroutine test_time_comparison_tz(error)
type(error_type), allocatable, intent(out) :: error
type(time_type) :: t1, t2
! 12:00 UTC == 17:30 +05:30
t1 = time_type(12, 0, 0, 0, 0)
t2 = time_type(17, 30, 0, 0, 330)
call check(error, t1 == t2, &
"12:00Z should equal 17:30+05:30")
if (allocated(error)) return
end subroutine test_time_comparison_tz
@JAi-SATHVIK
Copy link
Copy Markdown
Contributor Author

Hi @jalvesz,
Addressed several datetime issues by enforcing strict ISO date parsing, clamping millisecond values to prevent rounding overflows, and ensuring date arithmetic accounts for full timedelta durations.

Added new regression tests to verify midnight-crossing timezone comparisons and strict string validation, ensuring the module handles edge cases like sub-day components and trailing characters correctly.

@jvdp1
Copy link
Copy Markdown
Member

jvdp1 commented Apr 17, 2026

@JAi-SATHVIK thank you for this PR. However, Github shows commits that are already merged and are older thant this PR. Could you check that, please, to faciliate its review?

@JAi-SATHVIK JAi-SATHVIK force-pushed the add-date-time-types branch 2 times, most recently from fff814e to e8eab58 Compare April 18, 2026 06:49
@JAi-SATHVIK JAi-SATHVIK force-pushed the add-date-time-types branch from e8eab58 to 7653d13 Compare April 18, 2026 07:41
Copy link
Copy Markdown
Member

@jvdp1 jvdp1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you @JAi-SATHVIK . Here are some suggestions

Comment thread src/datetime/stdlib_datetime.f90 Outdated
!! version: experimental
!!
!! Represents a calendar date (no time-of-day component).
integer :: year = 1 !! Year (1-9999)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are negative years not supported?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, now negative years are supported by the underlying algorithm

Comment thread src/datetime/stdlib_datetime.f90 Outdated
Comment on lines +588 to +589
res = days_from_civil(d1%year, d1%month, d1%day) &
== days_from_civil(d2%year, d2%month, d2%day)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it not be more efficient to compare the components directly, instead of converting it first?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah correct, refactored the date comparison functions (==, /=, <, <=, >, >=) to compare the year, month, and day components directly.

integer :: milliseconds = 0 !! Milliseconds (0-999)
end type timedelta_type

type :: date_type
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if date_time_type could be an extension of date_type. This would avoid the need of "duplicating" many procedures.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting suggestion. While extending date_type would create an 'is-a' relationship, we would still need separate implementations for most procedures (like addition, subtraction, and full equality) to handle the sub-day components (time/milliseconds) correctly. For now, I've kept them separate to keep the types simple and consistent with the existing logic, but I'm open to refactoring this if you feel strongly about using inheritance here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants