Add date_type and time_type sub-types to stdlib_datetime#1179
Add date_type and time_type sub-types to stdlib_datetime#1179JAi-SATHVIK wants to merge 2 commits intofortran-lang:masterfrom
Conversation
Codecov Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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_typeandtime_type, plus constructors (date,time_of_day) and extractors (get_date,get_time). - Adds
parse_date/format_dateandparse_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 newday_of_year_date) return0for an invalid month, but the public interface documentation states the return is in1–366. Either update the contract/docs to include the0sentinel, 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(andday_of_week_date) return0for an invalid month, but the public interface documentation promises ISO weekday values in1–7. Either document the0sentinel 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.
| slen = len_trim(str) | ||
|
|
||
| ! Require exactly YYYY-MM-DD (10 characters) | ||
| if (slen < 10) then |
| if (present(stat)) stat = 1 | ||
| return | ||
| end if | ||
| t%millisecond = nint(ms_frac * 1000.0_dp) |
| 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) |
| 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 |
|
Hi @jalvesz, Added new regression tests to verify midnight-crossing |
|
@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? |
fff814e to
e8eab58
Compare
e8eab58 to
7653d13
Compare
jvdp1
left a comment
There was a problem hiding this comment.
thank you @JAi-SATHVIK . Here are some suggestions
| !! version: experimental | ||
| !! | ||
| !! Represents a calendar date (no time-of-day component). | ||
| integer :: year = 1 !! Year (1-9999) |
There was a problem hiding this comment.
are negative years not supported?
There was a problem hiding this comment.
Yes, now negative years are supported by the underlying algorithm
| res = days_from_civil(d1%year, d1%month, d1%day) & | ||
| == days_from_civil(d2%year, d2%month, d2%day) |
There was a problem hiding this comment.
Would it not be more efficient to compare the components directly, instead of converting it first?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
I wonder if date_time_type could be an extension of date_type. This would avoid the need of "duplicating" many procedures.
There was a problem hiding this comment.
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.
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).