提问人:Code Poet 提问时间:8/16/2023 最后编辑:Code Poet 更新时间:8/26/2023 访问量:105
仅适用于某些用户的 DateTimeFormatter 错误
DateTimeFormatter error for some users only
问:
我遇到了这种奇怪的情况,我的函数使用 DateTimeFormatter 对我来说非常有效(即 rss 提要列表按其发布的顺序排序),但对于我的应用程序的某些用户来说,它崩溃了。起初,我以为可能存在与语言环境相关的问题,但似乎所有 rss 提要都使用该格式,所以现在我没有想法了。我还收到了设备上设置了美式英语的用户崩溃的报告(我使用英式英语)。我的代码有问题还是其他可能的原因?locale.English
我使用 Rome 解析器,pubDates 是这样解析的:Sat Aug 12 12:51:34 GMT+01:00 2023
suspend fun sortDateTimeAndSaveLatestHeadline() {
val dataStore = AppDataStore(getApplication())
val listOfStringDates: MutableList<String> = mutableListOf()
val listOfHeadlines: MutableList<String> = mutableListOf()
val listOfFeedTitles: MutableList<String> = mutableListOf()
newsFeed.value?.forEach { feed ->
listOfStringDates.add(feed.feedItem.pubDate)
listOfHeadlines.add(feed.feedItem.title)
listOfFeedTitles.add(feed.feedTitle)
}
val zippedLists = listOfStringDates.zip(listOfHeadlines)
.zip(listOfFeedTitles) { (a, b), c -> Triple(a, b, c) }
val dateTimeFormatter: DateTimeFormatter =
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O yyyy", Locale.ENGLISH)
val result = zippedLists.sortedByDescending {
LocalDateTime.parse(it.first, dateTimeFormatter)
}
if (result.isNotEmpty()) {
dataStore.saveTileHeadline(result[0].second)
dataStore.saveFeedTitle(result[0].third)
println("Headline = ${result[0].second}")
}
}
这是堆栈跟踪:
Exception java.time.format.DateTimeParseException:
at java.time.format.DateTimeFormatter.parseResolved0 (DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse (DateTimeFormatter.java:1851)
at java.time.LocalDateTime.parse (LocalDateTime.java:486)
at java.util.TimSort.countRunAndMakeAscending (TimSort.java:355)
at java.util.TimSort.sort (TimSort.java:220)
at java.util.Arrays.sort (Arrays.java:1424)
at kotlin.collections.CollectionsKt___CollectionsKt.sortedWith (CollectionsKt___Collections.kt)
at com.strangerweather.news.presentation.screens.screens.FeedItemsScreenKt$FeedItemsScreen$7$1.invoke (FeedItemsScreen.kt)
at androidx.wear.compose.foundation.lazy.ScalingLazyColumnKt$ScalingLazyColumn$1$1$2$1.invoke (ScalingLazyColumn.kt)
at androidx.compose.foundation.lazy.layout.LazyLayoutIntervalContent.<init> (LazyLayoutIntervalContent.java)
at androidx.compose.foundation.lazy.LazyListIntervalContent.<init> (LazyListIntervalContent.java)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe (Snapshot.java)
at androidx.compose.runtime.DerivedSnapshotState.currentRecord (DerivedSnapshotState.java)
at androidx.compose.runtime.snapshots.SnapshotKt.getLock (Snapshot.kt)
at androidx.compose.runtime.DerivedSnapshotState$ResultRecord.readableHash (DerivedSnapshotState.java)
at androidx.compose.runtime.snapshots.SnapshotKt.getLock (Snapshot.kt)
at androidx.compose.runtime.DerivedSnapshotState$ResultRecord.isValid (DerivedSnapshotState.java)
at androidx.compose.runtime.DerivedSnapshotState.currentRecord (DerivedSnapshotState.java)
at androidx.compose.runtime.DerivedSnapshotState.getCurrentRecord (DerivedSnapshotState.java)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.recordInvalidation (SnapshotStateObserver.java)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.drainChanges (SnapshotStateObserver.java)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.access$drainChanges (SnapshotStateObserver.java)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot (Snapshot.kt)
at androidx.compose.runtime.snapshots.SnapshotKt.advanceGlobalSnapshot (Snapshot.kt)
at androidx.compose.runtime.snapshots.SnapshotKt.access$advanceGlobalSnapshot (Snapshot.kt)
at androidx.compose.runtime.snapshots.GlobalSnapshot.notifyObjectsInitialized$runtime_release (GlobalSnapshot.java)
at androidx.compose.runtime.DerivedSnapshotState.currentRecord (DerivedSnapshotState.java)
at androidx.compose.runtime.snapshots.Snapshot$Companion.getCurrent (Snapshot.java)
at androidx.compose.runtime.DerivedSnapshotState.getValue (DerivedSnapshotState.java)
at androidx.wear.compose.foundation.lazy.ScalingLazyListState.getLayoutInfo (ScalingLazyListState.java)
at androidx.wear.compose.foundation.lazy.ScalingLazyListState.scrollToItem$compose_foundation_release (ScalingLazyListState.java)
at androidx.wear.compose.foundation.lazy.ScalingLazyListState.scrollToInitialItem$compose_foundation_release (ScalingLazyListState.java)
at androidx.wear.compose.foundation.lazy.ScalingLazyColumnKt$ScalingLazyColumn$1$1$3$1.invokeSuspend (ScalingLazyColumn.kt)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (BaseContinuationImpl.java)
at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.java)
at androidx.compose.ui.platform.AndroidUiDispatcher.nextTask (AndroidUiDispatcher.java)
at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch (AndroidUiDispatcher.java)
at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch (AndroidUiDispatcher.java)
at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.run (AndroidUiDispatcher.java)
at android.os.Handler.handleCallback (Handler.java:938)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:246)
at android.app.ActivityThread.main (ActivityThread.java:7690)
at java.lang.reflect.Method.invoke
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:593)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:995)
答:
2赞
Arvind Kumar Avinash
8/19/2023
#1
更新:
感谢 Ole V.V. 的更新。
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT)
解析原始答案中的两个示例字符串就好了。
原文答案:
从您在代码和注释中提供的描述来看,您的应用程序似乎正在以不同的形式获取时区信息,例如 GMT+01:00、EDT 等。因此,您应该对时区使用多个可选模式。
演示:
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss [O][z] uuuu", Locale.ENGLISH);
// Test
Stream.of(
"Sat Aug 12 12:51:34 GMT+01:00 2023",
"Fri Aug 18 12:34:50 EDT 2023"
).forEach(s -> System.out.println(ZonedDateTime.parse(s, dtf)));
}
}
输出:
2023-08-12T12:51:34+01:00
2023-08-18T12:34:50-04:00[America/New_York]
笔记:
- 我在演示中只使用了两种可选模式。您可以根据您的要求进一步扩展它,例如 有三种可选模式。
"EEE MMM dd HH:mm:ss [O][z][VV] uuuu"
- 在这里,您可以使用代替,但我更喜欢
u
而不是y
。y
u
评论
0赞
Code Poet
8/20/2023
谢谢你!总共有多少种可选模式?是只有三个还是更多?我需要涵盖所有可能性......
0赞
Arvind Kumar Avinash
8/20/2023
@CodePoet,不幸的是,在自定义格式的情况下,我们需要指定所有必需的模式。
0赞
Code Poet
8/21/2023
因此,如果我理解正确,这是否涵盖了我在时区方面可能遇到的大多数情况:“EEE MMM dd HH:mm:ss [O][z][X][VV][V][v][x][Z] uuuu”?
0赞
Arvind Kumar Avinash
8/21/2023
像“EEE MMM dd HH:mm:ss [O][z][X[X[X]]][VV][x][Z[ZZZZ]] uuuu”一样使用它。请注意,需要用 double 表示,并且没有像 这样的符号。V
v
1赞
Arvind Kumar Avinash
8/26/2023
谢谢,@OleV.V.我已将您的评论纳入我的回答中。
评论
runCatching { LocalDate.parse(it.first, dateTimeFormatter) }.getOrElse { e-> throw IllegalArgumentException("Invalid date str: ${it.first}", e) }
ZonedDateTime
DateTimeFormatter
LocalDateTime
ZonedDateTime