Skip to content

Commit 671b7f4

Browse files
feat: implement date/time and integer formatting functions (#659)
Implement the XPath 3.1 date/time and integer formatting functions per the W3C XPath Functions 3.1 specification (sections 4.6.1 and 9.8). Functions added: - fn:format-integer with 2-arg and 3-arg signatures supporting decimal digit patterns, Roman numerals (i/I), alphabetic (a/A), words (w/W/Ww), ordinal numbers, and grouping separators - fn:format-dateTime with 2-arg and 5-arg signatures - fn:format-date with 2-arg and 5-arg signatures - fn:format-time with 2-arg and 5-arg signatures Key capabilities: - Picture string parser supporting all 16 component specifiers (Y, M, D, d, F, W, w, H, h, P, m, s, f, Z, z, C, E) with presentation modifiers and width modifiers - Formatting engine with year modulo, fractional seconds, timezone (numeric, military, GMT prefix), named months/days, and ordinal support - Proper marker validation per value type (FOFD1350 for invalid markers) - Ordinal modifier falls back to cardinal for non-decimal format tokens - Safe Math.abs handling for Integer.MIN_VALUE year values - FormatFunctionException (FODF1310) and FormatDateTimeFunctionException (FOFD1340, FOFD1350) error classes Includes PRD documentation and 206 unit tests. Closes #283
1 parent 3a6248a commit 671b7f4

18 files changed

Lines changed: 5439 additions & 4 deletions

.claude/CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ For larger initiatives, use PRDs stored in `PRDs/<YYYYMMDD>-<name>/`:
191191
| PRD | Description | Status |
192192
|-----|-------------|--------|
193193
| `PRDs/20251206-build-cleanup/` | Build warnings and deprecation removal | In Progress |
194+
| `PRDs/20260207-format-datetime/` | Date/time formatting functions (issue #283) | In Progress |
194195

195196
### Completed PRDs
196197

PRDs/20260207-format-datetime/PRD.md

Lines changed: 527 additions & 0 deletions
Large diffs are not rendered by default.

PRDs/20260207-format-datetime/implementation-plan.md

Lines changed: 497 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* SPDX-FileCopyrightText: none
3+
* SPDX-License-Identifier: CC0-1.0
4+
*/
5+
6+
package dev.metaschema.core.metapath.function;
7+
8+
import dev.metaschema.core.metapath.IErrorCode;
9+
import edu.umd.cs.findbugs.annotations.NonNull;
10+
11+
/**
12+
* FOFD: Exceptions related to errors in formatting date/time values.
13+
*
14+
* @see <a href="https://www.w3.org/TR/xpath-functions-31/#formatting-dates">
15+
* XPath Functions 3.1 - Formatting Dates and Times</a>
16+
*/
17+
public class FormatDateTimeFunctionException
18+
extends FunctionMetapathError {
19+
@NonNull
20+
private static final String PREFIX = "FOFD";
21+
/**
22+
* <a href=
23+
* "https://www.w3.org/TR/xpath-functions-31/#ERRFOFD1340">err:FOFD1340</a>:
24+
* Raised when the picture string supplied to a date/time formatting function
25+
* does not conform to the required syntax.
26+
*/
27+
public static final int INVALID_PICTURE_STRING = 1340;
28+
/**
29+
* <a href=
30+
* "https://www.w3.org/TR/xpath-functions-31/#ERRFOFD1350">err:FOFD1350</a>:
31+
* Raised when a component specifier within a picture string refers to a
32+
* component that is not available in the value being formatted.
33+
*/
34+
public static final int COMPONENT_NOT_AVAILABLE = 1350;
35+
36+
/**
37+
* the serial version UID.
38+
*/
39+
private static final long serialVersionUID = 1L;
40+
41+
/**
42+
* Constructs a new exception with the provided {@code code}, {@code message},
43+
* and no cause.
44+
*
45+
* @param code
46+
* the error code value
47+
* @param message
48+
* the exception message
49+
*/
50+
public FormatDateTimeFunctionException(int code, String message) {
51+
super(IErrorCode.of(PREFIX, code), message);
52+
}
53+
54+
/**
55+
* Constructs a new exception with the provided {@code code}, {@code message},
56+
* and {@code cause}.
57+
*
58+
* @param code
59+
* the error code value
60+
* @param message
61+
* the exception message
62+
* @param cause
63+
* the original exception cause
64+
*/
65+
public FormatDateTimeFunctionException(int code, String message, Throwable cause) {
66+
super(IErrorCode.of(PREFIX, code), message, cause);
67+
}
68+
69+
/**
70+
* Constructs a new exception with the provided {@code code}, no message, and
71+
* the {@code cause}.
72+
*
73+
* @param code
74+
* the error code value
75+
* @param cause
76+
* the original exception cause
77+
*/
78+
public FormatDateTimeFunctionException(int code, Throwable cause) {
79+
super(IErrorCode.of(PREFIX, code), cause);
80+
}
81+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* SPDX-FileCopyrightText: none
3+
* SPDX-License-Identifier: CC0-1.0
4+
*/
5+
6+
package dev.metaschema.core.metapath.function;
7+
8+
import dev.metaschema.core.metapath.IErrorCode;
9+
import edu.umd.cs.findbugs.annotations.NonNull;
10+
11+
/**
12+
* FODF: Exceptions related to formatting errors in Metapath functions such as
13+
* {@code format-integer}, {@code format-number}, {@code format-dateTime}, and
14+
* {@code format-date}.
15+
*/
16+
public class FormatFunctionException
17+
extends FunctionMetapathError {
18+
@NonNull
19+
private static final String PREFIX = "FODF";
20+
/**
21+
* <a href=
22+
* "https://www.w3.org/TR/xpath-functions-31/#ERRFODF1310">err:FODF1310</a>:
23+
* Raised when a format token in a picture string is invalid.
24+
*/
25+
public static final int INVALID_FORMAT_TOKEN = 1310;
26+
27+
/**
28+
* the serial version UID.
29+
*/
30+
private static final long serialVersionUID = 1L;
31+
32+
/**
33+
* Constructs a new exception with the provided {@code code}, {@code message},
34+
* and no cause.
35+
*
36+
* @param code
37+
* the error code value
38+
* @param message
39+
* the exception message
40+
*/
41+
public FormatFunctionException(int code, String message) {
42+
super(IErrorCode.of(PREFIX, code), message);
43+
}
44+
45+
/**
46+
* Constructs a new exception with the provided {@code code}, {@code message},
47+
* and {@code cause}.
48+
*
49+
* @param code
50+
* the error code value
51+
* @param message
52+
* the exception message
53+
* @param cause
54+
* the original exception cause
55+
*/
56+
public FormatFunctionException(int code, String message, Throwable cause) {
57+
super(IErrorCode.of(PREFIX, code), message, cause);
58+
}
59+
60+
/**
61+
* Constructs a new exception with the provided {@code code}, no message, and
62+
* the {@code cause}.
63+
*
64+
* @param code
65+
* the error code value
66+
* @param cause
67+
* the original exception cause
68+
*/
69+
public FormatFunctionException(int code, Throwable cause) {
70+
super(IErrorCode.of(PREFIX, code), cause);
71+
}
72+
}

0 commit comments

Comments
 (0)