Skip to content

Commit 931722a

Browse files
authored
fix: handle parse/format of 12-hour h with one or two digits
fix: handle parse/format of 12-hour h with one or two digits
2 parents 554c68c + cab16c7 commit 931722a

File tree

6 files changed

+87
-11
lines changed

6 files changed

+87
-11
lines changed

jalalidate/src/commonMain/kotlin/ir/amirroid/jalalidate/formatter/FormatPart.kt

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,26 @@ internal class LiteralPart(val literal: String) : FormatPart {
3535
internal class NumericPart(
3636
override val name: String,
3737
val extractor: (JalaliDateTime) -> Int,
38-
val length: Int,
38+
val maxLength: Int = 2,
3939
val padding: Padding = Padding.ZERO
4040
) : FormatPart {
4141
override fun format(date: JalaliDateTime): String {
4242
val value = extractor(date)
4343
return when (padding) {
44-
Padding.ZERO -> value.toString().padStart(length, '0')
45-
Padding.SPACE -> value.toString().padStart(length, ' ')
44+
Padding.NONE -> value.toString()
45+
Padding.ZERO -> value.toString().padStart(maxLength, '0')
46+
Padding.SPACE -> value.toString().padStart(maxLength, ' ')
4647
}
4748
}
4849

4950
override fun parse(input: String, pos: Int): ParseResult {
50-
val endPos = pos + length
51-
if (endPos > input.length) throw IllegalArgumentException("Input too short for numeric part at $pos")
51+
val endPos = (pos + maxLength).coerceAtMost(input.length)
5252
val substring = input.substring(pos, endPos)
53-
val number = substring.trim().toIntOrNull()
54-
?: throw IllegalArgumentException("Invalid number at $pos")
55-
return ParseResult(number, endPos)
53+
54+
val numberStr = substring.takeWhile { it.isDigit() }
55+
if (numberStr.isEmpty()) throw IllegalArgumentException("Invalid number at $pos")
56+
val number = numberStr.toInt()
57+
return ParseResult(number, pos + numberStr.length)
5658
}
5759
}
5860

jalalidate/src/commonMain/kotlin/ir/amirroid/jalalidate/formatter/JalaliDateTimeFormatter.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import ir.amirroid.jalalidate.configuration.JalaliDateGlobalConfiguration
55
import ir.amirroid.jalalidate.date.JalaliDateTime
66
import kotlin.compareTo
77

8-
public enum class Padding { ZERO, SPACE }
8+
public enum class Padding { NONE, ZERO, SPACE }
99

1010
public enum class Locale { PERSIAN, ENGLISH }
1111

@@ -125,10 +125,10 @@ public class JalaliDateTimeFormatter {
125125
"d" -> NumericPart("day", { it.jalaliDay }, 1, Padding.ZERO)
126126

127127
"HH" -> NumericPart("hour", { it.hour }, 2, Padding.ZERO)
128-
"H" -> NumericPart("hour", { it.hour }, 1, Padding.ZERO)
128+
"H" -> NumericPart("hour", { it.hour }, 2, Padding.NONE)
129129

130130
"hh" -> NumericPart("hour", { it.hourIn12 }, 2, Padding.ZERO)
131-
"h" -> NumericPart("hour", { it.hourIn12 }, 1, Padding.ZERO)
131+
"h" -> NumericPart("hour", { it.hourIn12 }, 2, Padding.NONE)
132132

133133
"mm" -> NumericPart("minute", { it.minute }, 2, Padding.ZERO)
134134
"m" -> NumericPart("minute", { it.minute }, 1, Padding.ZERO)

jalalidate/src/commonTest/kotlin/ir/amirroid/jalalidate/birashk/FormatTest.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,26 @@ class FormatTest {
184184
val formatted = date.format { byUnicodePattern("yyyy/MM/dd hh:mm a") }
185185
assertEquals("1402/01/01 11:15 PM", formatted)
186186
}
187+
188+
@Test
189+
fun formatHourIn12HourFormatWithAmPm() {
190+
val date1 = JalaliDateTime(1402, 1, 1, 13, 5, 0) // 1:05 PM
191+
val formatted1 = date1.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
192+
assertEquals("1402/01/01 1:05 PM", formatted1)
193+
194+
val date2 = JalaliDateTime(1402, 1, 1, 23, 15, 0) // 11:15 PM
195+
val formatted2 = date2.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
196+
assertEquals("1402/01/01 11:15 PM", formatted2)
197+
198+
val date3 = JalaliDateTime(1402, 1, 1, 9, 0, 0) // 9:00 AM
199+
val formatted3 = date3.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
200+
assertEquals("1402/01/01 9:00 AM", formatted3)
201+
}
202+
203+
@Test
204+
fun hour24FormatSingleDigit() {
205+
val date = JalaliDateTime(1402, 1, 1, 7, 5, 0)
206+
val formatted = date.format { byUnicodePattern("yyyy/MM/dd H:mm") }
207+
assertEquals("1402/01/01 7:05", formatted)
208+
}
187209
}

jalalidate/src/commonTest/kotlin/ir/amirroid/jalalidate/birashk/ParseTest.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,4 +285,18 @@ class ParseTest {
285285
assertEquals(23, date.hour)
286286
assertEquals(15, date.minute)
287287
}
288+
289+
@Test
290+
fun parseHourIn12HourFormatWithVariableLength() {
291+
val format = JalaliDateTime.Format { byUnicodePattern("yyyy/MM/dd h:mm a") }
292+
293+
val date1 = format.parse("1402/01/01 1:05 PM")
294+
assertEquals(13, date1.hour) // 1 PM -> 13
295+
296+
val date2 = format.parse("1402/01/01 11:15 PM")
297+
assertEquals(23, date2.hour) // 11 PM -> 23
298+
299+
val date3 = format.parse("1402/01/01 9:00 AM")
300+
assertEquals(9, date3.hour) // 9 AM -> 9
301+
}
288302
}

jalalidate/src/commonTest/kotlin/ir/amirroid/jalalidate/khayyam/FormatTest.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,4 +182,26 @@ class FormatTest {
182182
val formatted = date.format { byUnicodePattern("yyyy/MM/dd hh:mm a") }
183183
assertEquals("1402/01/01 11:15 PM", formatted)
184184
}
185+
186+
@Test
187+
fun formatHourIn12HourFormatWithAmPm() {
188+
val date1 = JalaliDateTime(1402, 1, 1, 13, 5, 0) // 1:05 PM
189+
val formatted1 = date1.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
190+
assertEquals("1402/01/01 1:05 PM", formatted1)
191+
192+
val date2 = JalaliDateTime(1402, 1, 1, 23, 15, 0) // 11:15 PM
193+
val formatted2 = date2.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
194+
assertEquals("1402/01/01 11:15 PM", formatted2)
195+
196+
val date3 = JalaliDateTime(1402, 1, 1, 9, 0, 0) // 9:00 AM
197+
val formatted3 = date3.format { byUnicodePattern("yyyy/MM/dd h:mm a") }
198+
assertEquals("1402/01/01 9:00 AM", formatted3)
199+
}
200+
201+
@Test
202+
fun hour24FormatSingleDigit() {
203+
val date = JalaliDateTime(1402, 1, 1, 7, 5, 0)
204+
val formatted = date.format { byUnicodePattern("yyyy/MM/dd H:mm") }
205+
assertEquals("1402/01/01 7:05", formatted)
206+
}
185207
}

jalalidate/src/commonTest/kotlin/ir/amirroid/jalalidate/khayyam/ParseTest.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package ir.amirroid.jalalidate.khayyam
22

33
import ir.amirroid.jalalidate.algorithm.defaults.KhayyamAlgorithm
4+
import ir.amirroid.jalalidate.date.JalaliDateTime
5+
import ir.amirroid.jalalidate.format
46
import ir.amirroid.jalalidate.formatter.JalaliDateTimeFormatter
57
import kotlin.test.Test
68
import kotlin.test.assertEquals
@@ -283,4 +285,18 @@ class ParseTest {
283285
assertEquals(23, date.hour)
284286
assertEquals(15, date.minute)
285287
}
288+
289+
@Test
290+
fun parseHourIn12HourFormatWithVariableLength() {
291+
val format = JalaliDateTime.Format { byUnicodePattern("yyyy/MM/dd h:mm a") }
292+
293+
val date1 = format.parse("1402/01/01 1:05 PM")
294+
assertEquals(13, date1.hour) // 1 PM -> 13
295+
296+
val date2 = format.parse("1402/01/01 11:15 PM")
297+
assertEquals(23, date2.hour) // 11 PM -> 23
298+
299+
val date3 = format.parse("1402/01/01 9:00 AM")
300+
assertEquals(9, date3.hour) // 9 AM -> 9
301+
}
286302
}

0 commit comments

Comments
 (0)