Turn date string from json into Date object using Moshi
If you like to use the standard ISO-8601 / RFC 3339 date adapter (you probably do), you can use the built-in adapter:
Moshi moshi = new Moshi.Builder()
.add(Date.class, new Rfc3339DateJsonAdapter().nullSafe())
.build();
JsonAdapter<Date> dateAdapter = moshi.adapter(Date.class);
assertThat(dateAdapter.fromJson("\"1985-04-12T23:20:50.52Z\""))
.isEqualTo(newDate(1985, 4, 12, 23, 20, 50, 520, 0));
You will need this Maven dependency to make this work:
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-adapters</artifactId>
<version>1.5.0</version>
</dependency>
If you want to use a custom format (you probably don't), theres more code. Write a method that takes a date and formats it for a string, and another method that takes a string and parses it as a date.
Object customDateAdapter = new Object() {
final DateFormat dateFormat;
{
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
}
@ToJson synchronized String dateToJson(Date d) {
return dateFormat.format(d);
}
@FromJson synchronized Date dateToJson(String s) throws ParseException {
return dateFormat.parse(s);
}
};
Moshi moshi = new Moshi.Builder()
.add(customDateAdapter)
.build();
JsonAdapter<Date> dateAdapter = moshi.adapter(Date.class);
assertThat(dateAdapter.fromJson("\"1985-04-12T23:20\""))
.isEqualTo(newDate(1985, 4, 12, 23, 20, 0, 0, 0));
You need to remember synchronized
because it is SimpleDateFormat
not thread safe. Also you need to configure the timezone for SimpleDateFormat
.
source to share
In kotlin, you can extend the class JsonAdapter
and create your own adapter:
class CustomDateAdapter : JsonAdapter<Date>() { private val dateFormat = SimpleDateFormat(SERVER_FORMAT, Locale.getDefault()) @FromJson override fun fromJson(reader: JsonReader): Date? { return try { val dateAsString = reader.nextString() dateFormat.parse(dateAsString) } catch (e: Exception) { null } } @ToJson override fun toJson(writer: JsonWriter, value: Date?) { if (value != null) { writer.value(value.toString()) } } companion object { const val SERVER_FORMAT = ("yyyy-MM-dd'T'HH:mm") // define your server format here } }
Then, in Retrofit initialization, you can install the adapter with Moshi.Builder
by running:
private val moshiBuilder = Moshi.Builder().add(CustomDateAdapter()) // Your custom date adapter here val service: ApiService by lazy { val loggingInterceptor = HttpLoggingInterceptor() loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY val httpClient = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build() val retrofit = Retrofit.Builder() .baseUrl(BuildConfig.API_URL) .client(httpClient) .addConverterFactory(MoshiConverterFactory.create(moshiBuilder.build())) .addCallAdapterFactory(CoroutineCallAdapterFactory()) .build() retrofit.create(ApiService::class.java) }
source to share