Skip to content

Commit 71fc711

Browse files
committed
Finish testing
1 parent bf6e723 commit 71fc711

File tree

2 files changed

+176
-34
lines changed

2 files changed

+176
-34
lines changed

core/native/src/Instant.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ private class UnboundedLocalDateTime(
189189
// org.threeten.bp.chrono.ChronoLocalDateTime#toEpochSecond
190190
epochDays * 86400L + daySeconds - offsetSeconds
191191
}
192+
if (epochSeconds < Instant.MIN.epochSeconds || epochSeconds > Instant.MAX.epochSeconds)
193+
throw DateTimeFormatException(
194+
"The parsed date is outside the range representable by Instant (Unix epoch second $epochSeconds)"
195+
)
192196
return Instant.fromEpochSeconds(epochSeconds, nanosecond)
193197
}
194198

core/native/test/InstantIsoStringsTest.kt

Lines changed: 172 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,187 @@
55

66
package kotlinx.datetime
77

8+
import kotlin.math.absoluteValue
9+
import kotlin.time.Duration.Companion.seconds
810
import kotlin.test.*
911

1012
class InstantIsoStringsTest {
1113

1214
@Test
13-
fun parseAndFormatCanonicalStrings() {
14-
for (canonicalString in arrayOf(
15-
"1970-01-01T00:00:00Z",
16-
"1970-01-01T00:00:00.100Z",
17-
"1970-01-01T00:00:00.010Z",
18-
"1970-01-01T00:00:00.001Z",
19-
"1970-01-01T00:00:00.000100Z",
20-
"1970-01-01T00:00:00.000010Z",
21-
"1970-01-01T00:00:00.000001Z",
22-
"1970-01-01T00:00:00.000000100Z",
23-
"1970-01-01T00:00:00.000000010Z",
24-
"1970-01-01T00:00:00.000000001Z",
15+
fun parseDates() {
16+
fun Int.zeroPadded(digits: Int): String = when {
17+
this >= 0 -> "${toString().padStart(digits, '0')}"
18+
else -> "-${absoluteValue.toString().padStart(digits, '0')}"
19+
}
20+
fun localDateToString(year: Int, month: Int, day: Int) =
21+
"${year.zeroPadded(4)}-${month.zeroPadded(2)}-${day.zeroPadded(2)}"
22+
// only works for 1-4-digit years
23+
fun assertMonthBoundariesAreCorrect(year: Int, month: Int, lastDayOfMonth: Int) {
24+
val validString = "${localDateToString(year, month, lastDayOfMonth)}T23:59:59Z"
25+
val invalidString = "${localDateToString(year, month, lastDayOfMonth + 1)}T23:59:59Z"
26+
parseInstant(validString) // shouldn't throw
27+
assertInvalidFormat(invalidString) { parseInstant(invalidString) }
28+
}
29+
val nonLeapYears = listOf(
30+
1970, 1971, 1973, 1974, 1975, 2021, 2022, 2023, 2100, 1100, 1, 2, 3, 5, -1, -2, -1971, 100, -100
31+
)
32+
val leapYears = listOf(
33+
0, 1972, 1976, 1980, 2000, 1200, 400, -400, -4, -8,
34+
)
35+
for ((month, lastDayOfMonth) in arrayOf(
36+
1 to 31, 3 to 31, 4 to 30, 5 to 31, 6 to 30,
37+
7 to 31, 8 to 31, 9 to 30, 10 to 31, 11 to 30, 12 to 31,
2538
)) {
26-
val instant = parseInstant(canonicalString)
27-
assertEquals(canonicalString, instant.toString())
39+
for (year in nonLeapYears + leapYears) {
40+
assertMonthBoundariesAreCorrect(year, month, lastDayOfMonth)
41+
}
42+
}
43+
for (leapYear in leapYears) {
44+
assertMonthBoundariesAreCorrect(leapYear, 2, 29)
45+
}
46+
for (nonLeapYear in nonLeapYears) {
47+
assertMonthBoundariesAreCorrect(nonLeapYear, 2, 28)
2848
}
2949
}
3050

3151
@Test
3252
fun parseIsoString() {
3353
for ((str, seconds, nanos) in arrayOf(
34-
// both upper and lower case is supported
35-
Triple("1970-01-01T00:00:00Z", 0, 0),
36-
Triple("1970-01-01t00:00:00Z", 0, 0),
37-
Triple("1970-01-01T00:00:00z", 0, 0),
38-
Triple("1970-01-01T00:00:00.0Z", 0, 0),
3954
// all components are taken into accout
40-
Triple("1970-01-01T00:00:00.000000000Z", 0, 0),
55+
Triple("1970-01-01T00:00:00Z", 0, 0),
4156
Triple("1970-01-01T00:00:00.000000001Z", 0, 1),
42-
Triple("1970-01-01T00:00:00.100000000Z", 0, 100000000),
57+
Triple("1970-01-01T00:00:00.100Z", 0, 100000000),
4358
Triple("1970-01-01T00:00:01Z", 1, 0),
4459
Triple("1970-01-01T00:01:00Z", 60, 0),
4560
Triple("1970-01-01T00:01:01Z", 61, 0),
4661
Triple("1970-01-01T00:01:01.000000001Z", 61, 1),
47-
Triple("1970-01-01T01:00:00.000000000Z", 3600, 0),
62+
Triple("1970-01-01T01:00:00Z", 3600, 0),
4863
Triple("1970-01-01T01:01:01.000000001Z", 3661, 1),
49-
Triple("1970-01-02T01:01:01.100000000Z", 90061, 100000000),
50-
Triple("1970-02-02T01:01:01.100000000Z", 31 * 86400 + 90061, 100000000),
51-
Triple("1971-02-02T01:01:01.100000000Z", (365 + 31) * 86400 + 90061, 100000000),
64+
Triple("1970-01-02T01:01:01.100Z", 90061, 100000000),
65+
Triple("1970-02-02T01:01:01.100Z", 31 * 86400 + 90061, 100000000),
66+
Triple("1971-02-02T01:01:01.100Z", (365 + 31) * 86400 + 90061, 100000000),
67+
// how many digits get output for various precision of the sub-second portion
68+
Triple("1970-01-01T00:00:00.100Z", 0, 100_000_000),
69+
Triple("1970-01-01T00:00:00.010Z", 0, 10_000_000),
70+
Triple("1970-01-01T00:00:00.001Z", 0, 1_000_000),
71+
Triple("1970-01-01T00:00:00.000100Z", 0, 100_000),
72+
Triple("1970-01-01T00:00:00.000010Z", 0, 10_000),
73+
Triple("1970-01-01T00:00:00.000001Z", 0, 1_000),
74+
Triple("1970-01-01T00:00:00.000000100Z", 0, 100),
75+
Triple("1970-01-01T00:00:00.000000010Z", 0, 10),
76+
Triple("1970-01-01T00:00:00.000000001Z", 0, 1),
77+
// random data queried from java.time
78+
Triple("+51861-09-21T11:07:43.782719883Z", 1574430692863, 782719883),
79+
Triple("+395069-04-30T01:28:37.454777349Z", 12405016603717, 454777349),
80+
Triple("-551259-03-05T08:01:36.195722269Z", -17458215523104, 195722269),
81+
Triple("+498403-02-11T17:47:05.156642423Z", 15665915958425, 156642423),
82+
Triple("+283686-10-14T23:00:25.666521845Z", 8890123158025, 666521845),
83+
Triple("-910329-04-04T09:27:54.456784744Z", -28789367639526, 456784744),
84+
Triple("-37222-03-21T18:04:37.006055123Z", -1236773166923, 6055123),
85+
Triple("-189377-03-30T01:37:14.288808090Z", -6038320515766, 288808090),
86+
Triple("-67394-03-24T03:19:41.794404047Z", -2188909341619, 794404047),
87+
Triple("-870649-05-27T13:47:39.925150102Z", -27537183223941, 925150102),
88+
Triple("+94020-04-10T14:51:21.569206089Z", 2904826114281, 569206089),
89+
Triple("-945485-07-11T23:28:58.240153828Z", -29898775384262, 240153828),
90+
Triple("-73722-02-22T11:19:54.364548772Z", -2388604250406, 364548772),
91+
Triple("-645899-05-17T16:44:21.522135477Z", -20444759104539, 522135477),
92+
Triple("-702594-10-20T10:13:53.212104714Z", -22233867083167, 212104714),
93+
Triple("-442579-11-22T01:35:44.591216727Z", -14028583357456, 591216727),
94+
Triple("-849915-06-25T01:28:27.625015449Z", -26882878833093, 625015449),
95+
Triple("-481897-08-13T05:44:47.077814711Z", -15269348340913, 77814711),
96+
Triple("+295919-02-07T15:47:37.850981753Z", 9276137682457, 850981753),
97+
Triple("+967334-01-15T15:08:10.235167075Z", 30463946694490, 235167075),
98+
Triple("+774237-04-30T16:00:32.810606451Z", 24370403011232, 810606451),
99+
Triple("+792959-05-03T08:18:31.616194572Z", 24961212490711, 616194572),
100+
Triple("-261823-02-16T03:17:35.085815500Z", -8324498983345, 85815500),
101+
Triple("+931062-03-22T17:04:54.135075640Z", 29319318637494, 135075640),
102+
Triple("+623320-01-26T03:08:05.121769356Z", 19607914264085, 121769356),
103+
Triple("+322804-03-06T11:31:24.788006817Z", 10124548774284, 788006817),
104+
Triple("-784322-04-03T21:25:19.666588404Z", -24812970806081, 666588404),
105+
Triple("+403293-01-07T05:59:41.601460200Z", 12664531288781, 601460200),
106+
Triple("-835821-06-01T00:52:15.782852248Z", -26438117296065, 782852248),
107+
Triple("+222483-07-15T08:29:55.019931345Z", 6958735086595, 19931345),
108+
Triple("-663595-09-05T04:36:24.110433196Z", -21003181356216, 110433196),
109+
Triple("+166626-02-15T22:16:34.070665743Z", 5196045449794, 70665743),
110+
Triple("-517158-01-02T22:52:24.155574933Z", -16382097162456, 155574933),
111+
Triple("+850155-01-02T10:25:31.349473798Z", 26766133467931, 349473798),
112+
Triple("-967697-04-25T20:43:33.328060156Z", -30599725115787, 328060156),
113+
Triple("+437131-04-26T07:32:58.134219875Z", 13732364705578, 134219875),
114+
Triple("+372920-11-25T13:38:22.852562723Z", 11706079786702, 852562723),
115+
Triple("+169255-09-07T11:28:18.481625778Z", 5279026303698, 481625778),
116+
Triple("-980786-08-18T17:05:22.581779094Z", -31012764044078, 581779094),
117+
Triple("+182945-05-25T20:39:24.545585221Z", 5711031952764, 545585221),
118+
Triple("+300811-12-15T02:53:38.676752671Z", 9430541175218, 676752671),
119+
Triple("-807816-01-18T18:04:26.291749218Z", -25554376389334, 291749218),
120+
Triple("-53033-12-30T22:02:01.398533618Z", -1735695568679, 398533618),
121+
Triple("-354903-06-14T10:08:46.111648055Z", -11261809864274, 111648055),
122+
Triple("+842009-03-11T23:58:06.537554993Z", 26509076495886, 537554993),
123+
Triple("-391976-11-09T04:16:17.862484469Z", -12431707962223, 862484469),
124+
Triple("-733019-10-28T17:07:13.450343935Z", -23193986539967, 450343935),
125+
Triple("+595280-03-05T23:36:27.765851400Z", 18723060833787, 765851400),
126+
Triple("-930296-07-17T03:33:33.094509320Z", -29419456335987, 94509320),
127+
Triple("+609508-02-29T10:58:02.703241053Z", 19172052557882, 703241053),
128+
Triple("+996233-06-25T06:01:55.647461964Z", 31375924927315, 647461964),
129+
Triple("-93200-12-06T21:29:56.140938343Z", -3003245692204, 140938343),
130+
Triple("+794143-07-02T09:49:35.585085194Z", 24998581100975, 585085194),
131+
Triple("-783550-12-31T17:10:16.577723428Z", -24788585371784, 577723428),
132+
Triple("-240168-11-03T17:22:09.108424624Z", -7641110702271, 108424624),
133+
Triple("+613419-02-15T12:00:07.012460989Z", 19295470641607, 12460989),
134+
Triple("-521405-03-25T02:03:46.552711998Z", -16516112536574, 552711998),
135+
Triple("-938829-01-22T16:48:43.582709371Z", -29688747030677, 582709371),
136+
Triple("+916785-05-16T21:54:45.983221956Z", 28868784818085, 983221956),
137+
Triple("+482425-06-09T04:24:32.683186155Z", 15161709183872, 683186155),
138+
Triple("+622585-08-20T05:45:52.555088343Z", 19584737819152, 555088343),
139+
Triple("-451048-11-02T01:49:29.076392891Z", -14295840847831, 76392891),
140+
Triple("+721083-09-17T00:31:34.648020241Z", 22693036811494, 648020241),
141+
Triple("+235979-10-28T12:07:33.706273641Z", 7384636728453, 706273641),
142+
Triple("+285234-04-12T18:30:25.215363003Z", 8938957285825, 215363003),
143+
Triple("-917176-03-10T10:03:25.943265324Z", -29005440213395, 943265324),
144+
Triple("-381932-09-05T02:47:17.004960541Z", -12114755529163, 4960541),
145+
Triple("-52158-11-11T09:38:45.489915403Z", -1708087530075, 489915403),
146+
Triple("-584290-11-15T20:15:24.377620606Z", -18500551127076, 377620606),
147+
Triple("-645616-05-05T17:36:59.941608628Z", -20435829488581, 941608628),
148+
Triple("+794405-06-22T21:08:20.853641989Z", 25006848239300, 853641989),
149+
Triple("+986590-08-01T05:15:25.827177433Z", 31071624470125, 827177433),
150+
Triple("+527158-02-06T12:34:35.088546391Z", 16573335654875, 88546391),
151+
Triple("-513116-05-01T07:28:44.448204123Z", -16254533665876, 448204123),
152+
Triple("+397065-10-19T21:59:05.831855226Z", 12468019211945, 831855226),
153+
Triple("+312769-04-26T11:33:07.802217284Z", 9807879123187, 802217284),
154+
Triple("+682473-04-14T01:00:38.067076018Z", 21474609498038, 67076018),
155+
Triple("+731560-02-15T02:15:06.599802467Z", 23023640456106, 599802467),
156+
Triple("-877354-10-27T22:55:02.723751549Z", -27748759338298, 723751549),
157+
Triple("-746193-01-02T07:19:56.258497483Z", -23609743807204, 258497483),
158+
Triple("-822112-07-28T08:55:19.319285417Z", -26005498038281, 319285417),
159+
Triple("-400365-04-30T00:05:51.210582736Z", -12696455980449, 210582736),
160+
Triple("+436254-07-11T18:08:06.937065549Z", 13704695921286, 937065549),
161+
Triple("-340854-01-07T03:17:32.367173472Z", -10818479997748, 367173472),
162+
Triple("-985221-04-25T22:57:01.511559459Z", -31152729085379, 511559459),
163+
Triple("+859861-09-01T02:21:20.289341591Z", 27072446149280, 289341591),
164+
Triple("-0131-07-16T10:47:54.756333457Z", -66284140326, 756333457),
165+
Triple("-327041-11-18T22:55:21.885337272Z", -10382556503079, 885337272),
166+
Triple("-268616-05-06T10:27:54.420166505Z", -8538858480726, 420166505),
167+
Triple("-228012-05-16T15:26:54.680432991Z", -7257519160386, 680432991),
168+
Triple("+857168-09-12T13:29:36.945689251Z", 26987464272576, 945689251),
169+
Triple("-974181-04-12T08:47:35.627678735Z", -30804341526745, 627678735),
170+
Triple("-435700-10-20T22:33:13.897477229Z", -13811505874007, 897477229),
171+
Triple("-507467-01-19T23:06:05.156792267Z", -16076277276835, 156792267),
172+
Triple("-382257-11-19T08:00:10.407963305Z", -12125005142390, 407963305),
173+
Triple("+83082-01-04T20:18:56.409867424Z", 2559647852336, 409867424),
174+
Triple("-916839-09-12T22:45:39.091941363Z", -28994789466861, 91941363),
175+
Triple("-147771-05-07T08:31:34.950238979Z", -4725358615706, 950238979),
176+
)) {
177+
val instant = parseInstant(str)
178+
assertEquals(
179+
seconds.toLong() * 1000 + nanos / 1000000, instant.toEpochMilliseconds(),
180+
"Parsed $instant from $str, with Unix time = `$seconds + 10^-9 * $nanos`"
181+
)
182+
assertEquals(str, formatIso(instant))
183+
}
184+
// non-canonical strings are parsed as well, but formatted differently
185+
for ((str, seconds, nanos) in arrayOf(
186+
// upper, lower case, trailing zeros
187+
Triple("2024-07-15T14:06:29.461245000z", 1721052389, 461245000),
188+
Triple("2024-07-15t14:06:29.4612450z", 1721052389, 461245000),
52189
// current time
53190
Triple("2024-07-15T16:06:29.461245691+02:00", 1721052389, 461245691),
54191
)) {
@@ -213,9 +350,12 @@ class InstantIsoStringsTest {
213350
val instants = listOf(
214351
Instant.DISTANT_FUTURE,
215352
Instant.DISTANT_PAST,
216-
Instant.fromEpochSeconds(0, 0))
353+
Instant.fromEpochSeconds(0, 0),
354+
Instant.parse("2020-01-02T03:04:05.6789Z"),
355+
Instant.MAX,
356+
Instant.MIN,
357+
)
217358

218-
/*
219359
val offsets = listOf(
220360
0 to "Z",
221361
3 * 3600 + 12 * 60 + 14 to "+03:12:14",
@@ -228,15 +368,13 @@ class InstantIsoStringsTest {
228368

229369
for (instant in instants) {
230370
for ((offsetSeconds, offsetString) in offsets) {
231-
val str = instant.format(DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET, offsets[offsetIx])
232-
val offsetString = offsets[offsetIx].toString()
233-
assertEquals(offsetString, offsetString.commonSuffixWith(str))
234-
assertEquals(instant, Instant.parse(str, DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET))
235-
assertEquals(instant, Instant.parse(str))
371+
if (instant == Instant.MAX && offsetSeconds < 0 ||
372+
instant == Instant.MIN && offsetSeconds > 0
373+
) continue
374+
val newInstant = Instant.parse("${instant.toString().dropLast(1)}$offsetString")
375+
assertEquals(newInstant, instant.minus(offsetSeconds.seconds))
236376
}
237377
}
238-
239-
*/
240378
}
241379

242380
private fun parseInstant(isoString: String): Instant {

0 commit comments

Comments
 (0)