Skip to content

Commit 542d8dd

Browse files
committed
FEAT: letting MOLD/ALL on datetime value to produce ISO8601 valid result
Related issues: metaeducation/rebol-issues#438 metaeducation/rebol-issues#2089 metaeducation/rebol-issues#2092
1 parent 1ebbbc3 commit 542d8dd

File tree

4 files changed

+50
-21
lines changed

4 files changed

+50
-21
lines changed

src/core/s-mold.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1095,7 +1095,7 @@ STOID Mold_Error(REBVAL *value, REB_MOLD *mold, REBFLG molded)
10951095

10961096
case REB_TIME:
10971097
//len = Emit_Time(value, buf, Punctuation[GET_MOPT(mold, MOPT_COMMA_PT) ? PUNCT_COMMA : PUNCT_DOT]);
1098-
Emit_Time(mold, value);
1098+
Emit_Time(mold, value, FALSE);
10991099
break;
11001100

11011101
case REB_DATE:

src/core/t-date.c

+27-13
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
REBYTE *bp = &buf[0];
9696
REBINT tz;
9797
REBYTE dash = GET_MOPT(mold, MOPT_SLASH_DATE) ? '/' : '-';
98+
REBOOL iso = GET_MOPT(mold, MOPT_MOLD_ALL);
9899
REBVAL val = *value;
99100
value = &val;
100101

@@ -111,21 +112,30 @@
111112
if (VAL_TIME(value) != NO_TIME) Adjust_Date_Zone(value, FALSE);
112113

113114
// Punctuation[GET_MOPT(mold, MOPT_COMMA_PT) ? PUNCT_COMMA : PUNCT_DOT]
114-
115-
bp = Form_Int(bp, (REBINT)VAL_DAY(value));
116-
*bp++ = dash;
117-
memcpy(bp, Month_Names[VAL_MONTH(value)-1], 3);
118-
bp += 3;
119-
*bp++ = dash;
120-
bp = Form_Int_Pad(bp, (REBINT)VAL_YEAR(value), 6, -4, '0');
121-
*bp = 0;
122-
115+
if (iso) {
116+
// use ISO8601 output
117+
bp = Form_Int_Pad(bp, (REBINT)VAL_YEAR(value), 6, -4, '0');
118+
*bp = '-';
119+
bp = Form_Int_Pad(++bp, (REBINT)VAL_MONTH(value), 2, -2, '0');
120+
*bp = '-';
121+
bp = Form_Int_Pad(++bp, (REBINT)VAL_DAY(value), 2, -2, '0');
122+
*bp = 0;
123+
} else {
124+
// use standard Rebol output
125+
bp = Form_Int(bp, (REBINT)VAL_DAY(value));
126+
*bp++ = dash;
127+
memcpy(bp, Month_Names[VAL_MONTH(value) - 1], 3);
128+
bp += 3;
129+
*bp++ = dash;
130+
bp = Form_Int_Pad(bp, (REBINT)VAL_YEAR(value), 6, -4, '0');
131+
*bp = 0;
132+
}
123133
Append_Bytes(mold->series, cs_cast(buf));
124134

125135
if (VAL_TIME(value) != NO_TIME) {
126136

127-
Append_Byte(mold->series, '/');
128-
Emit_Time(mold, value);
137+
Append_Byte(mold->series, iso ? 'T' : '/');
138+
Emit_Time(mold, value, iso);
129139

130140
if (VAL_ZONE(value) != 0) {
131141

@@ -138,9 +148,13 @@
138148
else
139149
*bp++ = '+';
140150

141-
bp = Form_Int(bp, tz/4);
151+
if(iso) {
152+
bp = Form_Int_Pad(bp, tz / 4, 2, -2, '0');
153+
} else {
154+
bp = Form_Int(bp, tz / 4);
155+
}
142156
*bp++ = ':';
143-
bp = Form_Int_Pad(bp, (tz&3) * 15, 2, 2, '0');
157+
bp = Form_Int_Pad(bp, (tz & 3) * 15, 2, 2, '0');
144158
*bp = 0;
145159

146160
Append_Bytes(mold->series, cs_cast(buf));

src/core/t-time.c

+10-3
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,24 @@
135135

136136
/***********************************************************************
137137
**
138-
*/ void Emit_Time(REB_MOLD *mold, REBVAL *value)
138+
*/ void Emit_Time(REB_MOLD *mold, REBVAL *value, REBOOL iso)
139139
/*
140+
** NOTE: 'iso' arg is padding hour to two digits.
141+
** It is used only when MOLDing datetime with /ALL refinement.
142+
** In this datetime case hour should not be over 24.
140143
***********************************************************************/
141144
{
142145
REB_TIMEF tf;
143146
char *fmt;
144147

145148
Split_Time(VAL_TIME(value), &tf); // loses sign
146149

147-
if (tf.s == 0 && tf.n == 0) fmt = "I:2";
148-
else fmt = "I:2:2";
150+
if(iso) {
151+
fmt = "2:2:2";
152+
} else {
153+
if (tf.s == 0 && tf.n == 0) fmt = "I:2";
154+
else fmt = "I:2:2";
155+
}
149156

150157
if (VAL_TIME(value) < (REBI64)0) Append_Byte(mold->series, '-');
151158
Emit(mold, fmt, tf.h, tf.m, tf.s, 0);

src/tests/units/date-test.r3

+12-4
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ Rebol [
88

99
~~~start-file~~~ "date"
1010

11-
===start-group=== "ISO88601 subset"
12-
--test-- "ISO88601 basic load"
11+
===start-group=== "ISO8601 subset"
12+
--test-- "ISO8601 basic load"
1313
--assert 8-Nov-2013/17:01 = load "2013-11-08T17:01"
1414
--assert 8-Nov-2013/17:01 = load "2013-11-08T17:01Z"
1515
--assert 8-Nov-2013/17:01+1:00 = load "2013-11-08T17:01+0100"
1616
--assert 8-Nov-2013/17:01-1:00 = load "2013-11-08T17:01-0100"
1717
--assert 8-Nov-2013/17:01+1:00 = load "2013-11-08T17:01+01:00"
18-
--test-- "basic load of not fully standard ISO88601"
18+
--test-- "basic load of not fully standard ISO8601"
1919
--assert 8-Nov-2013/17:01 = load "2013/11/08T17:01"
2020
--assert 8-Nov-2013/17:01 = load "2013/11/08T17:01Z"
2121
--assert 8-Nov-2013/17:01+1:00 = load "2013/11/08T17:01+0100"
2222
--assert 8-Nov-2013/17:01+1:00 = load "2013/11/08T17:01+01:00"
23-
--test-- "Invalid ISO88601 dates"
23+
--test-- "Invalid ISO8601 dates"
2424
--assert error? try [load "2013-11-08T17:01Z0100"]
2525
--assert error? try [load "2013/11/08T17:01Z0100"]
2626

@@ -31,6 +31,14 @@ Rebol [
3131

3232
===end-group===
3333

34+
===start-group=== "MOLD/ALL on date"
35+
;-- producing ISO8601 valid result (https://tools.ietf.org/html/rfc3339)
36+
--test-- "MOLD/ALL on date"
37+
--assert "2000-01-01T01:02:03" = mold/all 1-1-2000/1:2:3
38+
--assert "2000-01-01T10:20:03" = mold/all 1-1-2000/10:20:3
39+
--assert "0200-01-01T01:02:03" = mold/all 1-1-200/1:2:3
40+
--assert "0200-01-01T01:02:03+02:00" = mold/all 1-1-200/1:2:3+2:0
41+
--assert "0200-01-01T01:02:03+10:00" = mold/all 1-1-200/1:2:3+10:0
3442

3543
===end-group===
3644

0 commit comments

Comments
 (0)