diff --git a/.clang-format b/.clang-format
index 463f128..90a197c 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,140 +1,189 @@
---
Language: Cpp
+# BasedOnStyle: Microsoft
DisableFormat: false
-# GENERAL INDENTATION
-UseTab: Never
-TabWidth: 4
-IndentWidth: 4
-
AccessModifierOffset: -2
-
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Right
+
AlignConsecutiveAssignments:
- Enabled: true
- AcrossEmptyLines: true
- AcrossComments: false
- AlignCompound: false
+ Enabled: true
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
AlignFunctionPointers: false
- PadOperators: true
+ PadOperators: true
+
+AlignConsecutiveBitFields:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+
+AlignConsecutiveDeclarations:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
+ AlignFunctionPointers: false
+ PadOperators: false
+
AlignConsecutiveMacros:
- Enabled: true
- AcrossEmptyLines: true
- AcrossComments: false
- AlignCompound: false
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCompound: false
AlignFunctionPointers: false
- PadOperators: false
+ PadOperators: false
+
+AlignConsecutiveShortCaseStatements:
+ Enabled: false
+ AcrossEmptyLines: false
+ AcrossComments: false
+ AlignCaseColons: false
+
AlignEscapedNewlines: Right
-AlignOperands: Align
+AlignOperands: Align
+
AlignTrailingComments:
- Kind: Always
- OverEmptyLines: 2
+ Kind: Always
+ OverEmptyLines: 2
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
-AllowBreakBeforeNoexceptSpecifier: Always
-AllowShortBlocksOnASingleLine: Never
+AllowBreakBeforeNoexceptSpecifier: Never
+AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
-AllowShortCompoundRequirementOnASingleLine: false
+AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: InlineOnly
+AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
-AllowShortLambdasOnASingleLine: All
+AllowShortLambdasOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
-
-AlwaysBreakAfterReturnType: None
+#AllowShortNamespacesOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
-AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
+# AttributeMacros:
+# - __capability
+
BinPackArguments: false
-BinPackParameters: false
+BinPackParameters: true
+BitFieldColonSpacing: Both
BreakBeforeBraces: Custom
BraceWrapping:
- AfterCaseLabel: true
- AfterClass: false
+ AfterCaseLabel: true
+ AfterClass: false
AfterControlStatement: false
- AfterEnum: false
+ AfterEnum: false
AfterExternBlock: true
- AfterFunction: true
- AfterNamespace: true
- AfterStruct: false
- AfterUnion: false
- BeforeCatch: false
- BeforeElse: false
+ AfterFunction: true
+ AfterNamespace: true
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
BeforeLambdaBody: true
- BeforeWhile: false
- IndentBraces: false
+ BeforeWhile: false
+ IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
- SplitEmptyNamespace: true
+ SplitEmptyNamespace: false
+
BreakAdjacentStringLiterals: true
-BreakAfterAttributes: Never
-#BreakAfterReturnType: Automatic
+BreakAfterAttributes: Leave
+BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
+BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeColon
BreakInheritanceList: AfterColon
BreakStringLiterals: true
-
-ColumnLimit: 95
+ColumnLimit: 95
+CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
-Cpp11BracedListStyle: false
-
+Cpp11BracedListStyle: true
DerivePointerAlignment: false
-
EmptyLineAfterAccessModifier: Never
-EmptyLineBeforeAccessModifier: Always
-ExperimentalAutoDetectBinPacking: true
-
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
-IncludeBlocks: Preserve
+# ForEachMacros:
+# - foreach
+# - Q_FOREACH
+# - BOOST_FOREACH
+# IfMacros:
+# - KJ_IF_MAYBE
+
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IncludeBlocks: Preserve
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: NoIndent
-IndentGotoLabels: false
-IndentPPDirectives: BeforeHash
-IndentRequiresClause: false
+IndentGotoLabels: true
+IndentPPDirectives: AfterHash
+IndentRequiresClause: true
+IndentWidth: 4
IndentWrappedFunctionNames: false
-InsertBraces: false
+InsertBraces: false
+InsertNewlineAtEOF: false
InsertTrailingCommas: None
+
IntegerLiteralSeparator:
- Binary: 0
- Decimal: 3
- Hex: 4
+ Binary: 0
+ Decimal: 3
+ Hex: 4
+KeepEmptyLinesAtTheStartOfBlocks: false
+KeepEmptyLinesAtEOF: true
LambdaBodyIndentation: Signature
-
+LineEnding: DeriveLF
+MacroBlockBegin: ''
+MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
-
-NamespaceIndentation: All
-
+NamespaceIndentation: None
PackConstructorInitializers: BinPack
PointerAlignment: Left
-PPIndentWidth: -1
-
+PPIndentWidth: -1
QualifierAlignment: Leave
-
ReferenceAlignment: Pointer
-ReflowComments: true
+ReflowComments: true
+RemoveBracesLLVM: false
RemoveParentheses: Leave
RemoveSemicolon: false
-#RequiresClausePosition: OwnLineWithBrace
+RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
-
SeparateDefinitionBlocks: Always
-ShortNamespaceLines: 3
-#SortIncludes:
-# Enabled: true
-# IgnoreCase: false
+ShortNamespaceLines: 1
+SkipMacroDefinitionBody: false
+SortIncludes: CaseSensitive
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
@@ -145,35 +194,67 @@ SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
+SpaceBeforeJsonColon: false
+
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
- AfterIfMacros: true
+ AfterIfMacros: true
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
+
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: true
SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInContainerLiterals: true
-# PENALTIES:
-PenaltyReturnTypeOnItsOwnLine: 10000
-PenaltyBreakTemplateDeclaration: 10000
-#PenaltyBreakBeforeMemberAccess: 10000
-PenaltyBreakAssignment: 800
-PenaltyBreakScopeResolution: 500
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+
+SpacesInParens: Never
+SpacesInParensOptions:
+ InCStyleCasts: false
+ InConditionalStatements: false
+ InEmptyParentheses: false
+ Other: false
+
+SpacesInSquareBrackets: false
+Standard: Latest
+TabWidth: 4
+UseTab: Never
+VerilogBreakBetweenInstancePorts: true
+
+# StatementAttributeLikeMacros:
+# - Q_EMIT
+
+# StatementMacros:
+# - Q_UNUSED
+# - QT_REQUIRE_VERSION
+
+# WhitespaceSensitiveMacros:
+# - BOOST_PP_STRINGIZE
+# - CF_SWIFT_NAME
+# - NS_SWIFT_NAME
+# - PP_STRINGIZE
+# - STRINGIZE
+
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 10
PenaltyBreakComment: 500
PenaltyBreakFirstLessLess: 120
-PenaltyExcessCharacter: 100
-PenaltyBreakBeforeFirstCallParameter: 10
-PenaltyBreakString: 10
-PenaltyBreakOpenParenthesis: 10
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakScopeResolution: 500
+PenaltyBreakString: 100
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
-
-...
+PenaltyReturnTypeOnItsOwnLine: 10000
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0d995b5..e418f57 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ set(PRJ_CXX_STANDARD 20)
project(
${PRJ_NAME}
- VERSION 0.0.0.0
+ VERSION 0.1.0.0
LANGUAGES C CXX ASM
)
@@ -96,7 +96,18 @@ include(linker/config)
# Sources
add_subdirectory(lib)
-add_subdirectory(src)
+
+include(utility/project_tools)
+
+# Set library-wide C++ standard
+use_project_cxx_standard(GLOBAL_CXX_OPTIONS INTERFACE)
+
+target_link_options(
+ GLOBAL_CXX_OPTIONS
+
+ INTERFACE
+ ${GLOBAL_LINK_FLAGS}
+)
# C Interface Source
if(CFFI_BUILD)
diff --git a/README.md b/README.md
index 0f2496f..8b403dc 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
diff --git a/cffi/CMakeLists.txt b/cffi/CMakeLists.txt
index 70ebe30..ec9e722 100644
--- a/cffi/CMakeLists.txt
+++ b/cffi/CMakeLists.txt
@@ -11,6 +11,8 @@
#
#====================================
+# TODO: Major changes needed here in due time...
+
set(
PRJ_CFFI_INCLUDE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}/include"
diff --git a/cffi/include/simplydt/common/c_datetime_defs.h b/cffi/include/simplydt/common/c_datetime_defs.h
index a641b9f..e1f284a 100644
--- a/cffi/include/simplydt/common/c_datetime_defs.h
+++ b/cffi/include/simplydt/common/c_datetime_defs.h
@@ -1,5 +1,5 @@
-// Copyright (C) 2023-2025 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
// Released under the terms of the GNU Affero General Public License version 3.
// [ISJTB-CXX-XL20230401-000001]
diff --git a/cffi/include/simplydt/common/c_datetime_utils.h b/cffi/include/simplydt/common/c_datetime_utils.h
index 773bbd5..4fc2557 100644
--- a/cffi/include/simplydt/common/c_datetime_utils.h
+++ b/cffi/include/simplydt/common/c_datetime_utils.h
@@ -1,5 +1,5 @@
-// Copyright (C) 2023-2025 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
// Released under the terms of the GNU Affero General Public License version 3.
// [ISJTB-CXX-XL20230401-000001]
diff --git a/cffi/src/CMakeLists.txt b/cffi/src/CMakeLists.txt
index cd7b28d..9a83e1b 100644
--- a/cffi/src/CMakeLists.txt
+++ b/cffi/src/CMakeLists.txt
@@ -3,6 +3,9 @@
# /cffi/src Directory Script
#=====================================
+# TODO: Major changes needed here in due time...
+# (For now, disregard this entire cffi directory)
+
set(ORIGINAL_BINARY_NAME "${${PRJ_SCOPE}_MAIN_BINARY_NAME}")
set(STATIC_CFFI_BINARY_NAME "${ORIGINAL_BINARY_NAME}_c")
@@ -19,13 +22,6 @@ target_include_directories(
${PRJ_CFFI_INCLUDE_DIRS}
)
-target_link_libraries(
- CFFI_LIBRARY_INTERFACE
-
- INTERFACE
- ${ORIGINAL_BINARY_NAME}
-)
-
target_link_libraries(
CFFI_LIBRARY_INTERFACE
diff --git a/cffi/src/common/c_datetime_utils.cpp b/cffi/src/common/c_datetime_utils.cpp
index 083b1f6..fef3257 100644
--- a/cffi/src/common/c_datetime_utils.cpp
+++ b/cffi/src/common/c_datetime_utils.cpp
@@ -1,5 +1,5 @@
-// Copyright (C) 2023-2025 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
// Released under the terms of the GNU Affero General Public License version 3.
// [ISJTB-CXX-XL20230401-000001]
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 49bdb9b..c7f91b5 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = "Simply Datetime"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = v0.0.0.0
+PROJECT_NUMBER = v0.1.0.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/docs/prj/diagrams.drawio b/docs/prj/diagrams.drawio
new file mode 100644
index 0000000..04d561a
--- /dev/null
+++ b/docs/prj/diagrams.drawio
@@ -0,0 +1,4107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/ref/generate_docs.sh b/docs/ref/generate_docs
old mode 100755
new mode 100644
similarity index 100%
rename from docs/ref/generate_docs.sh
rename to docs/ref/generate_docs
diff --git a/include/simplydt/calendar/abstract_calendar.hpp b/include/simplydt/calendar/abstract_calendar.hpp
new file mode 100644
index 0000000..4efda67
--- /dev/null
+++ b/include/simplydt/calendar/abstract_calendar.hpp
@@ -0,0 +1,687 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file abstract_calendar.hpp
+ *
+ * @brief
+ * Base calendar system interface declaration.
+ */
+
+
+#ifndef SIMPLYDT_LIB_BASE_CALENDAR_INTERFACE_H_
+#define SIMPLYDT_LIB_BASE_CALENDAR_INTERFACE_H_
+
+#include "simplydt/common/simplydt_defs.hpp"
+#include "simplydt/common/stl_chrono_defs.hpp"
+#include "simplydt/common/stl_chrono_utils.hpp"
+#include "simplydt/time/units/time_units.hpp"
+#include
+#include
+#include
+
+namespace simplydt
+{
+
+/*!
+ * @brief
+ * Base calendar interface.
+ *
+ * @details
+ * This serves as the foundational interface for calendar
+ * systems in Simply Datetime. It is designed to be agnostic
+ * of any specific calendar implementation, allowing derived
+ * calendars to define their own characteristics. Note that
+ * the assumption is made that the calendar model in question
+ * utilizes year, month, and day values to describe a date in
+ * time. An implementation of this type focuses on conducting
+ * calendar operations on dates of type `Date_Impl` while
+ * obeying defined systemic calendar rules. Similar to other
+ * class hierarchies in Simply Datetime, this family uses the
+ * CRTP design pattern which allows this base to reference the
+ * derivative. Consequently, the convenience methods defined
+ * in this base structure depend on the concrete calendars
+ * public API for them to be well-formed. A derivative is
+ * expected to present the appropriate static attributes and
+ * methods, which can be verified by invoking the contract
+ * enforcement macro (`SIMPLYDT_ENFORCE_CALENDAR_CONTRACT`)
+ * just after the body of the implementation. Failing to have
+ * a compliant API can result in substitution errors or
+ * undefined behavior. Similarly, the provided date
+ * implementation must also satisfy its API requirements to
+ * avoid substitution errors or undefined behavior. This type
+ * is meant to present a stateless API and should not be
+ * constructable. It must be inherited by a concrete
+ * implementation that presents the expected (public) static
+ * API.
+ */
+template
+struct CalendricalSystem {
+ /*! @brief Calendar system base class. */
+ using Base = CalendricalSystem;
+ /*! @brief Calendar date. */
+ using Date = Date_Impl;
+ /*! @brief Calendar year integer type. */
+ using YearInt_t = typename Date::YearInt_t;
+ /*! @brief Calendar date validation policy. */
+ using DatePolicy = typename Date::ValidationPolicy;
+ /*! @brief Enumeration of calendar months. */
+ using Month = Month_Enum;
+ /*! @brief Enumeration of calendar days of week. */
+ using DayOfWeek = DOW_Enum;
+
+ /*!
+ * @brief
+ * Tag indicating timepoint should be interpreted
+ * without local timezone conversion.
+ *
+ * @details
+ * When passed to date conversion functions, this
+ * tag specifies that the input timepoint should
+ * be treated as a raw UTC value rather than being
+ * adjusted for the system's local timezone. This
+ * bypasses the operating system's timezone
+ * database and provides direct calendar date
+ * conversion based solely on the universal time
+ * count since the epoch.
+ */
+ struct NonLocal { };
+
+ /*!
+ * @brief
+ * Returns name of calendar month by its numeric value.
+ *
+ * @details
+ * Expects a 1-based month number (1 = January ... 12 =
+ * December). If the month value is invalid for the
+ * current calendar implementation, the function returns
+ * a predefined invalid string literal. Month names are
+ * sourced from the derived calendar's `MONTH_NAMES` array.
+ *
+ * @return
+ * Calendar month name
+ */
+ [[nodiscard]] static constexpr const char* getMonthName(const uint8_t month) noexcept
+ {
+ if (month == 0 || !Calendar_Impl::isValidMonth(month))
+ return INVALID_LITERAL;
+
+ const uint8_t monthIndex = month - 1;
+ return Calendar_Impl::MONTH_NAMES[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns name of calendar month from its enumeration
+ * representation.
+ *
+ * @details
+ * Accepts a month enumeration constant defined by the
+ * derived calendar implementation. The enumeration is
+ * expected to use zero-based indexing (0 = January ...
+ * 11 = December). If the month value is invalid for the
+ * current calendar, the function returns a predefined
+ * invalid string literal. Month names are sourced from
+ * the derived calendar's `MONTH_NAMES` array.
+ *
+ * @return
+ * Calendar month name
+ */
+ [[nodiscard]] static constexpr const char* getMonthName(const Month month_repr) noexcept
+ {
+ const uint8_t monthIndex = static_cast(month_repr);
+
+ if (!Calendar_Impl::isValidMonth(monthIndex + 1))
+ return INVALID_LITERAL;
+
+ return Calendar_Impl::MONTH_NAMES[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns month name of calendar date.
+ *
+ * @details
+ * Extracts month from calendar defined date implementation
+ * and returns its corresponding month name using the derived
+ * calendar's `MONTH_NAMES` array.
+ *
+ * @return
+ * Calendar month name
+ */
+ [[nodiscard]] static constexpr const char* getMonthName(const Date date) noexcept
+ {
+ const uint8_t monthIndex = date.month() - 1;
+ return Calendar_Impl::MONTH_NAMES[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns abbreviated name of a calendar month by its numeric
+ * value.
+ *
+ * @details
+ * Expects a 1-based month number (1 = January ... 12 = December).
+ * If the month value is invalid for the current calendar
+ * implementation, the function returns a predefined invalid
+ * string literal. Month abbreviations are sourced from the
+ * derived calendar's `MONTH_ABBREVS` array.
+ *
+ * @return
+ * Abbreviated calendar month name
+ */
+ [[nodiscard]] static constexpr std::string_view getMonthAbbrev(const uint8_t month
+ ) noexcept
+ {
+ if (month == 0 || !Calendar_Impl::isValidMonth(month))
+ return std::string_view{INVALID_LITERAL};
+
+ const uint8_t monthIndex = month - 1;
+ return Calendar_Impl::MONTH_ABBREVS[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns abbreviated name of a calendar month from its
+ * enumeration representation.
+ *
+ * @details
+ * Accepts a month enumeration constant defined by the derived
+ * calendar implementation. The enumeration is expected to use
+ * zero-based indexing (0 = January ... 11 = December). If the
+ * month value is invalid for the current calendar, the function
+ * returns a predefined invalid string literal. Month abbreviations
+ * are sourced from the derived calendar's `MONTH_ABBREVS` array.
+ *
+ * @return
+ * Abbreviated calendar month name
+ */
+ [[nodiscard]] static constexpr std::string_view getMonthAbbrev(const Month month_repr
+ ) noexcept
+ {
+ const uint8_t monthIndex = static_cast(month_repr);
+
+ if (!Calendar_Impl::isValidMonth(monthIndex + 1))
+ return std::string_view{INVALID_LITERAL};
+
+ return Calendar_Impl::MONTH_ABBREVS[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns abbreviated month name of calendar date.
+ *
+ * @details
+ * Extracts month from calendar defined date implementation
+ * and returns its corresponding abbreviated month name using
+ * the derived calendar's `MONTH_ABBREVS` array.
+ *
+ * @return
+ * Abbreviated calendar month name
+ */
+ [[nodiscard]] static constexpr std::string_view getMonthAbbrev(const Date date) noexcept
+ {
+ const uint8_t monthIndex = date.month() - 1;
+ return Calendar_Impl::MONTH_ABBREVS[monthIndex];
+ }
+
+ /*!
+ * @brief
+ * Converts a numeric month value to its corresponding
+ * enumeration representation.
+ *
+ * @details
+ * Expects a 1-based month number (1 = January ... 12 =
+ * December). If the value is invalid for the current
+ * calendar implementation, the function returns a fallback
+ * enumeration value (0). The returned value uses zero-based
+ * indexing of the derived calendar's `Month` enumeration.
+ *
+ * @return
+ * Calendar month enum representation
+ */
+ [[nodiscard]] static constexpr Month getMonthEnumRepr(const uint8_t month) noexcept
+ {
+ if (month == 0 || !Calendar_Impl::isValidMonth(month))
+ return static_cast(0); // TODO: Fallback value not acceptable here...
+
+ const uint8_t monthIndex = month - 1;
+ return static_cast(monthIndex);
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date month to its corresponding
+ * enumeration representation.
+ *
+ * @details
+ * Extracts month from calendar defined date implementation and
+ * converts it to the corresponding zero-based `Month`
+ * enumeration defined by the derived calendar implementation.
+ *
+ * @return
+ * Calendar month enum representation
+ */
+ [[nodiscard]] static constexpr Month getMonthEnumRepr(const Date date) noexcept
+ {
+ const uint8_t monthIndex = date.month() - 1;
+ return static_cast(monthIndex);
+ }
+
+ /*!
+ * @brief
+ * Returns name of calendar day-of-week from its enumeration
+ * representation.
+ *
+ * @details
+ * Accepts a day-of-week enumeration constant defined by
+ * the derived calendar implementation. The enumeration
+ * is expected to use zero-based indexing (0 = Sunday ...
+ * 6 = Saturday). If the day-of-week value is invalid for
+ * the current calendar, the function returns a predefined
+ * invalid string literal. Calendar day-of-week names are
+ * sourced from the derived calendar's `DAY_OF_WEEK_NAMES`
+ * array.
+ *
+ * @return
+ * Calendar day-of-week name
+ */
+ [[nodiscard]] static constexpr const char* getDayOfWeekName(const DayOfWeek dow_repr
+ ) noexcept
+ {
+ const uint8_t dowIndex = static_cast(dow_repr);
+
+ if (!Calendar_Impl::isValidDOWIndex(dowIndex))
+ return INVALID_LITERAL;
+
+ return Calendar_Impl::DAY_OF_WEEK_NAMES[dowIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns calendar date day-of-week name.
+ *
+ * @details
+ * Determines day-of-week index of the provided calendar
+ * date by calling the derived calendar implementation
+ * `getDayOfWeekIndex()` method. Returns the corresponding
+ * name from the calendar defined `DAY_OF_WEEK_NAMES`
+ * array, or a predefined invalid string literal if the
+ * date is not valid.
+ *
+ * @return
+ * Calendar day-of-week name
+ */
+ [[nodiscard]] static constexpr const char* getDayOfWeekName(const Date date) noexcept
+ {
+ const uint8_t dowIndex = Calendar_Impl::getDayOfWeekIndex(date);
+ return Calendar_Impl::DAY_OF_WEEK_NAMES[dowIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns abbreviated name of calendar day-of-week from its
+ * enumeration representation.
+ *
+ * @details
+ * Accepts a day-of-week enumeration constant defined by
+ * the derived calendar implementation. The enumeration is
+ * expected to use zero-based indexing (0 = Sunday ... 6 =
+ * Saturday). If the day-of-week value is invalid for the
+ * current calendar, the function returns a predefined
+ * invalid string literal. Day-of-week abbreviations are
+ * sourced from the derived calendar's `DAY_OF_WEEK_ABBREVS`
+ * array.
+ *
+ * @return
+ * Abbreviated calendar day-of-week name
+ */
+ [[nodiscard]] static constexpr std::string_view getDayOfWeekAbbrev(const DayOfWeek dow_repr
+ ) noexcept
+ {
+ const uint8_t dowIndex = static_cast(dow_repr);
+
+ if (!Calendar_Impl::isValidDOWIndex(dowIndex))
+ return std::string_view{INVALID_LITERAL};
+
+ return Calendar_Impl::DAY_OF_WEEK_ABBREVS[dowIndex];
+ }
+
+ /*!
+ * @brief
+ * Returns abbreviated name of calendar day-of-week from its
+ * enumeration representation.
+ *
+ * @details
+ * Determines day-of-week index of the provided calendar
+ * date by calling the derived calendar implementation
+ * `getDayOfWeekIndex()` method. Returns the corresponding
+ * name from the calendar defined `DAY_OF_WEEK_ABBREVS`
+ * array, or a predefined invalid string literal if the
+ * date is not valid.
+ *
+ * @return
+ * Abbreviated calendar day-of-week name
+ */
+ [[nodiscard]] static constexpr std::string_view getDayOfWeekAbbrev(const Date date
+ ) noexcept
+ {
+ if (!Calendar_Impl::isValidDate(date))
+ return std::string_view{INVALID_LITERAL};
+
+ const uint8_t dowIndex = Calendar_Impl::getDayOfWeekIndex(date);
+ return Calendar_Impl::DAY_OF_WEEK_ABBREVS[dowIndex];
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date to its corresponding day-of-week
+ * enumeration representation.
+ *
+ * @details
+ * Validates the given `Date` instance and determines its
+ * day-of-week index using the derived calendar's
+ * `getDayOfWeekIndex()` method. Returns the corresponding
+ * day-of-week enumeration representation using the
+ * `DayOfWeek` enumeration defined by the derived calendar.
+ *
+ * @return
+ * Calendar day-of-week enum representation
+ */
+ [[nodiscard]] static constexpr DayOfWeek getDayOfWeekEnumRepr(const Date date) noexcept
+ {
+ const uint8_t dowIndex = Calendar_Impl::getDayOfWeekIndex(date);
+ return static_cast(dowIndex);
+ }
+
+ /*!
+ * @brief
+ * Create calendar date using a year, month, and day value.
+ *
+ * @brief
+ * Constructs a calendar defined date implementation using
+ * the provided date values. Checks validity of date values
+ * beforehand using the derived calendars `isValidDate()`
+ * method. The method returns a default constructed calendar
+ * date if the provided date values were invalid for the
+ * current calendar.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] inline static constexpr Date getDate(
+ const YearInt_t year, const uint8_t month, const uint8_t day
+ ) noexcept
+ {
+ return Date{year, month, day};
+ }
+
+ /*!
+ * @brief
+ * Create calendar date using a year, month, and day value.
+ *
+ * @brief
+ * Constructs a calendar defined date implementation using
+ * the provided date values. Checks validity of date values
+ * beforehand using the derived calendars `isValidDate()`
+ * method. The method returns a default constructed calendar
+ * date if the provided date values were invalid for the
+ * current calendar. The month enumeration value is converted
+ * to a 1-based numerical month value for calculations.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static constexpr Date getDate(
+ const YearInt_t year, const Month month, const uint8_t day
+ ) noexcept
+ {
+ const uint8_t numericMonth = static_cast(month) + 1;
+ return Date{year, numericMonth, day};
+ }
+
+ /*!
+ * @brief
+ * Create calendar date using local system clock.
+ *
+ * @details
+ * Interprets the given `stl::SystemTimePoint` as local time
+ * by converting it to a Unix timestamp and then populating
+ * a `std::tm` structure using the C++ standard library backed
+ * `stl::deriveLocalDateTimeFromTimestamp()` method. The
+ * resulting year, month, and day fields are used to construct
+ * and return the calendar defined date implementation. If the
+ * local date conversion fails a default constructed calendar
+ * date is returned.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static Date getDate(const stl::SystemTimePoint time_point) noexcept
+ {
+ const stl::UnixTimestamp secsSinceEpoch = stl::SystemClock::to_time_t(time_point);
+ stl::CalendarDateTime dateBuffer{};
+
+ if (!stl::deriveLocalDateTimeFromTimestamp(&secsSinceEpoch, &dateBuffer))
+ return Date{}; // Failed to interpret local date
+
+ return Date{
+ static_cast(
+ dateBuffer.tm_year + 1'900
+ ), // tm_year measures years since 1900
+ static_cast(
+ dateBuffer.tm_mon + 1
+ ), // tm_mon measures months since January
+ static_cast(dateBuffer.tm_mday)
+ };
+ }
+
+ /*!
+ * @brief
+ * Create calendar date using system clock.
+ *
+ * @details
+ * When the `NonLocal` tag struct is supplied, the provided
+ * timepoint is interpreted without the assistance of the
+ * host OS (no time-zone applied). The OS has access to the
+ * necessary system settings that influence local time
+ * interpretation and must be consulted to get the systems
+ * true date (time-zone applied).
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static Date getDate(
+ const stl::SystemTimePoint time_point, const NonLocal
+ ) noexcept
+ {
+ const stl::UnixTimestamp secsSinceEpoch = stl::SystemClock::to_time_t(time_point);
+ return Calendar_Impl::fromUnixTimestamp(secsSinceEpoch);
+ }
+
+ /*!
+ * @brief
+ * Returns next calendar date.
+ *
+ * @details
+ * Increments the provided date by 1 day.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] inline static constexpr Date getNextDate(const Date from_date) noexcept
+ {
+ return from_date + Days{1};
+ }
+
+ /*!
+ * @brief
+ * Finds next calendar date on specified day-of-week.
+ *
+ * @details
+ * This function determines the first calendar date that
+ * falls on the specified day of the week strictly after
+ * the provided `from_date`. The calculation uses the
+ * day-of-week index supplied by the derived calendar
+ * implementation and advances by at least one full week.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static constexpr Date getNextDate(
+ const Date from_date, const DayOfWeek dow_repr
+ ) noexcept
+ {
+ constexpr uint8_t daysInWeek =
+ static_cast(Calendar_Impl::DAY_OF_WEEK_NAMES.size());
+ const int8_t fromDate_dow =
+ static_cast(Calendar_Impl::getDayOfWeekIndex(from_date));
+ const int8_t dowOffset = static_cast(dow_repr) - fromDate_dow;
+ return from_date + Days{dowOffset + daysInWeek};
+ }
+
+ /*!
+ * @brief
+ * Finds next calendar date within specified month.
+ *
+ * @details
+ * This function calculates the next date in the given
+ * `month_repr` relative to the provided `from_date`. If
+ * the target month has not yet occurred in the current
+ * year, the result is the first day of that month within
+ * the same year. If the target month has already passed,
+ * the result is the first day of that month in the
+ * following year. If the `from_date` is already within
+ * the target month, the function advances to the very
+ * next day, unless the date is the last day of the month,
+ * in which case it rolls over to the first day of the
+ * same month in the next year.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static constexpr Date getNextDate(
+ const Date from_date, const Month month_repr
+ ) noexcept
+ {
+ const uint8_t fromNumericMonth = from_date.month();
+ const uint8_t toNumericMonth = static_cast(month_repr) + 1;
+
+ if (fromNumericMonth != toNumericMonth) {
+ if (fromNumericMonth > toNumericMonth) {
+ const YearInt_t nextYear = from_date.year() + 1;
+ return Date{nextYear, toNumericMonth, 1};
+ } else { // fromNumericMonth < toNumericMonth
+ return Date{from_date.year(), toNumericMonth, 1};
+ }
+ }
+
+ const uint8_t daysInMonth =
+ Calendar_Impl::getDaysInMonth(from_date.year(), fromNumericMonth);
+
+ if (from_date.day() != daysInMonth)
+ return from_date + Days{1};
+
+ const YearInt_t nextYear = from_date.year() + 1;
+ return Date{nextYear, fromNumericMonth, 1};
+ }
+
+ /*!
+ * @brief
+ * Returns last calendar date.
+ *
+ * @details
+ * Decrements the provided date by 1 day.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] inline static constexpr Date getLastDate(const Date from_date) noexcept
+ {
+ return from_date - Days{1};
+ }
+
+ /*!
+ * @brief
+ * Finds last calendar date on provided day-of-week.
+ *
+ * @details
+ * This function determines the first calendar date that
+ * falls on the specified day of the week strictly before
+ * the provided `from_date`. The calculation uses the
+ * day-of-week index supplied by the derived calendar
+ * implementation and decreases by at least one full week.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static constexpr Date getLastDate(
+ const Date from_date, const DayOfWeek dow_repr
+ ) noexcept
+ {
+ constexpr uint8_t daysInWeek =
+ static_cast(Calendar_Impl::DAY_OF_WEEK_NAMES.size());
+ const int8_t fromDate_dow =
+ static_cast(Calendar_Impl::getDayOfWeekIndex(from_date));
+ const int8_t dowOffset = fromDate_dow - static_cast(dow_repr);
+ return from_date - Days{dowOffset + daysInWeek};
+ }
+
+ /*!
+ * @brief
+ * Finds last calendar date within specified month.
+ *
+ * @details
+ * This function calculates the last date in the given
+ * `month_repr` relative to the provided `from_date`. If
+ * the target month has not yet occurred in the current
+ * year, the result will be the last day of that month
+ * in the previous year. If the target month has already
+ * passed, the result is the last day of that month in
+ * the same year. If `from_date` is already within the
+ * target month, the function returns the day
+ * immediately preceding it, unless `from_date` is the
+ * first day of the month, in which case it rolls back
+ * to the last day of the same month in the previous year.
+ *
+ * @return
+ * Calendar date
+ */
+ [[nodiscard]] static constexpr Date getLastDate(
+ const Date from_date, const Month month_repr
+ ) noexcept
+ {
+ const uint8_t fromNumericMonth = from_date.month();
+ const uint8_t toNumericMonth = static_cast(month_repr) + 1;
+ uint8_t daysInMonth = Calendar_Impl::getDaysInMonth(from_date.year(), toNumericMonth);
+
+ if (fromNumericMonth != toNumericMonth) {
+ if (fromNumericMonth > toNumericMonth) {
+ return Date{from_date.year(), toNumericMonth, daysInMonth};
+ } else { // fromNumericMonth < toNumericMonth
+ const YearInt_t previousYear = from_date.year() - 1;
+ daysInMonth = Calendar_Impl::getDaysInMonth(previousYear, toNumericMonth);
+ return Date{previousYear, toNumericMonth, daysInMonth};
+ }
+ }
+
+ if (from_date.day() != 1)
+ return from_date - Days{1};
+
+ const YearInt_t previousYear = from_date.year() - 1;
+ daysInMonth = Calendar_Impl::getDaysInMonth(previousYear, toNumericMonth);
+ return Date{previousYear, toNumericMonth, daysInMonth};
+ }
+
+ private:
+ CalendricalSystem() = delete;
+ ~CalendricalSystem() = delete;
+ friend Calendar_Impl;
+};
+
+} // namespace simplydt
+
+#endif // SIMPLYDT_LIB_BASE_CALENDAR_INTERFACE_H_
diff --git a/include/simplydt/calendar/concepts/calendar_api_contract.hpp b/include/simplydt/calendar/concepts/calendar_api_contract.hpp
new file mode 100644
index 0000000..fe2ff98
--- /dev/null
+++ b/include/simplydt/calendar/concepts/calendar_api_contract.hpp
@@ -0,0 +1,65 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file calendar_api_contract.hpp
+ *
+ * @brief
+ * Conceptual calendar implementation contract.
+ */
+
+
+#ifndef SIMPLYDT_LIB_CALENDAR_CONTRACT_CONCEPT_H_
+#define SIMPLYDT_LIB_CALENDAR_CONTRACT_CONCEPT_H_
+
+#include "simplydt/calendar/concepts/calendar_concepts.hpp"
+#include "simplydt/calendar/concepts/date_api_contract.hpp"
+
+namespace simplydt::concepts
+{
+
+/*!
+ * @brief
+ * Concept of a type that meets the criteria to be
+ * considered a useable calendar implementation.
+ *
+ * @details
+ * A valid calendar type must provide contextual
+ * nested types for library integration and utilize
+ * a date type that satisfies the date contract.
+ * It must include characteristic members defining
+ * calendar properties, name arrays for month and
+ * day identification, and comprehensive structure
+ * validation and query methods. The implementation
+ * must support date queries, standard date
+ * conversion operations, and calendar naming
+ * utilities, through static members.
+ */
+template
+concept contract_abiding_calendar = requires {
+ requires calendar::has_contextual_nested_types;
+ requires contract_abiding_date;
+ requires calendar::has_characteristic_members;
+ requires calendar::has_calendar_name_arrays;
+ requires calendar::has_structure_validation_methods;
+ requires calendar::has_structure_query_methods;
+ requires calendar::has_date_query_methods;
+ requires calendar::has_standard_date_conversion_methods;
+ requires calendar::has_name_methods;
+};
+
+#ifndef SIMPLYDT_ENFORCE_CALENDAR_CONTRACT
+/*! @brief Macro for asserting calendar implementation interface contract. */
+# define SIMPLYDT_ENFORCE_CALENDAR_CONTRACT(Class) \
+ static_assert( \
+ simplydt::concepts::contract_abiding_calendar, \
+ #Class " implementation does not fulfill the public API contract." \
+ )
+#endif
+
+} // namespace simplydt::concepts
+
+#endif // SIMPLYDT_LIB_CALENDAR_CONTRACT_CONCEPT_H_
diff --git a/include/simplydt/calendar/concepts/calendar_concepts.hpp b/include/simplydt/calendar/concepts/calendar_concepts.hpp
new file mode 100644
index 0000000..2b60275
--- /dev/null
+++ b/include/simplydt/calendar/concepts/calendar_concepts.hpp
@@ -0,0 +1,293 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file calendar_concepts.hpp
+ *
+ * @brief
+ * Agnostic calendar concepts.
+ */
+
+
+#ifndef SIMPLYDT_LIB_CALENDAR_CONCEPTS_H_
+#define SIMPLYDT_LIB_CALENDAR_CONCEPTS_H_
+
+#include "simplydt/calendar/concepts/date_concepts.hpp"
+#include "simplydt/common/calendar_defs.hpp"
+#include "simplydt/common/stl_chrono_defs.hpp"
+#include
+
+/*!
+ * @namespace simplydt::concepts::calendar
+ *
+ * @brief
+ * Calendar concepts.
+ */
+namespace simplydt::concepts::calendar
+{
+
+template
+concept has_contextual_nested_types = requires {
+ typename Calendar_Impl::YearInt_t;
+ typename Calendar_Impl::Date;
+ typename Calendar_Impl::Month;
+ typename Calendar_Impl::DayOfWeek;
+ typename Calendar_Impl::DatePolicy;
+ typename Calendar_Impl::NonLocal;
+};
+
+template
+concept has_characteristic_members = requires {
+ { Calendar_Impl::calendar } -> std::same_as;
+ { Calendar_Impl::isSolarCalendar } -> std::same_as;
+ { Calendar_Impl::isLunarCalendar } -> std::same_as;
+ { Calendar_Impl::isLunisolarCalendar } -> std::same_as;
+};
+
+template
+concept has_calendar_name_arrays = requires {
+ {
+ Calendar_Impl::MONTH_NAMES
+ } -> std::same_as>>&>;
+
+ {
+ Calendar_Impl::MONTH_ABBREVS
+ } -> std::same_as>>&>;
+
+ {
+ Calendar_Impl::DAY_OF_WEEK_NAMES
+ } -> std::same_as>>&>;
+
+ {
+ Calendar_Impl::DAY_OF_WEEK_ABBREVS
+ } -> std::same_as>>&>;
+};
+
+template
+concept has_structure_validation_methods = requires {
+ {
+ Calendar_Impl::isValidYear(std::declval())
+ } -> std::same_as;
+
+ { Calendar_Impl::isValidMonth(std::declval()) } -> std::same_as;
+ { Calendar_Impl::isValidDay(std::declval()) } -> std::same_as;
+ { Calendar_Impl::isValidDOWIndex(std::declval()) } -> std::same_as;
+ { Calendar_Impl::isValidWeekIndex(std::declval()) } -> std::same_as;
+
+ {
+ Calendar_Impl::isValidDate(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+};
+
+template
+concept has_structure_query_methods = requires {
+ {
+ Calendar_Impl::getDaysInYear(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDaysInMonth(
+ std::declval(), std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getWeeksInMonth(
+ std::declval(), std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getWeeksMonthSpans(
+ std::declval(), std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getWeekIndex(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekIndex(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthEnumRepr(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthEnumRepr(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekEnumRepr(std::declval())
+ } -> std::same_as;
+};
+
+template
+concept has_date_query_methods = requires {
+ {
+ Calendar_Impl::getDate(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDate(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDate(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDate(
+ std::declval(), typename Calendar_Impl::NonLocal{}
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getNextDate(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getNextDate(
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getNextDate(
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getLastDate(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getLastDate(
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getLastDate(
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ // TODO: Add `Calendar_Impl::getWeek()` at some point...
+ // (Requires generic `WeekDates` container alias)
+};
+
+template
+concept has_standard_date_conversion_methods = requires {
+ {
+ Calendar_Impl::toDaysSinceEpoch(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::fromDaysSinceEpoch(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::toUnixTimestamp(
+ std::declval(),
+ std::declval(),
+ std::declval()
+ )
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::fromUnixTimestamp(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::fromUnixTimestamp(std::declval())
+ } -> std::same_as;
+};
+
+template
+concept has_name_methods = requires {
+ { Calendar_Impl::getMonthName(std::declval()) } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthName(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthName(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthAbbrev(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthAbbrev(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getMonthAbbrev(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekName(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekName(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekAbbrev(std::declval())
+ } -> std::same_as;
+
+ {
+ Calendar_Impl::getDayOfWeekAbbrev(std::declval())
+ } -> std::same_as;
+};
+
+} // namespace simplydt::concepts::calendar
+
+#endif // SIMPLYDT_LIB_CALENDAR_CONCEPTS_H_
diff --git a/include/simplydt/calendar/concepts/date_api_contract.hpp b/include/simplydt/calendar/concepts/date_api_contract.hpp
new file mode 100644
index 0000000..049d067
--- /dev/null
+++ b/include/simplydt/calendar/concepts/date_api_contract.hpp
@@ -0,0 +1,66 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file date_api_contract.hpp
+ *
+ * @brief
+ * Conceptual calendar date implementation contract.
+ */
+
+
+#ifndef SIMPLYDT_LIB_CALENDAR_DATE_CONTRACT_CONCEPT_H_
+#define SIMPLYDT_LIB_CALENDAR_DATE_CONTRACT_CONCEPT_H_
+
+#include "simplydt/calendar/concepts/date_concepts.hpp"
+
+namespace simplydt::concepts
+{
+
+/*!
+ * @brief
+ * Concept of a type that meets the criteria to be
+ * considered a useable calendar date implementation.
+ *
+ * @details
+ * A valid date type must provide contextual nested
+ * types (for library internal-use), integer-based
+ * year representation, and component accessors for
+ * date parts. It must support logical and arithmetic
+ * operators, basic state and sequential evaluation
+ * methods, as well as stream output and string
+ * conversion utilities. In addition, it must satisfy
+ * fundamental C++ type requirements including default
+ * initialization, copyability, and destructibility.
+ */
+template
+concept contract_abiding_date = requires {
+ requires date::has_contextual_nested_types;
+ requires std::is_integral_v;
+ requires date::has_date_component_methods;
+ requires date::has_logical_operators;
+ requires date::has_arithmetic_operators;
+ requires date::has_basic_state_methods;
+ requires date::has_sequential_evaluation_methods;
+ requires date::is_stream_out_compatible;
+ requires date::has_date_string_methods;
+ requires std::default_initializable;
+ requires std::copyable;
+ requires std::destructible;
+};
+
+} // namespace simplydt::concepts
+
+#ifndef SIMPLYDT_ENFORCE_DATE_CONTRACT
+/*! @brief Macro for asserting date interface implementation contract. */
+# define SIMPLYDT_ENFORCE_DATE_CONTRACT(Class) \
+ static_assert( \
+ simplydt::concepts::contract_abiding_date, \
+ #Class " implementation does not fulfill the public API contract." \
+ )
+#endif
+
+#endif // SIMPLYDT_LIB_CALENDAR_DATE_CONTRACT_CONCEPT_H_
diff --git a/include/simplydt/calendar/concepts/date_concepts.hpp b/include/simplydt/calendar/concepts/date_concepts.hpp
new file mode 100644
index 0000000..ea281e6
--- /dev/null
+++ b/include/simplydt/calendar/concepts/date_concepts.hpp
@@ -0,0 +1,106 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file date_concepts.hpp
+ *
+ * @brief
+ * Agnostic calendar date concepts.
+ */
+
+
+#ifndef SIMPLYDT_LIB_CALENDAR_DATE_CONCEPTS_H_
+#define SIMPLYDT_LIB_CALENDAR_DATE_CONCEPTS_H_
+
+#include "simplydt/time/units/time_units.hpp"
+#include
+#include
+#include
+
+/*!
+ * @namespace simplydt::concepts
+ *
+ * @brief
+ * Simply Datetime library concepts.
+ */
+namespace simplydt::concepts
+{ }
+
+/*!
+ * @namespace simplydt::concepts::date
+ *
+ * @brief
+ * Calendar date concepts.
+ */
+namespace simplydt::concepts::date
+{
+
+template
+concept has_date_component_methods = requires(const Date_Impl& d) {
+ { d.year() } -> std::same_as;
+ { d.month() } -> std::same_as;
+ { d.day() } -> std::same_as;
+};
+
+template
+concept has_logical_operators = requires(const Date_Impl& d) {
+ { d == d } -> std::same_as;
+ { d < d } -> std::same_as;
+ { d > d } -> std::same_as;
+ { d <= d } -> std::same_as;
+ { d >= d } -> std::same_as;
+};
+
+template
+concept has_arithmetic_operators = requires(Date_Impl& d, simplydt::Days days) {
+ { d + days } -> std::same_as;
+ { d - days } -> std::same_as;
+ { d - d } -> std::same_as;
+ { d += days } -> std::same_as;
+ { d -= days } -> std::same_as;
+ { ++d } -> std::same_as;
+ { d++ } -> std::same_as;
+ { --d } -> std::same_as;
+ { d-- } -> std::same_as;
+};
+
+template
+concept has_basic_state_methods = requires(const Date_Impl& d) {
+ { d.isZero() } -> std::same_as;
+ { d.underlying() } -> std::same_as;
+ { d.units() } -> std::same_as;
+};
+
+template
+concept is_stream_out_compatible = requires(std::ostream& os, const Date_Impl& d) {
+ { os << d } -> std::convertible_to;
+};
+
+template
+concept has_sequential_evaluation_methods = requires(const Date_Impl& d) {
+ { d.isBefore(d) } -> std::same_as;
+ { d.isAfter(d) } -> std::same_as;
+ { d.isBetween(d, d) } -> std::same_as;
+ { d.daysUntil(d) } -> std::same_as;
+};
+
+template
+concept has_date_string_methods = requires(const Date_Impl& d) {
+ //_// { d.monthStr() } -> std::same_as;
+ //_// { d.monthAbbrev() } -> std::same_as;
+ { d.toStr() } -> std::same_as;
+};
+
+template
+concept has_contextual_nested_types = requires {
+ typename Date_Impl::Repr_Type;
+ typename Date_Impl::YearInt_t;
+ typename Date_Impl::ValidationPolicy;
+};
+
+} // namespace simplydt::concepts::date
+
+#endif // SIMPLYDT_LIB_CALENDAR_DATE_CONCEPTS_H_
diff --git a/include/simplydt/calendar/date/abstract_date.hpp b/include/simplydt/calendar/date/abstract_date.hpp
new file mode 100644
index 0000000..8219e0e
--- /dev/null
+++ b/include/simplydt/calendar/date/abstract_date.hpp
@@ -0,0 +1,356 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file abstract_date.hpp
+ *
+ * @brief
+ * Base serial calendar date interface declaration.
+ */
+
+
+#ifndef SIMPLYDT_LIB_BASE_SERIAL_CALENDAR_DATE_INTERFACE_H_
+#define SIMPLYDT_LIB_BASE_SERIAL_CALENDAR_DATE_INTERFACE_H_
+
+#include "simplydt/time/units/time_units.hpp"
+#include
+#include
+
+namespace simplydt
+{
+
+/*!
+ * @brief
+ * Base calendar date interface.
+ *
+ * @details
+ * This is the foundational interface for serial calendar
+ * dates in Simply Datetime. It is agnostic of any specific
+ * calendar and allows derivatives to define their own
+ * implementation. Note that the assumption is made that
+ * the calendar model in question utilizes year, month,
+ * and day values to describe a date in time. This type
+ * is not meant to have calendar knowledge, its purpose
+ * is to point to a valid date on the calendar it is
+ * designed for. Simply Datetime relies on the object
+ * invariant that any constructed instance of this type
+ * represents a valid calendar date. Each implementation is
+ * responsible for enforcing this invariant to prevent bugs
+ * and undefined behavior. This structure timekeeps dates
+ * using a serial count of days relative to some epoch date.
+ * The provided underlying serial date representation type
+ * `Repr_T` is initialized in this base class but can also
+ * be accessed by the derived calendar date implementation.
+ * The class hierarchy implements the CRTP design pattern
+ * which allows this base to reference the derivative.
+ * Consequently, the convenience methods defined in this
+ * base structure depend on the concrete calendar dates
+ * public API for them to be well-formed. A derivative is
+ * expected to present the appropriate attributes and
+ * methods, which can be verified by invoking the contract
+ * enforcement macro (`SIMPLYDT_ENFORCE_DATE_CONTRACT`)
+ * just after the body of the implementation. Failing to
+ * have a compliant API can result in substitution errors
+ * or undefined behavior. This is not a self-constructable
+ * type, it must be inherited by a concrete implementation
+ * that presents the expected public API.
+ */
+template
+struct SerialCalendarDate {
+ /*! @brief Calendar date base class. */
+ using Base = SerialCalendarDate;
+ /*! @brief Calendar date validation policy. */
+ using ValidationPolicy = Validation_Policy;
+ /*! @brief Underlying serial date type. */
+ using Repr_Type = Repr_T;
+ /*! @brief Year integer type. */
+ using YearInt_t = Year_T;
+
+ /*! @brief Puts human-readable date string in output stream. */
+ friend inline std::ostream& operator<<(std::ostream& os, const Base& serial_date) noexcept
+ {
+ os << serial_date.derivedImpl().toStr();
+ return os;
+ }
+
+ /*! @brief Evaluates equivalence of calendar dates. */
+ [[nodiscard]] constexpr bool operator==(const Base& serial_date) const noexcept
+ {
+ return this->serialDays == serial_date.serialDays;
+ }
+
+ /*! @brief Determines if left-hand side is sequentially before right-hand side. */
+ [[nodiscard]] constexpr bool operator<(const Base& serial_date) const noexcept
+ {
+ return this->serialDays < serial_date.serialDays;
+ }
+
+ /*! @brief Determines if left-hand side is sequentially after right-hand side. */
+ [[nodiscard]] constexpr bool operator>(const Base& serial_date) const noexcept
+ {
+ return this->serialDays > serial_date.serialDays;
+ }
+
+ [[nodiscard]] constexpr bool operator<=(const Base& serial_date) const noexcept
+ {
+ return this->serialDays <= serial_date.serialDays;
+ }
+
+ [[nodiscard]] constexpr bool operator>=(const Base& serial_date) const noexcept
+ {
+ return this->serialDays >= serial_date.serialDays;
+ }
+
+ /*! @brief Returns this calendar date with provided amount of days added. */
+ [[nodiscard]] constexpr Date_Impl operator+(const Days days) const noexcept
+ {
+ Date_Impl displacedDate{this->derivedImpl()};
+ displacedDate.serialDays += days.count();
+ return displacedDate;
+ // TODO: This method is not safe nor complete...
+ // ('days' can underflow or overflow 'serialDays')
+ }
+
+ /*! @brief Returns this calendar date with provided amount of days subtracted. */
+ [[nodiscard]] constexpr Date_Impl operator-(const Days days) const noexcept
+ {
+ Date_Impl displacedDate{this->derivedImpl()};
+ displacedDate.serialDays -= days.count();
+ return displacedDate;
+ // TODO: This method is not safe nor complete...
+ // ('days' can underflow or overflow 'serialDays')
+ }
+
+ /*! @brief Calculates number of days between calendar dates. */
+ [[nodiscard]] constexpr Days operator-(const Date_Impl date) const noexcept
+ {
+ return Days{this->serialDays - date.serialDays};
+ }
+
+ /*!
+ * @brief
+ * Increments calendar date one day.
+ *
+ * @return
+ * Reference to self
+ */
+ Date_Impl& operator++() noexcept
+ {
+ this->serialDays += 1;
+ return static_cast(*this);
+ // TODO: This method is not safe nor complete...
+ // ('this->serialDays' can overflow)
+ }
+
+ /*!
+ * @brief
+ * Increments calendar date one day.
+ *
+ * @return
+ * Copy of previous calendar date
+ */
+ [[nodiscard]] Date_Impl operator++(int) noexcept
+ {
+ Date_Impl previousDate{this->derivedImpl()};
+ this->serialDays += 1;
+ return previousDate;
+ // TODO: This method is not safe nor complete...
+ // ('this->serialDays' can overflow)
+ }
+
+ /*! @brief Adds provided amount of days to calendar date. */
+ Date_Impl& operator+=(const Days days) noexcept
+ {
+ this->serialDays += days.count();
+ return static_cast(*this);
+ // TODO: This method is not safe nor complete...
+ // ('days' can underflow or overflow 'this->serialDays')
+ }
+
+ /*!
+ * @brief
+ * Decrements calendar date one day.
+ *
+ * @return
+ * Reference to self
+ */
+ Date_Impl& operator--() noexcept
+ {
+ this->serialDays -= 1;
+ return static_cast(*this);
+ // TODO: This method is not safe nor complete...
+ // ('this->serialDays' can underflow)
+ }
+
+ /*!
+ * @brief
+ * Decrements calendar date one day.
+ *
+ * @return
+ * Copy of previous calendar date
+ */
+ [[nodiscard]] Date_Impl operator--(int) noexcept
+ {
+ Date_Impl previousDate{this->derivedImpl()};
+ this->serialDays -= 1;
+ return previousDate;
+ // TODO: This method is not safe nor complete...
+ // ('this->serialDays' can underflow)
+ }
+
+ /*! @brief Subtracts provided amount of days from calendar date. */
+ Date_Impl& operator-=(const Days days) noexcept
+ {
+ this->serialDays -= days.count();
+ return static_cast(*this);
+ // TODO: This method is not safe nor complete...
+ // ('days' can underflow or overflow 'this->serialDays')
+ }
+
+ /*!
+ * @brief
+ * Determines if calendar date is epoch date.
+ *
+ * @return
+ * True if serial day count is zero
+ */
+ [[nodiscard]] constexpr bool isZero() const noexcept
+ {
+ return this->serialDays == 0;
+ }
+
+ /*!
+ * @brief
+ * Determines if date is sequentially before provided
+ * date.
+ *
+ * @return
+ * True if this date occurs before provided
+ */
+ [[nodiscard]] constexpr bool isBefore(const Date_Impl date) const noexcept
+ {
+ return this->serialDays < date.serialDays;
+ }
+
+ /*!
+ * @brief
+ * Determines if date is sequentially after provided
+ * date.
+ *
+ * @return
+ * True if this date occurs after provided
+ */
+ [[nodiscard]] constexpr bool isAfter(const Date_Impl date) const noexcept
+ {
+ return this->serialDays > date.serialDays;
+ }
+
+ /*!
+ * @brief
+ * Checks if this date falls within a specified
+ * date range.
+ *
+ * @details
+ * This function compares the serial day count of
+ * the current date instance against two provided
+ * dates, expressed in the same serial-day format.
+ * The comparison is inclusive, meaning the
+ * function returns true if this date is equal to
+ * either boundary date or lies strictly between
+ * them.
+ *
+ * @return
+ * True if date lies within inclusive date range
+ */
+ [[nodiscard]] constexpr bool isBetween(
+ const Date_Impl start_date, const Date_Impl end_date
+ ) const noexcept
+ {
+ return start_date.serialDays <= this->serialDays &&
+ this->serialDays <= end_date.serialDays;
+ }
+
+ /*!
+ * @brief
+ * Calculates day difference between dates.
+ *
+ * @details
+ * This function calculates the signed number of
+ * days from the current date instance to the
+ * specified `date`. A positive result indicates
+ * that the given `date` occurs after this date,
+ * while a negative result indicates it occurs
+ * before.
+ *
+ * @return
+ * Days from this date to provided
+ */
+ [[nodiscard]] constexpr Days daysUntil(const Date_Impl date) const noexcept
+ {
+ return Days{date.serialDays - this->serialDays};
+ }
+
+ /*!
+ * @brief
+ * Returns serial calendar date as explicit units
+ * of precision.
+ *
+ * @details
+ * This function exposes the underlying serial day
+ * count of the current date instance, wrapped in
+ * `Days` units. The value represents the total
+ * number of days elapsed since the calendar's
+ * defined epoch date.
+ *
+ * @return
+ * Serial day count
+ */
+ [[nodiscard]] constexpr Days units() const noexcept
+ {
+ return Days{this->serialDays};
+ }
+
+ /*!
+ * @brief
+ * Returns constant reference to underlying serial
+ * day count.
+ *
+ * @return
+ * Constant reference to serial day count
+ */
+ [[nodiscard]] constexpr const Repr_Type& underlying() const noexcept
+ {
+ return this->serialDays;
+ }
+
+ private:
+ Repr_Type serialDays; ///< Serial day count
+
+ /*! @brief Construct calendar date with serial day count. */
+ constexpr SerialCalendarDate(const Repr_Type serialDayCount) noexcept
+ : serialDays{serialDayCount}
+ { }
+
+ ~SerialCalendarDate() = default;
+ friend Date_Impl;
+
+ /*!
+ * @brief
+ * Returns constant reference to this concrete derivative.
+ *
+ * @note
+ * Do not call this from the derived class, YOU are the
+ * `derivedImpl()` (a.k.a `this`)
+ */
+ [[nodiscard]] constexpr const Date_Impl& derivedImpl() const noexcept
+ {
+ return static_cast(*this);
+ }
+};
+
+} // namespace simplydt
+
+#endif // SIMPLYDT_LIB_BASE_SERIAL_CALENDAR_DATE_INTERFACE_H_
diff --git a/include/simplydt/calendar/gregorian/date_validation.hpp b/include/simplydt/calendar/gregorian/date_validation.hpp
new file mode 100644
index 0000000..150bd64
--- /dev/null
+++ b/include/simplydt/calendar/gregorian/date_validation.hpp
@@ -0,0 +1,162 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file date_validation.hpp
+ *
+ * @brief
+ * Gregorian calendar date validation policy declaration.
+ */
+
+
+#ifndef SIMPLYDT_LIB_GREGORIAN_DATE_VALIDATION_POLICY_H_
+#define SIMPLYDT_LIB_GREGORIAN_DATE_VALIDATION_POLICY_H_
+
+#include "simplydt/calendar/gregorian/gregorian_defs.hpp"
+#include
+
+namespace simplydt::gregorian
+{
+
+/*!
+ * @brief
+ * Gregorian calendar date validation policy.
+ *
+ * @details
+ * This is the Gregorian calendar date validator, which is
+ * responsible for determining if a given set of date params
+ * describe a real date on the Gregorian calendar. This
+ * structure serves no purpose beyond validating potential
+ * Gregorian calendar dates and only maintains functions
+ * necessarry for validation.
+ */
+struct DateValidationPolicy {
+ /*!
+ * @brief
+ * Determines if provided year is a leap year.
+ *
+ * @details
+ * This function checks if the specified year qualifies
+ * as a leap year under Gregorian calendar rules. A year
+ * is considered a leap year if it is divisible by 4,
+ * except for years divisible by 100 unless it is also
+ * divisible by 400.
+ *
+ * @return
+ * True if leap year
+ */
+ [[nodiscard]] inline static constexpr bool isLeapYear(const Year_Type year) noexcept
+ {
+ return (year % 4) == 0 && (year % 100 != 0 || year % YEARS_IN_ERA == 0);
+ }
+
+ /*!
+ * @brief
+ * Evaluates support of year value.
+ *
+ * @details
+ * This function returns true if the given year falls
+ * within the inclusive bounds defined by `YEAR_MINIMUM`
+ * and `YEAR_MAXIMUM` for the Gregorian calendar system.
+ *
+ * @return
+ * True if supported year
+ */
+ [[nodiscard]] inline static constexpr bool isValidYear(const Year_Type year) noexcept
+ {
+ return year >= YEAR_MINIMUM && year <= YEAR_MAXIMUM;
+ }
+
+ /*!
+ * @brief
+ * Checks if a month value is within valid range.
+ *
+ * @details
+ * This function returns true if the given month falls
+ * within the inclusive bounds defined by
+ * `MIN_MONTH_OF_YEAR` and `MAX_MONTH_OF_YEAR` for the
+ * Gregorian calendar system.
+ *
+ * @return
+ * True if valid numerical month
+ */
+ [[nodiscard]] inline static constexpr bool isValidMonth(const uint8_t month) noexcept
+ {
+ return month >= MIN_MONTH_OF_YEAR && month <= MAX_MONTH_OF_YEAR;
+ }
+
+ /*!
+ * @brief
+ * Calculates total number of days in a given month of
+ * a specified year.
+ *
+ * @details
+ * This function handles the varying lengths of months
+ * in the Gregorian calendar, including the special
+ * case of February during a leap year. The function
+ * first validates the year and month; if either is
+ * invalid, it returns 0 to indicate an unsupported or
+ * invalid date value.
+ *
+ * @return
+ * Total days in month
+ */
+ [[nodiscard]] static constexpr uint8_t getDaysInMonth(
+ const Year_Type year, const uint8_t month
+ ) noexcept
+ {
+ if (!isValidYear(year) || !isValidMonth(month))
+ return 0; // Unsupported or invalid
+
+ switch (month) {
+ case February:
+ switch (isLeapYear(year)) {
+ case true:
+ return 29;
+ default:
+ return 28;
+ }
+
+ case April:
+ case June:
+ case September:
+ case November:
+ return 30;
+
+ // January, March, May, July, August, October, December
+ default:
+ return 31;
+ }
+ }
+
+ /*!
+ * @brief
+ * Checks if given date values form a valid Gregorian
+ * date.
+ *
+ * @details
+ * This function returns true when the provided date
+ * parameters describe a real date on the Gregorian
+ * calendar. This is achieved by comparing the dates
+ * day to the total number of days in the month. If
+ * the provided year is not supported, the function
+ * returns false.
+ *
+ * @return
+ * True if date exists on calendar
+ */
+ [[nodiscard]] static constexpr bool isValidDate(
+ const Year_Type year, const uint8_t month, const uint8_t day
+ ) noexcept
+ {
+ const uint8_t monthTotalDays = getDaysInMonth(year, month);
+ return monthTotalDays != 0 && day != 0 && day <= monthTotalDays;
+ }
+};
+
+} // namespace simplydt::gregorian
+
+#endif // SIMPLYDT_LIB_GREGORIAN_DATE_VALIDATION_POLICY_H_
diff --git a/include/simplydt/calendar/gregorian/gregorian_calendar.hpp b/include/simplydt/calendar/gregorian/gregorian_calendar.hpp
new file mode 100644
index 0000000..b3ffb9b
--- /dev/null
+++ b/include/simplydt/calendar/gregorian/gregorian_calendar.hpp
@@ -0,0 +1,952 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file gregorian_calendar.hpp
+ *
+ * @brief
+ * Gregorian calendar declaration.
+ */
+
+
+#ifndef SIMPLYDT_LIB_GREGORIAN_CALENDAR_H_
+#define SIMPLYDT_LIB_GREGORIAN_CALENDAR_H_
+
+#include "simplydt/calendar/abstract_calendar.hpp"
+#include "simplydt/calendar/concepts/calendar_api_contract.hpp"
+#include "simplydt/calendar/gregorian/gregorian_date.hpp"
+
+namespace simplydt::gregorian
+{
+
+/*!
+ * @brief
+ * Gregorian calendar system.
+ *
+ * @details
+ * TODO: INCOMPLETE COMMENT!!!
+ */
+struct GregorianCalendar :
+ public CalendricalSystem {
+ /*! @brief Array of dates in one calendar week. */
+ using WeekDates = std::array;
+
+ /*!
+ * @brief
+ * Identifies calendar system represented by
+ * this implementation.
+ */
+ static constexpr CalendarSystem calendar = CalendarSystem::GREGORIAN;
+
+ /*!
+ * @brief
+ * Indicates whether calendar system is
+ * solar-based.
+ *
+ * @details
+ * This constant specifies that the Gregorian
+ * calendar system follows a solar model, where
+ * date progression is based on the Earth's
+ * orbit around the Sun.
+ */
+ static constexpr bool isSolarCalendar = true;
+
+ /*!
+ * @brief
+ * Indicates whether calendar system is
+ * lunar-based.
+ *
+ * @details
+ * This constant specifies that the Gregorian
+ * calendar system does not follow a lunar
+ * model, which bases months on the phases of
+ * the Moon.
+ */
+ static constexpr bool isLunarCalendar = false;
+
+ /*!
+ * @brief
+ * Indicates whether calendar system is
+ * lunisolar-based.
+ *
+ * @details
+ * This constant specifies that the Gregorian
+ * calendar system does not follow a lunisolar
+ * model, which combines solar and lunar cycles
+ * to structure months and years.
+ */
+ static constexpr bool isLunisolarCalendar = false;
+
+ /*!
+ * @brief
+ * Full names of Gregorian calendar months.
+ */
+ static constexpr inline const std::array& MONTH_NAMES =
+ Months;
+
+ /*!
+ * @brief
+ * Abbreviated names of Gregorian calendar
+ * months.
+ */
+ static constexpr inline const std::array& MONTH_ABBREVS =
+ MonthAbbrevs;
+
+ /*!
+ * @brief
+ * Full names of Gregorian calendar
+ * days-of-week.
+ */
+ static constexpr inline const std::array& DAY_OF_WEEK_NAMES =
+ DaysOfWeek;
+
+ /*!
+ * @brief
+ * Abbreviated names of Gregorian calendar
+ * days-of-week.
+ */
+ static constexpr inline const std::array&
+ DAY_OF_WEEK_ABBREVS = DayOfWeekAbbrevs;
+
+ /*!
+ * @brief
+ * Evaluate support of year value.
+ *
+ * @details
+ * This function returns true if the given year
+ * falls within the inclusive bounds defined by
+ * `YEAR_MINIMUM` and `YEAR_MAXIMUM` for the
+ * Gregorian calendar system.
+ *
+ * @return
+ * True if supported year value
+ */
+ [[nodiscard]] static constexpr bool isValidYear(const YearInt_t year) noexcept
+ {
+ return DatePolicy::isValidYear(year);
+ }
+
+ /*!
+ * @brief
+ * Determines whether a given year is a leap year.
+ *
+ * @details
+ * This function checks if the specified year
+ * qualifies as a leap year under Gregorian
+ * calendar rules. A year is considered a leap
+ * year if it is divisible by 4, except for
+ * years divisible by 100 unless it is also
+ * divisible by 400.
+ *
+ * @return
+ * True if leap year
+ */
+ [[nodiscard]] static constexpr bool isLeapYear(const YearInt_t year) noexcept
+ {
+ return DatePolicy::isLeapYear(year);
+ }
+
+ /*!
+ * @brief
+ * Determines whether a date is within a leap
+ * year.
+ *
+ * @return
+ * True if leap year
+ */
+ [[nodiscard]] static constexpr bool isLeapYear(const Date date) noexcept
+ {
+ return DatePolicy::isLeapYear(date.year());
+ }
+
+ /*!
+ * @brief
+ * Returns total number of days in a given
+ * calendar year.
+ *
+ * @details
+ * Determines whether the specified year is a
+ * leap year and returns `DAYS_IN_LEAP_YEAR` or
+ * `DAYS_IN_YEAR` accordingly. If the year is
+ * unsupported the function returns 0.
+ *
+ * @return
+ * Total days in year
+ */
+ [[nodiscard]] static constexpr uint16_t getDaysInYear(const YearInt_t year) noexcept
+ {
+ if (!DatePolicy::isValidYear(year))
+ return 0; // Unsupported year
+
+ return DatePolicy::isLeapYear(year) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
+ }
+
+ /*!
+ * @brief
+ * Returns total number of days in a given
+ * calendar year.
+ *
+ * @details
+ * Extracts the year from the provided `Date`
+ * to determine the total number of days in
+ * the year.
+ *
+ * @return
+ * Total days in year
+ */
+ [[nodiscard]] static constexpr uint16_t getDaysInYear(const Date date) noexcept
+ {
+ return DatePolicy::isLeapYear(date.year()) ? DAYS_IN_LEAP_YEAR : DAYS_IN_YEAR;
+ }
+
+ /*!
+ * @brief
+ * Checks if numerical month value is within
+ * valid range.
+ *
+ * @details
+ * This function returns true if the given
+ * month falls within the inclusive bounds
+ * defined by `MIN_MONTH_OF_YEAR` and
+ * `MAX_MONTH_OF_YEAR` for the Gregorian
+ * calendar system.
+ *
+ * @return
+ * True if valid numerical month
+ */
+ [[nodiscard]] static constexpr bool isValidMonth(const uint8_t month) noexcept
+ {
+ return DatePolicy::isValidMonth(month);
+ }
+
+ /*!
+ * @brief
+ * Returns total number of days in a given
+ * month of a specified year.
+ *
+ * @details
+ * This function handles the varying lengths of
+ * months in the Gregorian calendar, including
+ * the special case of February during a leap
+ * year. The function first validates the year
+ * and month; if either is invalid, it returns 0
+ * to indicate an unsupported or invalid date
+ * component.
+ *
+ * @return
+ * Total days in month
+ */
+ [[nodiscard]] static constexpr uint8_t getDaysInMonth(
+ const YearInt_t year, const uint8_t month
+ ) noexcept
+ {
+ return DatePolicy::getDaysInMonth(year, month);
+ }
+
+ /*!
+ * @brief
+ * Returns total number of days within month of
+ * a given date.
+ *
+ * @details
+ * Extracts the year and month from the provided
+ * `Date` to determine the total number of days
+ * in the dates month.
+ *
+ * @return
+ * Total days in month
+ */
+ [[nodiscard]] static constexpr uint8_t getDaysInMonth(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return DatePolicy::getDaysInMonth(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents) // Month
+ );
+ }
+
+ /*!
+ * @brief
+ * Checks if day value is within valid range.
+ *
+ * @details
+ * This function returns true if the given day
+ * falls within the inclusive bounds defined by
+ * `MIN_DAY_OF_MONTH` and `MAX_DAY_OF_MONTH` for
+ * the Gregorian calendar system.
+ *
+ * @return
+ * True if valid day value
+ */
+ [[nodiscard]] inline static constexpr bool isValidDay(const uint8_t day) noexcept
+ {
+ return day >= MIN_DAY_OF_MONTH && day <= MAX_DAY_OF_MONTH;
+ }
+
+ /*!
+ * @brief
+ * Checks if week index is within valid range.
+ *
+ * @details
+ * Checks whether the given week index represents
+ * a valid calendar week, accounting for the fact
+ * that weeks are aligned to calendar boundaries
+ * rather than strictly contained within a single
+ * year. A week index is considered valid if it
+ * falls within the complete set of weeks that
+ * contain days from the current year, which may
+ * include partial weeks from adjacent years.
+ * This accommodates cases where the first week
+ * contains days from the previous December or
+ * the last week contains days from the following
+ * January.
+ *
+ * @return
+ * True if valid calendar week index
+ */
+ [[nodiscard]] inline static constexpr bool isValidWeekIndex(const uint8_t week_index
+ ) noexcept
+ {
+ return week_index <= WEEKS_IN_YEAR;
+ }
+
+ /*!
+ * @brief
+ * Checks if day-of-week index is within valid
+ * range.
+ *
+ * @details
+ * Accepts a zero-based day-of-week index
+ * (0 = Sunday ... 6 = Saturday). Returns true
+ * only if the index is less than `DAYS_IN_WEEK`.
+ *
+ * @return
+ * True if valid day-of-week index
+ */
+ [[nodiscard]] inline static constexpr bool isValidDOWIndex(const uint8_t dow_index
+ ) noexcept
+ {
+ return dow_index < DAYS_IN_WEEK;
+ }
+
+ /*!
+ * @brief
+ * Checks if given year, month, and day
+ * combination form a valid calendar date.
+ *
+ * @details
+ * This function returns true when the provided
+ * date parameters describe a real date on the
+ * Gregorian calendar. This is achieved by
+ * comparing the dates day to the total number
+ * of days in the month. If the provided year
+ * is not supported, the function returns false.
+ *
+ * @return
+ * True if date exists on calendar
+ */
+ [[nodiscard]] static constexpr bool isValidDate(
+ const YearInt_t year, const uint8_t month, const uint8_t day
+ ) noexcept
+ {
+ return DatePolicy::isValidDate(year, month, day);
+ }
+
+ /*!
+ * @brief
+ * Calculates day-of-week index of provided
+ * calendar date.
+ *
+ * @details
+ * Implements Tomohiko Sakamoto's algorithm to
+ * determine the day of the week for the
+ * specified year, month, and day combination.
+ * Returns a zero-based day-of-week index
+ * (0 = Sunday ... 6 = Saturday), or
+ * `INVALID_DOW_INDEX` if the provided date
+ * does not exist on the calendar.
+ *
+ * @return
+ * Day-of-week index
+ */
+ [[nodiscard]] static constexpr uint8_t getDayOfWeekIndex(
+ YearInt_t year, uint8_t month, uint8_t day
+ ) noexcept
+ {
+ if (!DatePolicy::isValidDate(year, month, day))
+ return INVALID_DOW_INDEX; // NOTE: This has to go...
+
+ // CREDITS: Tomohiko Sakamoto
+ // Day-of-week index algorithm
+ year -= (month < March); // Extra days from leap year
+ // only affect March and later
+ const uint8_t monthIndex = month - 1;
+ const int index =
+ ((year + year / 4 - year / 100 + year / YEARS_IN_ERA +
+ sakamoto::MONTH_KEY[monthIndex] + day) %
+ DAYS_IN_WEEK);
+
+ return static_cast(index);
+ }
+
+ /*!
+ * @brief
+ * Calculates day-of-week index for a given
+ * calendar date.
+ *
+ * @details
+ * Extracts the year, month, and day from the
+ * given `Date` instance to compute the
+ * zero-based day-of-week index.
+ *
+ * @return
+ * Day-of-week index
+ */
+ [[nodiscard]] static constexpr uint8_t getDayOfWeekIndex(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return getDayOfWeekIndex(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents), // Month
+ std::get<2>(dateComponents) // Day
+ );
+ }
+
+ /*!
+ * @brief
+ * Number of full 7-day weeks contained in
+ * specified month.
+ *
+ * @details
+ * Calculates how many full seven-day calendar
+ * weeks are in the provided month. Fractional
+ * week information is truncated (*floor*) and
+ * results are not dependent on current day of
+ * the week. Returns 0 if the month is invalid
+ * or if the provided year is unsupported.
+ *
+ * @return
+ * Number of full 7-day weeks in month
+ */
+ [[nodiscard]] static constexpr uint8_t getWeeksInMonth(
+ const YearInt_t year, const uint8_t month
+ ) noexcept
+ {
+ const uint8_t monthTotalDays = DatePolicy::getDaysInMonth(year, month);
+
+ if (monthTotalDays == 0)
+ return 0; // Unsupported year or invalid month
+
+ uint8_t disqualifiedDays = (
+ (SATURDAY - getDayOfWeekIndex(year, month, 1)) +
+ (getDayOfWeekIndex(year, month, monthTotalDays)) + 2
+ );
+ const uint8_t fullWeeks = static_cast(
+ (monthTotalDays - disqualifiedDays) / DAYS_IN_WEEK
+ );
+ return fullWeeks;
+ }
+
+ /*!
+ * @brief
+ * Number of full 7-day weeks contained in
+ * specified month.
+ *
+ * @details
+ * Extracts the year and month components from
+ * the provided `Date` instance to calculate
+ * how many full seven-day calendar weeks are
+ * in the provided month. Fractional week
+ * information is truncated.
+ *
+ * @return
+ * Number of full 7-day weeks in month
+ */
+ [[nodiscard]] static constexpr uint8_t getWeeksInMonth(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return getWeeksInMonth(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents) // Month
+ );
+ }
+
+ /*!
+ * @brief
+ * Determines number of weeks a specified month
+ * spans over the calendar.
+ *
+ * @details
+ * Calculates how many full or partial weeks are
+ * needed to contain all days of the specified
+ * month in a standard calendar grid. The result
+ * depends on the day of the week the month starts
+ * on and the total number of days in the month.
+ * Returns 0 if the month is invalid or if the
+ * provided year is unsupported.
+ *
+ * @return
+ * Number of weeks month spans
+ */
+ [[nodiscard]] static constexpr uint8_t getWeeksMonthSpans(
+ const YearInt_t year, const uint8_t month
+ ) noexcept
+ {
+ const uint8_t monthTotalDays = DatePolicy::getDaysInMonth(year, month);
+
+ if (monthTotalDays == 0)
+ return 0; // Unsupported or invalid
+
+ const uint8_t firstOfMonthDowIndex = getDayOfWeekIndex(year, month, 1);
+ const uint8_t monthCells = firstOfMonthDowIndex + monthTotalDays;
+ return (monthCells + 6) / DAYS_IN_WEEK;
+ }
+
+ /*!
+ * @brief
+ * Determines number of weeks a specified month
+ * spans over the calendar.
+ *
+ * @details
+ * Extracts year and month components from the
+ * provided `Date` instance to calculates how
+ * many full or partial weeks are needed to
+ * contain all days of the specified month in
+ * a standard calendar grid.
+ *
+ * @return
+ * Number of weeks month spans
+ */
+ [[nodiscard]] static constexpr uint8_t getWeeksMonthSpans(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return getWeeksMonthSpans(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents) // Month
+ );
+ }
+
+ /*!
+ * @brief
+ * Determines zero-based index of week for a
+ * specified date within its year.
+ *
+ * @details
+ * This function calculates which week of the year
+ * [0–52] the given Gregorian calendar date falls
+ * into. Weeks are defined relative to Sundays,
+ * with week 0 beginning on the first Sunday before
+ * or on January 1 of the given year. The weeks are
+ * calendar aligned. Consequently, the week index
+ * can range from [0-52] (inclusive) because the
+ * potential partial week(s) at the beginning and
+ * end of the year are taken into account. The index
+ * is obtained by computing the difference in days
+ * between the target date and that first Sunday,
+ * then dividing by the number of days in a week. If
+ * the provided year, month, or day values do not
+ * form a valid Gregorian date, the function returns
+ * index 0 as a fallback.
+ *
+ * @return
+ * Index of week within year [0 - 52]
+ */
+ [[nodiscard]] static constexpr uint8_t getWeekIndex(
+ YearInt_t year, uint8_t month, uint8_t day
+ ) noexcept
+ {
+ if (!DatePolicy::isValidDate(year, month, day))
+ return 0; // NOTE: Unexpected behavior?
+
+ const int8_t sundayDiff = SUNDAY - getDayOfWeekIndex(year, January, 1);
+ const Days firstSunday{toDaysSinceEpoch(year, January, 1) + Days{sundayDiff}};
+ const Days serialDate{toDaysSinceEpoch(year, month, day)};
+ return static_cast((serialDate - firstSunday).count() / DAYS_IN_WEEK);
+ }
+
+ /*!
+ * @brief
+ * Determines zero-based index of week for a
+ * specified date within its year.
+ *
+ * @details
+ * Extracts year, month, and day components from
+ * the provided `Date` instance to calculate which
+ * week of the year [0–52] the given Gregorian
+ * calendar date falls into.
+ *
+ * @return
+ * Index of week within year [0 - 52]
+ */
+ [[nodiscard]] static constexpr uint8_t getWeekIndex(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return getWeekIndex(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents), // Month
+ std::get<2>(dateComponents) // Day
+ );
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date to serial number of
+ * days since Unix epoch.
+ *
+ * @details
+ * Uses Howard Hinnant’s civil date algorithm to
+ * convert a year, month, day combination into a
+ * signed day count relative to the Unix epoch
+ * (1970-01-01 = day 0). The result can be
+ * negative for dates before the epoch.
+ *
+ * @return
+ * Days since January 1, 1970
+ */
+ [[nodiscard]] static constexpr Days toDaysSinceEpoch(
+ YearInt_t year, uint8_t month, uint8_t day
+ ) noexcept
+ {
+ if (!DatePolicy::isValidDate(year, month, day))
+ return Days{0}; // Epoch date
+
+ return Days{static_cast(hinnant::toDaysSinceEpoch(year, month, day))};
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date to serial number of
+ * days since Unix epoch.
+ *
+ * @details
+ * Returns serial date count in explicit units of
+ * precision (days) using the provided `Date`
+ * instances `units()` function.
+ *
+ * @return
+ * Days since January 1, 1970
+ */
+ [[nodiscard]] inline static constexpr Days toDaysSinceEpoch(const Date date) noexcept
+ {
+ return date.units();
+ }
+
+ /*!
+ * @brief
+ * Converts a serial count of days since Unix
+ * epoch to a calendar date.
+ *
+ * @details
+ * Uses Howard Hinnant’s civil date algorithm
+ * to convert a signed day count relative to
+ * the Unix epoch (1970-01-01 = day 0) into a
+ * year, month, day combination. Returns a
+ * `GregorianDate` representing the calculated
+ * civil date.
+ *
+ * @return
+ * Gregorian calendar date
+ */
+ [[nodiscard]] static constexpr Date fromDaysSinceEpoch(const Days serial_days) noexcept
+ {
+ DateTuple dateComponents = hinnant::fromDaysSinceEpoch(serial_days.count());
+
+ return Date{
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents), // Month
+ std::get<2>(dateComponents) // Day
+ };
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date to a Unix timestamp
+ * (seconds since epoch).
+ *
+ * @details
+ * Uses `toDaysSinceEpoch()` to calculate the
+ * number of days since the Unix epoch
+ * (1970-01-01) and multiplies by the number
+ * of seconds in a day to obtain the equivalent
+ * timestamp in seconds. The returned value is
+ * stored in `stl::UnixTimestamp` and may be
+ * negative for dates before the epoch.
+ *
+ * @return
+ * Unix timestamp
+ */
+ [[nodiscard]] static constexpr stl::UnixTimestamp toUnixTimestamp(
+ const YearInt_t year, const uint8_t month, const uint8_t day
+ ) noexcept
+ {
+ return static_cast(
+ Seconds{toDaysSinceEpoch(year, month, day)}.count()
+ );
+ }
+
+ /*!
+ * @brief
+ * Converts a calendar date to a Unix timestamp
+ * (seconds since epoch).
+ *
+ * @details
+ * Extracts year, month, and day components from
+ * the provided `Date` instance to calculate the
+ * number of days since the Unix epoch (1970-01-01).
+ *
+ * @return
+ * Unix timestamp
+ */
+ [[nodiscard]] static constexpr stl::UnixTimestamp toUnixTimestamp(const Date date) noexcept
+ {
+ const DateTuple dateComponents = hinnant::fromDaysSinceEpoch(date.underlying());
+
+ return toUnixTimestamp(
+ std::get<0>(dateComponents), // Year
+ std::get<1>(dateComponents), // Month
+ std::get<2>(dateComponents) // Day
+ );
+ }
+
+ /*!
+ * @brief
+ * Converts a Unix timestamp (seconds since
+ * epoch) to a calendar date.
+ *
+ * @details
+ * Divides the given `stl::UnixTimestamp` by the
+ * number of seconds in a day to convert seconds
+ * to whole days since the Unix epoch (1970-01-01),
+ * then calls `fromDaysSinceEpoch()` to obtain the
+ * corresponding calendar date.
+ *
+ * @return
+ * Gregorian calendar date
+ */
+ [[nodiscard]] static constexpr Date fromUnixTimestamp(const stl::UnixTimestamp& timestamp
+ ) noexcept
+ {
+ return fromDaysSinceEpoch(Days{static_cast(timestamp / SECONDS_IN_DAY)});
+ }
+
+ /*!
+ * @brief
+ * Converts a serial count of seconds to
+ * a calendar date.
+ *
+ * @details
+ * Converts the provided serial seconds count
+ * timestamp to days, which is then interpreted
+ * using Howard Hinnants algorithm.
+ *
+ * @return
+ * Gregorian calendar date
+ */
+ [[nodiscard]] static constexpr Date fromUnixTimestamp(const Seconds serial_secs) noexcept
+ {
+ return fromDaysSinceEpoch(duration_cast(serial_secs));
+ }
+
+ /*!
+ * @brief
+ * Finds next weekday [Monday – Friday] after a
+ * given date.
+ *
+ * @details
+ * This function advances the provided `from_date`
+ * to the next date that falls on a weekday
+ * (Monday through Friday). If the current date is
+ * Friday, the result is the following Monday
+ * (skipping the weekend). If the current date is
+ * Saturday or Sunday, the function advances to
+ * the upcoming Monday. For all other weekdays
+ * (Monday–Thursday), the result is simply the
+ * next calendar day.
+ *
+ * @return
+ * Next date between [Monday - Friday]
+ */
+ [[nodiscard]] static constexpr Date getNextWeekday(const Date from_date) noexcept
+ {
+ const DayOfWeek fromDow = static_cast(getDayOfWeekIndex(from_date));
+
+ switch (fromDow) {
+ case FRIDAY:
+ return from_date + Days{3};
+
+ case SATURDAY:
+ return from_date + Days{2};
+
+ default: // SUNDAY - THURSDAY
+ return from_date + Days{1};
+ }
+ }
+
+ /*!
+ * @brief
+ * Finds most recent weekday [Monday – Friday]
+ * before a given date.
+ *
+ * @details
+ * This function rolls the provided `from_date`
+ * back to the last date that falls on a weekday
+ * (Monday through Friday). If the current date is
+ * Monday, the result is the previous Friday. If
+ * the current date is Sunday, the result is the
+ * previous Friday as well. For all other days
+ * (Tuesday through Saturday), the result is simply
+ * the preceding calendar day, provided it falls
+ * within the weekday range.
+ *
+ * @return
+ * Last date between [Monday - Friday]
+ */
+ [[nodiscard]] static constexpr Date getLastWeekday(const Date from_date) noexcept
+ {
+ const DayOfWeek fromDow = static_cast(getDayOfWeekIndex(from_date));
+
+ switch (fromDow) {
+ case SUNDAY:
+ return from_date - Days{2};
+
+ case MONDAY:
+ return from_date - Days{3};
+
+ default: // TUESDAY - SATURDAY
+ return from_date - Days{1};
+ }
+ }
+
+ /*!
+ * @brief
+ * Finds next Saturday following a provided date.
+ *
+ * @details
+ * This function advances the provided `from_date`
+ * to the next occurrence of Saturday in the
+ * Gregorian calendar. If the given date already
+ * falls on a Saturday, the function returns the
+ * Saturday of the following week. For all other
+ * days, the function computes the offset to the
+ * upcoming Saturday and advances accordingly.
+ *
+ * @return
+ * Next Saturday date
+ */
+ [[nodiscard]] static constexpr Date getNextWeekend(const Date from_date) noexcept
+ {
+ const uint8_t dowIndex = getDayOfWeekIndex(from_date);
+ return from_date + Days{((SATURDAY - dowIndex + DAYS_IN_WEEK - 1) % 7) + 1};
+ }
+
+ /*!
+ * @brief
+ * Finds last Saturday before provided date.
+ *
+ * @details
+ * This function decreases the provided `from_date`
+ * to the last occurrence of Saturday in the
+ * Gregorian calendar. If the given date already
+ * falls on a Saturday, the function returns the
+ * Saturday of the prior week. For all other
+ * days, the function computes the offset to the
+ * previous Saturday and decreases accordingly.
+ *
+ * @return
+ * Last Saturday date
+ */
+ [[nodiscard]] static constexpr Date getLastWeekend(const Date from_date) noexcept
+ {
+ const uint8_t dowDiff = SATURDAY - getDayOfWeekIndex(from_date);
+ return from_date - Days{DAYS_IN_WEEK - dowDiff};
+ }
+
+ /*!
+ * @brief
+ * Finds all dates associated with provided week
+ * within a year.
+ *
+ * @details
+ * Gathers all 7 dates of a specified week within a
+ * year into an array and returns the results.
+ * Weeks are defined relative to Sundays, with week
+ * 0 beginning on the first Sunday before or on
+ * January 1 of the given year. The weeks are
+ * calendar aligned. Consequently, a request for the
+ * first and last week of a given year may result in
+ * dates from the previous or next year. If the
+ * provided year value is not supported or an invalid
+ * week index is provided, the function returns an
+ * array of epoch dates.
+ *
+ * @return
+ * Array of calendar week dates
+ */
+ [[nodiscard]] static constexpr WeekDates getWeek(
+ const YearInt_t year, const uint8_t week_index
+ ) noexcept
+ {
+ WeekDates week{};
+
+ if (!isValidWeekIndex(week_index) || !DatePolicy::isValidYear(year))
+ return week; // Invalid week index or unsupported year
+
+ const Days serialStart{
+ toDaysSinceEpoch(year, January, 1) + Days{week_index * DAYS_IN_WEEK}
+ };
+ const DayOfWeek fromDow = static_cast(getDayOfWeekIndex(year, January, 1));
+
+ for (uint8_t dowIndex = SUNDAY; dowIndex < DAYS_IN_WEEK; dowIndex++) {
+ const int8_t dowDiff = dowIndex - fromDow;
+ week[dowIndex] = fromDaysSinceEpoch(Days{serialStart + Days{dowDiff}});
+ }
+
+ return week;
+ }
+
+ /*!
+ * @brief
+ * Finds all dates associated with week containing
+ * provided date.
+ *
+ * @details
+ * Determines the full calendar week (Sunday through
+ * Saturday) that the provided date falls within by
+ * aligning to the date’s weekday and filling in
+ * surrounding dates.
+ *
+ * @return
+ * Array of calendar week dates
+ */
+ [[nodiscard]] static constexpr WeekDates getWeek(const Date date) noexcept
+ {
+ const Days serialStart{toDaysSinceEpoch(date)};
+ const DayOfWeek fromDow = static_cast(getDayOfWeekIndex(date));
+ WeekDates week{};
+
+ for (uint8_t dowIndex = SUNDAY; dowIndex < DAYS_IN_WEEK; dowIndex++) {
+ const int8_t dowDiff = dowIndex - fromDow;
+ week[dowIndex] = fromDaysSinceEpoch(Days{serialStart + Days{dowDiff}});
+ }
+
+ return week;
+ }
+
+ private:
+ GregorianCalendar() = delete;
+ ~GregorianCalendar() = delete;
+};
+
+SIMPLYDT_ENFORCE_CALENDAR_CONTRACT(GregorianCalendar);
+
+} // namespace simplydt::gregorian
+
+#endif // SIMPLYDT_LIB_GREGORIAN_CALENDAR_H_
diff --git a/include/simplydt/calendar/gregorian/gregorian_date.hpp b/include/simplydt/calendar/gregorian/gregorian_date.hpp
new file mode 100644
index 0000000..090545c
--- /dev/null
+++ b/include/simplydt/calendar/gregorian/gregorian_date.hpp
@@ -0,0 +1,191 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file gregorian_date.hpp
+ *
+ * @brief
+ * Gregorian calendar date declaration.
+ */
+
+
+#ifndef SIMPLYDT_LIB_SERIAL_GREGORIAN_CALENDAR_DATE_H_
+#define SIMPLYDT_LIB_SERIAL_GREGORIAN_CALENDAR_DATE_H_
+
+#include "simplydt/calendar/concepts/date_api_contract.hpp"
+#include "simplydt/calendar/date/abstract_date.hpp"
+#include "simplydt/calendar/gregorian/date_validation.hpp"
+#include "simplydt/calendar/gregorian/gregorian_defs.hpp"
+#include "simplydt/calendar/gregorian/hinnant_algorithms.hpp"
+#include "simplydt/common/string_utils.hpp"
+
+namespace simplydt::gregorian
+{
+
+/*!
+ * @brief
+ * Gregorian calendar date.
+ *
+ * @details
+ * TODO: INCOMPLETE COMMENT!!!
+ */
+struct GregorianDate :
+ public SerialCalendarDate {
+ /*! @brief Epoch date in serial days. */
+ static constexpr Repr_Type SERIAL_EPOCH = 0;
+
+ /*!
+ * @brief
+ * Intercepts invalid date constructor values.
+ *
+ * @details
+ * This function verifies that the provided year,
+ * month, and day values form a valid Gregorian
+ * calendar date according to the associated
+ * `ValidationPolicy`. If the date is valid, it is
+ * converted into its corresponding serial day
+ * representation relative to the Unix epoch
+ * (January 1, 1970). If the date is invalid, the
+ * function returns the Unix epoch (0) as a default.
+ *
+ * @return
+ * Provided date in serial days if valid, epoch
+ * otherwise
+ */
+ static constexpr Repr_Type useDefaultIfInvalid(
+ const YearInt_t year, const uint8_t month, const uint8_t day
+ ) noexcept
+ {
+ if (!ValidationPolicy::isValidDate(year, month, day))
+ return SERIAL_EPOCH;
+
+ return hinnant::toDaysSinceEpoch(year, month, day);
+ }
+
+ /*!
+ * @brief
+ * Construct Gregorian calendar date using year,
+ * month, and day values.
+ */
+ constexpr GregorianDate(
+ const YearInt_t year, const uint8_t month, const uint8_t day
+ ) noexcept
+ : SerialCalendarDate{
+ useDefaultIfInvalid(year, month, day)
+ }
+ { }
+
+ /*!
+ * @brief
+ * Construct default Gregorian calendar date
+ * (epoch date).
+ */
+ constexpr GregorianDate() noexcept
+ : SerialCalendarDate{
+ SERIAL_EPOCH
+ }
+ { }
+
+ ~GregorianDate() = default;
+
+ /*!
+ * @brief
+ * Date year component.
+ *
+ * @details
+ * This function derives the year value from the
+ * internal serial day count using algorithms from
+ * Howard Hinnant. The calculation decomposes the
+ * serial day count into its era, year-of-era,
+ * day-of-era, and month-prime components. These
+ * values are then combined to yield the correct
+ * Gregorian calendar year.
+ *
+ * @return
+ * Year of Gregorian calendar date
+ */
+ [[nodiscard]] constexpr YearInt_t year() const noexcept
+ {
+ const int era = hinnant::eraFromSerialDays(this->serialDays);
+ const unsigned yoe = hinnant::yearOfEraFromSerialDays(this->serialDays);
+ const unsigned doy =
+ (hinnant::dayOfEraFromSerialDays(this->serialDays) -
+ (DAYS_IN_YEAR * yoe + yoe / 4 - yoe / 100));
+ const unsigned mp = hinnant::monthPrime(doy);
+ return static_cast(era * YEARS_IN_ERA + yoe + (mp >= 10));
+ }
+
+ /*!
+ * @brief
+ * Date month component.
+ *
+ * @details
+ * This function derives the month value from the
+ * internal serial day count using algorithms from
+ * Howard Hinnant. The calculation decomposes the
+ * serial day count into its day-of-year and
+ * month-prime components. These values are then
+ * combined to yield the correct numeric Gregorian
+ * calendar month.
+ *
+ * @return
+ * Month of Gregorian calendar date
+ */
+ [[nodiscard]] constexpr uint8_t month() const noexcept
+ {
+ const unsigned doy = hinnant::dayOfYearFromSerialDays(this->serialDays);
+ const unsigned mp = hinnant::monthPrime(doy);
+ return static_cast(mp + (mp < 10 ? 3 : -9));
+ }
+
+ /*!
+ * @brief
+ * Date day component.
+ *
+ * @details
+ * This function derives the day value from the
+ * internal serial day count using algorithms from
+ * Howard Hinnant. The calculation decomposes the
+ * serial day count into its day-of-year and
+ * month-prime components. These values are then
+ * combined to yield the correct day of month.
+ *
+ * @return
+ * Day of Gregorian calendar date
+ */
+ [[nodiscard]] constexpr uint8_t day() const noexcept
+ {
+ const unsigned doy = hinnant::dayOfYearFromSerialDays(this->serialDays);
+ const unsigned mp = hinnant::monthPrime(doy);
+ return static_cast(doy - (153 * mp + 2) / 5 + 1);
+ }
+
+ /*!
+ * @brief
+ * Compose string representation of Gregorian
+ * calendar date.
+ *
+ * @return
+ * Gregorian calendar date as string
+ */
+ [[nodiscard]] std::string toStr() const noexcept
+ {
+ const char delimiter = '-';
+ std::string dateStr;
+ dateStr.reserve(12);
+ const DateTuple dateValues = hinnant::fromDaysSinceEpoch(this->serialDays);
+ dateStr += (std::to_string(std::get<0>(dateValues)) + delimiter);
+ dateStr += (toDoubleDigitStr(std::get<1>(dateValues)) + delimiter);
+ dateStr += toDoubleDigitStr(std::get<2>(dateValues));
+ return dateStr;
+ }
+};
+
+SIMPLYDT_ENFORCE_DATE_CONTRACT(GregorianDate);
+
+} // namespace simplydt::gregorian
+
+#endif // SIMPLYDT_LIB_SERIAL_GREGORIAN_CALENDAR_DATE_H_
diff --git a/include/simplydt/calendar/gregorian/gregorian_defs.hpp b/include/simplydt/calendar/gregorian/gregorian_defs.hpp
new file mode 100644
index 0000000..0a9b0a6
--- /dev/null
+++ b/include/simplydt/calendar/gregorian/gregorian_defs.hpp
@@ -0,0 +1,403 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file gregorian_defs.hpp
+ *
+ * @brief
+ * Gregorian calendar system definitions.
+ */
+
+
+#ifndef SIMPLYDT_LIB_GREGORIAN_CALENDAR_DEFINITIONS_H_
+#define SIMPLYDT_LIB_GREGORIAN_CALENDAR_DEFINITIONS_H_
+
+#include "simplydt/common/calendar_defs.hpp"
+#include
+#include
+
+/*!
+ * @namespace simplydt::gregorian
+ *
+ * @brief
+ * Standard civil calendar system.
+ */
+namespace simplydt::gregorian
+{
+
+/*!
+ * @brief
+ * Gregorian year integer type.
+ *
+ * @note
+ * The underlying type used to represent Gregorian
+ * calendar years imposes a limit on the range of
+ * representable dates.
+ */
+using Year_Type = uint16_t;
+
+/*!
+ * @brief
+ * Gregorian calendar date values tuple.
+ *
+ * @details
+ * A specialized tuple type containing the three
+ * fundamental components of a Gregorian calendar
+ * date: year, month, and day. The tuple structure
+ * provides a lightweight container for date
+ * storage while maintaining clear separation of
+ * the individual components.
+ */
+using DateTuple = CalendarDateTuple;
+
+/*!
+ * @brief
+ * Minimum supported year value.
+ *
+ * @details
+ * This is the minimum supported year for the
+ * Gregorian calendar in Simply Datetime.
+ * This limit was choosen because it aligns with
+ * Microsoft's FILETIME structure which measures
+ * 100-nanosecond intervals since January 1, 1601.
+ * This allows compatibility with Windows NT
+ * systems and historical time point capabilities.
+ */
+constexpr Year_Type YEAR_MINIMUM = 1'601;
+
+/*!
+ * @brief
+ * Maximum supported year value.
+ *
+ * @details
+ * This is the maximum supported year value for the
+ * Gregorian calendar in Simply Datetime.
+ */
+constexpr Year_Type YEAR_MAXIMUM = 2'038; // TODO: Find real limitation...
+
+/*! @brief The month of January (1). */
+constexpr uint8_t January = 1;
+
+/*! @brief The month of February (2). */
+constexpr uint8_t February = 2;
+
+/*! @brief The month of March (3). */
+constexpr uint8_t March = 3;
+
+/*! @brief The month of April (4). */
+constexpr uint8_t April = 4;
+
+/*! @brief The month of May (5). */
+constexpr uint8_t May = 5;
+
+/*! @brief The month of June (6). */
+constexpr uint8_t June = 6;
+
+/*! @brief The month of July (7). */
+constexpr uint8_t July = 7;
+
+/*! @brief The month of August (8). */
+constexpr uint8_t August = 8;
+
+/*! @brief The month of September (9). */
+constexpr uint8_t September = 9;
+
+/*! @brief The month of October (10). */
+constexpr uint8_t October = 10;
+
+/*! @brief The month of November (11). */
+constexpr uint8_t November = 11;
+
+/*! @brief The month of December (12). */
+constexpr uint8_t December = 12;
+
+/*!
+ * @brief
+ * Abbreviation length for Gregorian calendar name
+ * literals.
+ *
+ * @details
+ * Details length of abbreviated Gregorian calendar
+ * day-of-week and month names.
+ */
+constexpr int ABBREV_LENGTH = 3;
+
+/*!
+ * @brief
+ * Minimum day of Gregorian month.
+ */
+constexpr uint8_t MIN_DAY_OF_MONTH = 1;
+
+/*!
+ * @brief
+ * Maximum day of Gregorian month.
+ */
+constexpr uint8_t MAX_DAY_OF_MONTH = 31;
+
+/*!
+ * @brief
+ * Minimum month of Gregorian year.
+ */
+constexpr uint8_t MIN_MONTH_OF_YEAR = January;
+
+/*!
+ * @brief
+ * Maximum month of Gregorian year.
+ */
+constexpr uint8_t MAX_MONTH_OF_YEAR = December;
+
+/*!
+ * @brief
+ * Total number of days in one calendar week.
+ */
+constexpr uint8_t DAYS_IN_WEEK = 7;
+
+/*!
+ * @brief
+ * Total number of days in one common calendar
+ * year.
+ */
+constexpr uint16_t DAYS_IN_YEAR = 365;
+
+/*!
+ * @brief
+ * Total number of days in one calendar leap
+ * year.
+ */
+constexpr uint16_t DAYS_IN_LEAP_YEAR = 366;
+
+/*!
+ * @brief
+ * Total number of calendar years in one Gregorian
+ * era.
+ */
+constexpr Year_Type YEARS_IN_ERA = 400;
+
+/*!
+ * @brief
+ * Total number of days in one Gregorian era.
+ *
+ * @details
+ * Represents the number of days in a 400-year
+ * Gregorian cycle. The patterns of the Gregorian
+ * calendar repeat themselves over an era,
+ * consequently the number of days in a single era
+ * are the same for all others. This value is
+ * calculated by multiplying the number of days in
+ * a year by the number of years in one era, which
+ * is then increased by an additional 97 days to
+ * account for leap days within the era.
+ */
+constexpr uint32_t DAYS_IN_ERA = YEARS_IN_ERA * DAYS_IN_YEAR + 97;
+
+/*!
+ * @brief
+ * Average amount of days per calendar year.
+ */
+constexpr inline float AVG_DAYS_IN_YEAR = 365.25;
+
+/*!
+ * @brief
+ * Whole number of seven-day periods in a
+ * calendar year.
+ */
+constexpr uint8_t WEEKS_IN_YEAR = 52;
+
+/*!
+ * @brief
+ * Total number of months in one calendar year.
+ */
+constexpr uint8_t MONTHS_IN_YEAR = 12;
+
+/*!
+ * @brief
+ * Enumeration of Gregorian calendar months.
+ */
+enum Month : uint8_t {
+ JANUARY, ///< January (1)
+ FEBRUARY, ///< February (2)
+ MARCH, ///< March (3)
+ APRIL, ///< April (4)
+ MAY, ///< May (5)
+ JUNE, ///< June (6)
+ JULY, ///< July (7)
+ AUGUST, ///< August (8)
+ SEPTEMBER, ///< September (9)
+ OCTOBER, ///< October (10)
+ NOVEMBER, ///< November (11)
+ DECEMBER ///< December (12)
+};
+
+/*!
+ * @brief
+ * Enumeration of Gregorian calendar days of week.
+ */
+enum DayOfWeek : uint8_t {
+ SUNDAY, ///< Sunday
+ MONDAY, ///< Monday
+ TUESDAY, ///< Tuesday
+ WEDNESDAY, ///< Wednesday
+ THURSDAY, ///< Thursday
+ FRIDAY, ///< Friday
+ SATURDAY ///< Saturday
+};
+
+/*!
+ * @brief
+ * Array of Gregorian calendar month name literals.
+ */
+inline constexpr std::array Months = {
+ "January", ///< Index 0
+ "February", ///< Index 1
+ "March", ///< Index 2
+ "April", ///< Index 3
+ "May", ///< Index 4
+ "June", ///< Index 5
+ "July", ///< Index 6
+ "August", ///< Index 7
+ "September", ///< Index 8
+ "October", ///< Index 9
+ "November", ///< Index 10
+ "December" ///< Index 11
+};
+
+/*!
+ * @brief
+ * Array of abbreviated Gregorian calendar month
+ * names.
+ */
+inline constexpr std::array MonthAbbrevs = {
+ std::string_view(Months[JANUARY], ABBREV_LENGTH), ///< Jan
+ std::string_view(Months[FEBRUARY], ABBREV_LENGTH), ///< Feb
+ std::string_view(Months[MARCH], ABBREV_LENGTH), ///< Mar
+ std::string_view(Months[APRIL], ABBREV_LENGTH), ///< Apr
+ std::string_view(Months[MAY], ABBREV_LENGTH), ///< May
+ std::string_view(Months[JUNE], ABBREV_LENGTH), ///< Jun
+ std::string_view(Months[JULY], ABBREV_LENGTH), ///< Jul
+ std::string_view(Months[AUGUST], ABBREV_LENGTH), ///< Aug
+ std::string_view(Months[SEPTEMBER], ABBREV_LENGTH), ///< Sep
+ std::string_view(Months[OCTOBER], ABBREV_LENGTH), ///< Oct
+ std::string_view(Months[NOVEMBER], ABBREV_LENGTH), ///< Nov
+ std::string_view(Months[DECEMBER], ABBREV_LENGTH) ///< Dec
+};
+
+/*!
+ * @brief
+ * Array of Gregorian calendar day-of-week literals.
+ */
+inline constexpr std::array DaysOfWeek = {
+ "Sunday", ///< Index 0
+ "Monday", ///< Index 1
+ "Tuesday", ///< Index 2
+ "Wednesday", ///< Index 3
+ "Thursday", ///< Index 4
+ "Friday", ///< Index 5
+ "Saturday" ///< Index 6
+};
+
+/*!
+ * @brief
+ * Array of abbreviated Gregorian calendar day-of-week
+ * literals.
+ */
+inline constexpr std::array DayOfWeekAbbrevs = {
+ std::string_view(DaysOfWeek[SUNDAY], ABBREV_LENGTH), ///< Sun
+ std::string_view(DaysOfWeek[MONDAY], ABBREV_LENGTH), ///< Mon
+ std::string_view(DaysOfWeek[TUESDAY], ABBREV_LENGTH), ///< Tue
+ std::string_view(DaysOfWeek[WEDNESDAY], ABBREV_LENGTH), ///< Wed
+ std::string_view(DaysOfWeek[THURSDAY], ABBREV_LENGTH), ///< Thu
+ std::string_view(DaysOfWeek[FRIDAY], ABBREV_LENGTH), ///< Fri
+ std::string_view(DaysOfWeek[SATURDAY], ABBREV_LENGTH) ///< Sat
+};
+
+/*!
+ * @brief
+ * Invalid date day-of-week index.
+ *
+ * @details
+ * Used to signal invalid dates that seek a day-of-week
+ * index.
+ */
+constexpr uint8_t INVALID_DOW_INDEX = 255;
+
+} // namespace simplydt::gregorian
+
+/*!
+ * @brief
+ * Tomohiko Sakamoto's Algorithm.
+ *
+ * @details
+ * Algorithm for computing day-of-week indecies of
+ * Gregorian calendar dates by Tomohiko Sakamoto.
+ */
+namespace simplydt::sakamoto
+{
+
+/*!
+ * @brief
+ * Month offset lookup table for Tomohiko Sakamoto's
+ * algorithm.
+ *
+ * @details
+ * Each value is a precomputed offset added in the
+ * algorithm's summation. The offsets compactly encode
+ * month length variations and leap year alignment,
+ * avoiding branches when calculating the day-of-week.
+ */
+inline constexpr uint8_t MONTH_KEY[gregorian::MONTHS_IN_YEAR] = {
+ 0, ///< January offset
+ 3, ///< February offset
+ 2, ///< March offset
+ 5, ///< April offset
+ 0, ///< May offset
+ 3, ///< June offset
+ 5, ///< July offset
+ 1, ///< August offset
+ 4, ///< September offset
+ 6, ///< October offset
+ 2, ///< November offset
+ 4 ///< December offset
+};
+
+} // namespace simplydt::sakamoto
+
+/*!
+ * @brief
+ * Howard Hinnant's Algorithm.
+ *
+ * @note
+ * https://howardhinnant.github.io/date_algorithms.html
+ * for more details.
+ *
+ * @details
+ * Algorithms sourced from Howard Hinnant for the
+ * Gregorian calendar.
+ */
+namespace simplydt::hinnant
+{
+
+/*!
+ * @brief
+ * Days from 1970-01-01 to 0000-03-01.
+ *
+ * @details
+ * This value shifts the epoch from 1970-01-01
+ * to 0000-03-01 (March 1 of year 0) when
+ * converting to civil date components or
+ * vice-versa when calculating a serial count
+ * of days since the Unix epoch. This is crucial
+ * because it aligns the algorithm with all known
+ * implementations of `std::chrono::system_clock`,
+ * which count seconds from 1970-01-01, neglecting
+ * leap seconds. This value is what makes the
+ * serial date 0 equivalent to 1970-01-01 instead
+ * of 0000-03-01.
+ */
+constexpr int32_t EPOCH_SHIFT = 719'468;
+
+} // namespace simplydt::hinnant
+
+#endif // SIMPLYDT_LIB_GREGORIAN_CALENDAR_DEFINITIONS_H_
diff --git a/include/simplydt/calendar/gregorian/hinnant_algorithms.hpp b/include/simplydt/calendar/gregorian/hinnant_algorithms.hpp
new file mode 100644
index 0000000..ce71196
--- /dev/null
+++ b/include/simplydt/calendar/gregorian/hinnant_algorithms.hpp
@@ -0,0 +1,216 @@
+
+// Copyright (C) 2026 by Jamon T. Bailey and Infinity Systems, LLC. All rights reserved.
+// Released under the terms of the GNU Affero General Public License version 3.
+
+// [ISJTB-CXX-XL20230401-000001]
+
+/*!
+ * @file hinnant_algorithms.hpp
+ *
+ * @brief
+ * Gregorian calendar helper algorithms.
+ */
+
+
+#ifndef SIMPLYDT_LIB_HOWARD_HINNANT_GREGORIAN_ALGORITHMS_H_
+#define SIMPLYDT_LIB_HOWARD_HINNANT_GREGORIAN_ALGORITHMS_H_
+
+#include "simplydt/calendar/gregorian/gregorian_defs.hpp"
+#include "simplydt/common/stl_chrono_defs.hpp"
+
+namespace simplydt::hinnant
+{
+
+/*!
+ * @brief
+ * Converts a calendar date to serial number
+ * of days since Unix epoch.
+ *
+ * @details
+ * Uses Howard Hinnant’s civil date algorithm
+ * to convert a year, month, day combination
+ * into a signed day count relative to the
+ * Unix epoch (1970-01-01 = day 0). The result
+ * can be negative for dates before the epoch.
+ *
+ * @return
+ * Days since January 1, 1970
+ */
+[[nodiscard]] constexpr int32_t toDaysSinceEpoch(
+ gregorian::Year_Type year, uint8_t month, uint8_t day
+) noexcept
+{
+ // CREDITS: Howard Hinnant [Mr. Chrono] - (Ripple Labs)
+ // Convert {year, month, day} triple into a serial count of days.
+ using namespace simplydt::gregorian;
+ year -= month <= February;
+ const int era = year / YEARS_IN_ERA;
+ const unsigned yoe = static_cast(year - era * YEARS_IN_ERA);
+ const unsigned doy = (153 * (month + (month > February ? -3 : 9)) + 2) / 5 + day - 1;
+ const unsigned doe = yoe * DAYS_IN_YEAR + yoe / 4 - yoe / 100 + doy;
+ return static_cast(era * DAYS_IN_ERA + static_cast(doe) - EPOCH_SHIFT);
+}
+
+/*!
+ * @brief
+ * Calculates 400-year era index from serial
+ * number of days.
+ *
+ * @details
+ * Adjusts the input day count by the epoch
+ * shift to align with the March-based year
+ * system used in the algorithm. Then
+ * computes which 400-year Gregorian cycle
+ * (era) the date falls within. The
+ * calculation handles negative day counts
+ * (dates before the algorithm's epoch) by
+ * subtracting one less than a full era to
+ * ensure proper era boundary crossing.
+ *
+ * @return
+ * Year era index
+ */
+[[nodiscard]] constexpr int eraFromSerialDays(int32_t serial_days) noexcept
+{
+ using namespace simplydt::gregorian;
+ serial_days += EPOCH_SHIFT;
+ return (serial_days >= 0 ? serial_days : serial_days - 146'096) / DAYS_IN_ERA;
+}
+
+/*!
+ * @brief
+ * Calculates index of day within current
+ * 400-year era.
+ *
+ * @details
+ * First determines which 400-year era contains
+ * the specified date using `eraFromSerialDays()`,
+ * then calculates the relative day position
+ * within that era. The result represents the
+ * number of days elapsed since the start of the
+ * era (March 1st of the era's first year) to
+ * the specified date. The result can range from
+ * [0 - 146,096] inclusive.
+ *
+ * @return
+ * Day offset within current era [0 - 146,096]
+ */
+[[nodiscard]] constexpr unsigned dayOfEraFromSerialDays(int32_t serial_days) noexcept
+{
+ using namespace simplydt::gregorian;
+ const int era = eraFromSerialDays(serial_days);
+ serial_days += EPOCH_SHIFT;
+ return static_cast(serial_days - era * DAYS_IN_ERA);
+}
+
+/*!
+ * @brief
+ * Calculates year index within current 400-year
+ * era.
+ *
+ * @details
+ * Uses the day-of-era value to compute the year
+ * index within the 400-year Gregorian cycle. The
+ * calculation accounts for leap year patterns by
+ * subtracting/excluding partial periods. These
+ * complex adjustment handles the irregular leap
+ * year distribution across centuries. The result
+ * can range from [0 - 399] inclusive.
+ *
+ * @return
+ * Year offset within current era [0 - 399]
+ */
+[[nodiscard]] constexpr unsigned yearOfEraFromSerialDays(int32_t serial_days) noexcept
+{
+ using namespace simplydt::gregorian;
+ const unsigned doe = dayOfEraFromSerialDays(serial_days);
+ return (doe - doe / 1'460 + doe / 36'524 - doe / 146'096) / DAYS_IN_YEAR;
+}
+
+/*!
+ * @brief
+ * Calculates day index within current year.
+ *
+ * @details
+ * Computes the number of days that have elapsed
+ * since the start of the current year. First
+ * determines the year offset within the era,
+ * then subtracts the cumulative days from the
+ * beginning of the era up to the start of the
+ * current year. The calculation accounts for
+ * leap years by including the appropriate
+ * number of leap days accumulated up to the
+ * current year within the era. The result can
+ * range from [0 - 365] inclusive.
+ *
+ * @return
+ * Day offset within current year [0 - 365]
+ */
+[[nodiscard]] constexpr unsigned dayOfYearFromSerialDays(int32_t serial_days) noexcept
+{
+ using namespace simplydt::gregorian;
+ const unsigned yoe = yearOfEraFromSerialDays(serial_days);
+ return dayOfEraFromSerialDays(serial_days) - (DAYS_IN_YEAR * yoe + yoe / 4 - yoe / 100);
+}
+
+/*!
+ * @brief
+ * Calculates month index within a March-based
+ * year system.
+ *
+ * @details
+ * Uses integer arithmetic to convert a day of
+ * year value into a month index where the year
+ * starts in March. This March-based numbering
+ * system simplifies leap day handling since
+ * February becomes the last month of the year
+ * (March = 0, April = 1, ..., February = 11).
+ * The formula employs a linear approximation
+ * that distributes days across months using
+ * fixed-point mathematics for efficient
+ * computation without branching.
+ *
+ * @return
+ * March-based month index
+ */
+[[nodiscard]] inline constexpr unsigned monthPrime(const unsigned dayOfYear) noexcept
+{
+ return (5 * dayOfYear + 2) / 153;
+}
+
+/*!
+ * @brief
+ * Converts a serial count of days since Unix
+ * epoch to calendar date values.
+ *
+ * @details
+ * Uses Howard Hinnant’s civil date algorithm
+ * to convert a signed day count relative to
+ * the Unix epoch (1970-01-01 = day 0) into a
+ * year, month, day combination. Returns a
+ * `DateTuple` representing the calculated
+ * civil date in y-m-d order.
+ *
+ * @return
+ * Calendar date values tuple
+ */
+[[nodiscard]] constexpr gregorian::DateTuple fromDaysSinceEpoch(int32_t serial_days) noexcept
+{
+ // CREDITS: Howard Hinnant [Mr. Chrono] - (Ripple Labs)
+ // Convert a serial count of days into a {year, month, day} triple.
+ using namespace simplydt::gregorian;
+ serial_days += EPOCH_SHIFT;
+ const int era = (serial_days >= 0 ? serial_days : serial_days - 146'096) / DAYS_IN_ERA;
+ const unsigned doe = static_cast(serial_days - era * DAYS_IN_ERA);
+ const unsigned yoe = (doe - doe / 1'460 + doe / 36'524 - doe / 146'096) / DAYS_IN_YEAR;
+ const Year_Type y = static_cast(yoe) + era * YEARS_IN_ERA;
+ const unsigned doy = doe - (DAYS_IN_YEAR * yoe + yoe / 4 - yoe / 100);
+ const unsigned mp = (5 * doy + 2) / 153;
+ const uint8_t d = static_cast