使用Moshi将字符串日期从json转换为Date对象

时间:2017-06-09 18:28:23

标签: android retrofit2 moshi

与Gson你会这样做

<nav id="nav" role="navigation">
  <a href="#nav" title="Show navigation"><font size="+2">MENU</font></a>
  <a href="#" title="Hide navigation"><font size="+2">HIDE MENU</font></a>
  <ul>
    <li><a href="index.html#quicknav"><b><font color="#CC9933">HOME:</font></b></a></li>

    <li>
      <a href="firstlevellink.html" title="I want to be seen on page load">FIRST LEVEL <img src="ddlevelsfiles/arrow-down.gif"></a>
      <ul>
        <li><a href="secondlevellink.html" title="I want to be hidden on page load">SECOND LEVEL LINK</a></li>
      </ul>
    </li>
  </ul>
</nav>

/* New Responsive Menu CSS */

#crumbs {
  width: 97%;
  overflow: hidden;
}

#nav {
  /* container */
  background: #333;
}

#nav > a {
  display: none;
}

#nav a {
  color: #FFF;
}

#nav li {
  position: relative;
  background: #CC9;
  color: #000;
  padding: 15px 15px;
  padding-bottom: 15px;
  border-bottom: 1px solid #333;
}


/* first level */

#nav > ul {
  font: bold 14px Verdana;
}

#nav li ul li a {
  color: black;
}

#nav > ul > li {
  height: 100%;
  float: left;
  padding: 15px 10px;
  background: #333;
}


/* second level */

#nav li ul {
  display: none;
  position: absolute;
  top: 100%;
  width: 100%;
}

#nav li:hover ul {
  display: block;
}

@media only screen and ( max-width: 640px)
/* 640 */

{
  #sticky-element {}
  .nav-container {}
  .f-nav {
    z-index: 9999;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
  }
  #nav {
    position: relative;
  }
  #nav > a {}
  #nav:not(:target) > a:first-of-type,
  #nav:target > a:last-of-type {
    display: block;
  }
  /* first level */
  #nav > ul {
    height: auto;
    display: none;
    position: absolute;
    left: 0;
    right: 0;
  }
  #nav:target > ul {
    display: block;
  }
  #nav > ul > li {
    width: 93%;
    float: none;
  }
  /* second level */
  #nav li ul {
    position: static;
  }
}

并将其传递给改造构建器,Gson将为您创建一个Date对象,是否有某种方法可以让Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm") .create(); 在kotlin类中执行此操作?

2 个答案:

答案 0 :(得分:16)

如果您想使用标准的ISO-8601 / RFC 3339日期适配器(您可能会这样做),那么您可以使用内置适配器:

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));

你需要这个Maven依赖来实现这个目的:

<dependency>
  <groupId>com.squareup.moshi</groupId>
  <artifactId>moshi-adapters</artifactId>
  <version>1.5.0</version>
</dependency>

如果你想使用自定义格式(你可能没有),那么代码就会更多。编写一个接受日期并将其格式化为字符串的方法,以及另一个接受字符串并将其解析为日期的方法。

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));

您需要记住使用synchronized因为SimpleDateFormat不是线程安全的。您还需要为SimpleDateFormat配置时区。

答案 1 :(得分:0)

在kotlin中,您可以扩展JsonAdapter类并创建自己的适配器:

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
    }
}

然后,在改造初始化中,您可以通过执行以下操作使用Moshi.Builder设置适配器:

 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)
        }