Validate and convert Julian dates¶
Validate a Julian-format date string or integer and convert it to a DateTime, or convert a DateTime into Julian format. This operation is triggered when a consumer calls Julian.IsValid, Julian.GetYear, Julian.ToDate, or the DateTime.ToJulian() extension method.
| Field | Value |
|---|---|
| Operation ID | OP-04 |
| Trigger | A consumer calls Julian.IsValid, Julian.GetYear, Julian.ToDate, or the DateTime.ToJulian() extension method. |
| Inputs | julian (string or int), optional millenium (int), yearLength (int, for ToJulian) |
| Outputs | IsValid returns bool with an out message; ToDate returns DateTime; ToJulian returns string. |
| Primary components | Julian.IsValid, Julian.GetYear, Julian.ToDate, Julian.ToJulian |
| Entry point | src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Helpers/Julian.cs |
Steps¶
- Validate that the input contains at least 4 digits. (BR-017)
- On failure:
IsValidreturnsfalsewith the message "The julian must contain at least 4 numbers".ToDatethrowsApplicationException. - Derive the year: if
millenium < 1000, derive it from the first digit of the current year times 1000; the year digits are those before the final 3, withmilleniumadded when under 1000. - Compute
isLeapYearusingSystem.Globalization.JulianCalendar.IsLeapYear. JulianCalendartreats every 4th year as a leap year, which does not match Gregorian century-year rules (for example 2100)*.- For
ToDate: reject a day-of-year greater than 365 (or 366 in a leap year). (BR-017) - On failure: throws
ApplicationExceptionwith a message that says "must be < {validDaysInYear}" even though the actual check is>, so a day equal to 365/366 is accepted*. - For
ToDate: return 1 January of the derived year plus (day − 1) days. - A day-of-year value of
000is not rejected and yields 31 December of the previous year*. - For
ToJulian(date, yearLength=2): whenyearLengthequals exactly2, convertdate.ToString("yy")to anintand concatenate it with the 3-digit day of year as astring— theintconversion drops any leading zero from the two-digit year (for example January 1, 2005 produces"5001", not"05001"). For any otheryearLengthvalue, the full numericdate.Year, without zero padding, is concatenated with the 3-digit day instead (for example January 1, 2005 produces"2005001", while January 1 of year 1 produces"1001", not a zero-padded"0001001"). This member is independent ofIsValid/ToDateand does not call either.
Process flow¶
The following diagram visualizes this operation's control flow, split into its four independent entry points — IsValid ends at its own bool return and is never followed by year/day conversion on its own; ToDate separately re-derives the year and builds a DateTime; ToJulian is a wholly independent forward conversion.
flowchart TD
subgraph IV["Julian.IsValid(julian)"]
IV_Start([Call IsValid]) --> IV_Check{At least 4 digits?}
IV_Check -->|No| IV_False(["Return false<br>with message"])
IV_Check -->|Yes| IV_True(["Return true"])
end
subgraph GY["Julian.GetYear(julian)"]
GY_Start([Call GetYear]) --> GY_Derive["Derive year from<br>digits before final 3"]
GY_Derive --> GY_Leap["Compute isLeapYear<br>via JulianCalendar"]
GY_Leap --> GY_Return(["Return year,<br>out isLeapYear"])
end
subgraph TD["Julian.ToDate(julian)"]
TD_Start([Call ToDate]) --> TD_Valid{IsValid?}
TD_Valid -->|No| TD_Throw1([Throw ApplicationException])
TD_Valid -->|Yes| TD_Year["Call GetYear"]
TD_Year --> TD_DayCheck{day-of-year within<br>valid days in year?}
TD_DayCheck -->|No| TD_Throw2([Throw ApplicationException])
TD_DayCheck -->|Yes| TD_Build(["Return Jan 1 of year<br>plus day minus 1"])
end
subgraph TJ["DateTime.ToJulian(yearLength)"]
TJ_Start([Call ToJulian]) --> TJ_Check{yearLength == 2?}
TJ_Check -->|Yes| TJ_Short["year = int of two-digit<br>yy, no leading zero"]
TJ_Check -->|No| TJ_Full["year = full numeric<br>date.Year, no padding"]
TJ_Short --> TJ_Build["Concatenate year with<br>3-digit day of year"]
TJ_Full --> TJ_Build
TJ_Build --> TJ_Return(["Return string"])
end
Failure and edge-case behavior¶
- Fewer than 4 digits:
IsValidreturnsfalse;ToDatethrowsApplicationException. - Day-of-year greater than the valid days in year: throws
ApplicationException, though the message text does not match the actual>comparison used*. - Day-of-year
000: accepted, yielding 31 December of the previous year*. - Leap-year detection via
JulianCalendarcan diverge from Gregorian rules on century years such as 2100*.
Related documentation¶
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with**could not be confirmed; treat as unknown until verified.
Sources¶
src/SAIF.NetCore.Common/SAIF.NetCore.Common/SAIF.NetCore.Common/Helpers/Julian.cs