Home > Software design >  Android retrofit - date format when passing datetime by URL
Android retrofit - date format when passing datetime by URL

Time:01-28

I have API method mapping like this

@POST("api/updateStarted/{id}/{started}")
suspend fun updateStarted(
    @Path("id") id: Int,
    @Path("started") started: Date
) : Response <Int>

I want to use yyyy-MM-dd'T'HH:mm:ss format everywhere. My API adapter looks like this:

val gson = GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss")

val apiClient: ApiClient = Retrofit.Builder()
    .addConverterFactory(GsonConverterFactory.create(gson.create()))
    .baseUrl(API_BASE_URL)
    .client(getHttpClient(API_USERNAME, API_PASSWORD))
    .addConverterFactory(GsonConverterFactory.create())
    .build()
    .create(ApiClient::class.java)

However GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss") cannot affect date format when I pass it thru URL (because that's not JSON) so Retrofit builds URL like this:

http://myserver.com/api/updateFinished/2/Fri Jan 27 13:48:42 GMT 01:00 2023 

instead of something like this:

http://myserver.com/api/updateFinished/2/2023-01-28T02:03:04.000

How can I fix that? I'm new in Retrofit and I don't fully understand date/time libraries in Java.

CodePudding user response:

GsonConverterFactory supports responseBodyConverter and requestBodyConverter which aren't used to convert URL params. For that, you need a stringConverter which, fortunately is trivial to implement:

class MyToStringConverter : Converter<SomeClass, String> {
    override fun convert(value: SomeClass): String {
        return formatToUrlParam(value)
    }

    companion object {
        val INSTANCE = MyToStringConverter()
    }
}

class MyConverterFactory : Converter.Factory() {
    override fun stringConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit): Converter<*, String>? {
        return if (type == SomeClass::class.java) {
            //extra check to make sure the circumstances are correct:
            if (annotations.any { it is retrofit2.http.Query }) {
                MyToStringConverter.INSTANCE
            } else {
                null
            }
        } else {
            null
        }
    }
}

I've added checking for annotations as example if one would want tighter control on when the converter is used.

CodePudding user response:

You can switch the data type from java.util.Date to java.time.LocalDateTime if you want your desired format using the toString() method of that data type.

Currently, you have Date.toString() producing an undesired result.

If you don't have to use a Date, import java.time.LocalDateTime and just change your fun a little to this:

@POST("api/updateStarted/{id}/{started}")
suspend fun updateStarted(
    @Path("id") id: Int,
    @Path("started") started: LocalDateTime
) : Response <Int>
  • Related