【问题标题】:java.time.format.DateTimeParseException: Text '20/10/2019' could not be parsed at index 0java.time.format.DateTimeParseException:无法在索引 0 处解析文本“20/10/2019”
【发布时间】:2020-02-16 15:53:25
【问题描述】:

我正在开发新闻,在我的适配器类中我遇到了异常

埃德加,[20.10.19 13:50]

java.time.format.DateTimeParseException: 文本 '20/10/2019' 不能 在索引 0 处解析 java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1948) 在 java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851) 在 java.time.LocalDateTime.parse(LocalDateTime.java:486) 在 java.time.LocalDateTime.parse(LocalDateTime.java:471) 在 yodgorbek.komilov.musobaqayangiliklari.adapter.BBCSportAdapter.onBindViewHolder(BBCSportAdapter.kt:83) 在 androidx.recyclerview.widget.RecyclerView$Adapter.onBindViewHolder(RecyclerView.java:6781) 在 androidx.recyclerview.widget.RecyclerView$Adapter.bindViewHolder(RecyclerView.java:6823) 在 androidx.recyclerview.widget.RecyclerView$Recycler.tryBindViewHolderByDeadline(RecyclerView.java:5752) 在 androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6019) 在 androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5858) 在 androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5854) 在 androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2230) 在 androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1557) 在 androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1517) 在 androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:612) 在 androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3924) 在 androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:3336) 在 android.view.View.measure(View.java:22260) 在 androidx.constraintlayout.widget.ConstraintLayout.internalMeasureChildren(ConstraintLayout.java:1227) 在 androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1572) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:185) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:185) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:185) 在 androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:143) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:403) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:185) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1514) 在 android.widget.LinearLayout.measureVertical(LinearLayout.java:806) 在 android.widget.LinearLayout.onMeasure(LinearLayout.java:685) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6686) 在 android.widget.FrameLayout.onMeasure(FrameLayout.java:185) 在 com.android.internal.policy.DecorView.onMeasure(DecorView.java:728) 在 android.view.View.measure(View.java:22260) 在 android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2569) 在 android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1594) 在 android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1862) 在 android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1482) 在 android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7124) 在 android.view.Choreographer$CallbackRecord.run(Choreographer.java:1008) 在 android.view.Choreographer.doCallbacks(Choreographer.java:804) 在 android.view.Choreographer.doFrame(Choreographer.

在 MyAdapter 类下

class BBCSportAdapter(private val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    var articleList: List<Article> = listOf()
    companion object {
        const val urlKey = "urlKey"
        const val imageUrl = "imageUrl"
    }


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.bbc_sport_item, null)
        return ViewHolder(view)
    }

    @SuppressLint("NewApi")
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

        (holder as ViewHolder).apply {
            when(position){
                0 -> {
                    header.visibility = ViewGroup.VISIBLE
                    item.visibility = ViewGroup.GONE

                    Picasso.get().load(articleList[position].urlToImage)
                        .into(bigImage)
                }
                else -> {
                    header.visibility = ViewGroup.GONE
                    item.visibility = ViewGroup.VISIBLE

                    articleTitle.text = articleList[position].title
                    articleSourceName.text = articleList[position].source.name
                    Picasso.get().load(articleList[position].urlToImage).into(image)
                    val input = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX", Locale.getDefault())
                    val output = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault())
                    var d = Date()
                    try {
                        d = input.parse(articleList[5].publishedAt)
                    } catch (e: ParseException) {
                        try {
                            val fallback = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault())
                            fallback.timeZone = TimeZone.getTimeZone("UTC")
                            d = fallback.parse(articleList[5].publishedAt)
                        } catch (e2: ParseException) {
                            // TODO handle error
                            val formatted = output.format(d)
                            val timelinePoint = LocalDateTime.parse(formatted)
                            val now = LocalDateTime.now()

                            val elapsedTime = Duration.between(timelinePoint, now)

                            println(timelinePoint)
                            println(now)
                            elapsedTime.toMinutes()

                            articleTime.text = "${elapsedTime.toMinutes()}"

                            holder.itemView.setOnClickListener { v->
                                val intent = Intent(v.context, DetailActivity::class.java)
                                intent.putExtra("urlKey", articleList[position].url)
                                intent.putExtra("imageUrl", articleList[position].urlToImage)
                                v.context.startActivity(intent)
                            }
                        }
                    }
                }
            }
        }
    }
    override fun getItemCount(): Int {
        return articleList.size
    }

    fun setMovieListItems(articleList: List<Article>) {
        this.articleList = articleList
        notifyDataSetChanged()
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val image: ImageView = itemView.imageView
        val articleTitle: TextView = itemView.articleTitle
        val articleSourceName: TextView = itemView.articleSourceName
        val imageCategory: ImageView = itemView.imageCategory
        val articleTime: TextView = itemView.articleTime

        val bigImage = itemView.bigImage
        val header: CardView = itemView.header
        val item: CardView = itemView.item
    }
}

在 Fragment 类下

class BBCSportFragment : Fragment() {

    private val listViewType: List<Int> = listOf()

    var bbcSportAdapter : BBCSportAdapter? = null




    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_sport_bbc, container, false)

        val recyclerView = view.findViewById (R.id.recyclerView) as RecyclerView
        bbcSportAdapter = BBCSportAdapter(recyclerView.context)

        recyclerView.layoutManager = LinearLayoutManager(context)
        recyclerView.adapter = bbcSportAdapter


        val apiInterface = SportNewsInterface.create().getBBCSport()

// Getting interface
        apiInterface.enqueue(object : Callback<SportNewsResponse> {
            override fun onResponse(
                call: Call<SportNewsResponse>?,
                response: Response<SportNewsResponse>?
            ) {

                if (response!!.body() != null) {
                    bbcSportAdapter!!.setMovieListItems(response.body()!!.articles)
                }
            }

            override fun onFailure(call: Call<SportNewsResponse>?, t: Throwable?) {

            }
        })


        return view
    }

}

【问题讨论】:

标签: kotlin android-recyclerview date-formatting datetime-parsing java-time


【解决方案1】:

按照我阅读您的代码的方式,您会收到一个publishedAt 字符串,它应该看起来像2019-10-21T15:12:34+022019-10-21T13:01:23Z。如果无法解析,则说明您的代码尝试使用从var d = Date() 获取的日期和时间,即当前时间。

java.time

当您知道如何操作时,它可以很容易地完成。很抱歉,我只能编写 Java 代码。我需要相信你会自己翻译。

    String publishedAt = "2019-10-21T13:01:23Z";
    Instant timelinePoint;
    try {
        timelinePoint = DateTimeFormatter.ISO_OFFSET_DATE_TIME
                .parse(publishedAt, Instant::from);
    } catch (DateTimeParseException dtpe) {
        timelinePoint = Instant.now();
    }

    Instant now = Instant.now();

    Duration elapsedTime = Duration.between(timelinePoint, now);

    System.out.println(timelinePoint);
    System.out.println(now);
    System.out.println(elapsedTime.toMinutes());

当我刚才运行这个 sn-p 时,我得到了这个输出:

2019-10-21T13:01:23Z
2019-10-21T16:17:49.719Z
196

DateTimeFormatter.ISO_OFFSET_DATE_TIME 将解析您的字符串,无论偏移量是小时和可选分钟还是以Z 给出为零。所以上面处理了你的两种格式。

你的代码出了什么问题?

没有任何理由将SimpleDateFormatDate 也带入您的代码中。它只会让事情变得更复杂,却一无所获。而且这些类设计的很糟糕,尤其是前者非常麻烦,而且已经过时了,所以我强烈建议你把它们淘汰掉,不要再碰它们了。

您正在使用的来自 java.time 的 LocalDateTime 类不是时间线上某个点的正确类。如果您的字符串中的偏移量与 JVM 默认时区的 UTC 偏移量不同,您将获得具有不同隐含偏移量的 LocalDateTime 对象。这意味着比较它们是没有意义的,并且您会得到它们之间不正确的经过时间。

对于您观察到的例外情况:在您无法在任何一次尝试中解析字符串的情况下,您将当前日期和时间(来自Date())格式化为dd/MM/yyyy 格式,例如21/10/2019 ,然后尝试使用单参数LocalDateTime.parse() 解析此字符串。这有几个问题。首先,parse 方法需要 ISO 8601 格式。文档说:

从文本字符串中获取LocalDateTime 的实例,例如 2007-12-03T10:15:30.

您会看到21/10/20192007-12-03T10:15:30 的格式不一样。这就是你例外的原因。异常消息显示at index 0,因为字符串中的索引0 是两位数,并且该方法需要“一年四位数或更多”(引用自DateTimeFormatter.ISO_LOCAL_DATE 的文档)。其次,您不想根据没有时间的日期以分钟为单位测量经过的时间。第三,您不能将没有时间的日期字符串解析为LocalDateTime(有一些技巧可以做到这一点,但不能像那样工作)。

链接

【讨论】:

  • 我试图在this answer 中告诉您一些相同的信息,抱歉,我似乎无法做到。这次我试着把解释解释得更清楚一点,希望对你有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-10
  • 2018-04-04
  • 2018-12-12
  • 2020-06-25
  • 1970-01-01
相关资源
最近更新 更多