Time zones are not handled correctly
theisenp opened this issue · comments
Currently we require Instant
for both date and time arguments, which we then convert to a Long
before passing it on to the ICU library.
These types don't have an associated time zone, so when the ICU library formats them it uses the default system time zone. Probably a reasonable assumption for most use cases, but not all. For instance - the Android tests in our :tests
module fail if you don't run them on the east coast 🫠
Ah yeah I meant to fix this as a follow-up. The ICU code tragically calls Locale.getDefault()
internally rather than accepting superior types that contain timezone information.
The fix is a test rule that sets the location to a fixed locale and then resets it at the end of the test.
I can do it right now.
The underlying ICU library accepts three types for date and time arguments: Long
, Date
, Calendar
.
Calendar
includes time zone information, so we can potentially use that in cases where developers don't want to use the system default. And to have a consistent java.time
API, we could require ZonedDateTime
and map it to Calendar
internally.
Maybe we generate two methods? Something like:
fun release_description(release_date: Instant, release_time: Instant) {
// ...
}
fun release_description(release_date: ZonedDateTime, release_time: ZonedDateTime) {
// ...
}
Or I should say that ICU4J accepts com.ibm.icu.util.Calendar
- I haven't confirmed yet that the Android fork accepts android.icu.util.Calendar
Oof Calendar
is a brutally terrible type, but yeah if we can encapsulate it entirely as implementation detail then that's an excellent idea.
I think we can and should be more opinionated about what's generated based on which is used and what will be printed.
Dates never print time or time zone information, so for dates we should accept only LocalDate
:
fun some_resource(argName: LocalDate)
Times never print date information. short
, medium
, and long
times don't print time zone information; full
times do. So for all times we should accept a LocalTime
, and for full
times only we should accept a ZoneId
:
fun resource_with_long_time(argName: LocalTime)
fun resource_with_full_time(argName: LocalTime, argNameZone: ZoneId)
Skeletons can have an arbitrary combination of date, time, and time zone elements. But which symbols correspond to which type of elements is well-defined, so we can check skeleton strings and decide the correct arg type based on the combination of symbols: LocalDate
, LocalTime
, ZoneId
, LocalDateTime
if both date and time are present but no zone, or ZonedDateTime
if all three are present.
I wouldn't offer Instant
args for any of them; as a formatter with explicit date/time type differentiation I think it makes sense to force the consumer to be explicit about what they want.
Nice, I like the idea of requesting specifically what we need to resolve the argument!
Some of the the details regarding time
formatting were off in my previous comment; see #91 for details.