mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 00:06:22 -06:00
PM-22502: Format dates and times correctly for locale (#5333)
This commit is contained in:
parent
d822be62e1
commit
9cdfe0c5d6
@ -4,7 +4,7 @@ package com.x8bit.bitwarden.ui.platform.feature.search.util
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.send.SendType
|
||||
import com.bitwarden.send.SendView
|
||||
import com.bitwarden.ui.platform.base.util.removeDiacritics
|
||||
@ -27,8 +27,7 @@ import com.x8bit.bitwarden.ui.vault.feature.util.toLabelIcons
|
||||
import com.x8bit.bitwarden.ui.vault.feature.util.toOverflowActions
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData
|
||||
import java.time.Clock
|
||||
|
||||
private const val DELETION_DATE_PATTERN: String = "MMM d, uuuu, hh:mm a"
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Updates a [SearchTypeData] with the given data if necessary.
|
||||
@ -353,7 +352,11 @@ private fun SendView.toDisplayItem(
|
||||
id = id.orEmpty(),
|
||||
title = name,
|
||||
titleTestTag = "SendNameLabel",
|
||||
subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock),
|
||||
subtitle = deletionDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
subtitleTestTag = "SendDateLabel",
|
||||
iconData = IconData.Local(
|
||||
iconRes = when (type) {
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.about.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateStyle
|
||||
import com.bitwarden.core.data.util.toFormattedTimeStyle
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Creates a properly formatted string indicating when the logging will stop for the active log or
|
||||
@ -23,7 +25,13 @@ private fun FlightRecorderDataSet.FlightRecorderData.getStopsLoggingString(
|
||||
clock: Clock,
|
||||
): Text {
|
||||
val completionInstant = Instant.ofEpochMilli(this.startTimeMs + this.durationMs)
|
||||
val completionDate = completionInstant.toFormattedPattern(pattern = "M/d/yy", clock = clock)
|
||||
val completionTime = completionInstant.toFormattedPattern(pattern = "h:mm a", clock = clock)
|
||||
val completionDate = completionInstant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
val completionTime = completionInstant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
return R.string.stops_logging_on.asText(completionDate, completionTime)
|
||||
}
|
||||
|
||||
@ -572,13 +572,11 @@ private fun SessionCustomTimeoutRow(
|
||||
cardStyle = CardStyle.Middle(),
|
||||
modifier = modifier,
|
||||
) {
|
||||
val formattedTime = LocalTime
|
||||
.ofSecondOfDay(
|
||||
vaultTimeoutInMinutes * MINUTES_PER_HOUR.toLong(),
|
||||
)
|
||||
.toFormattedPattern("HH:mm")
|
||||
|
||||
Text(
|
||||
text = formattedTime,
|
||||
text = LocalTime
|
||||
.ofSecondOfDay(vaultTimeoutInMinutes * MINUTES_PER_HOUR.toLong())
|
||||
.toFormattedPattern(pattern = "HH:mm"),
|
||||
style = BitwardenTheme.typography.labelSmall,
|
||||
color = BitwardenTheme.colorScheme.text.primary,
|
||||
)
|
||||
|
||||
@ -5,7 +5,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.loginap
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -23,6 +23,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val KEY_STATE = "state"
|
||||
@ -214,8 +215,9 @@ class LoginApprovalViewModel @Inject constructor(
|
||||
email = email,
|
||||
fingerprint = result.authRequest.fingerprint,
|
||||
ipAddress = result.authRequest.ipAddress,
|
||||
time = result.authRequest.creationDate.toFormattedPattern(
|
||||
pattern = "M/d/yy hh:mm a",
|
||||
time = result.authRequest.creationDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
),
|
||||
|
||||
@ -3,7 +3,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.pending
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||
@ -20,6 +20,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val KEY_STATE = "state"
|
||||
@ -144,8 +145,9 @@ class PendingRequestsViewModel @Inject constructor(
|
||||
PendingRequestsState.ViewState.Content.PendingLoginRequest(
|
||||
fingerprintPhrase = request.fingerprint,
|
||||
platform = request.platform,
|
||||
timestamp = request.creationDate.toFormattedPattern(
|
||||
pattern = "M/d/yy hh:mm a",
|
||||
timestamp = request.creationDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
)
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.x8bit.bitwarden.ui.platform.feature.settings.flightrecorder.recordedLogs.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedDateStyle
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedTimeStyle
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.R
|
||||
@ -11,6 +13,7 @@ import com.x8bit.bitwarden.ui.platform.util.formatBytes
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.format.FormatStyle
|
||||
import java.time.temporal.ChronoUnit
|
||||
|
||||
/**
|
||||
@ -67,14 +70,20 @@ private fun FlightRecorderDataSet.FlightRecorderData.expiresIn(clock: Clock): Te
|
||||
R.string.expired.asText()
|
||||
} else if (now.isAfter(expirationTime.minus(1, ChronoUnit.DAYS))) {
|
||||
// We are within 24 hours of expiration, so show the specific time.
|
||||
val expirationTime = expirationTime.toFormattedPattern(pattern = "h:mm a", clock = clock)
|
||||
val expirationTime = expirationTime.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
R.string.expires_at.asText(expirationTime)
|
||||
} else if (dayBeforeExpiration.dayOfYear == now.atZone(clock.zone).dayOfYear) {
|
||||
// We expire tomorrow based on the day of year.
|
||||
R.string.expires_tomorrow.asText()
|
||||
} else {
|
||||
// Let them know the date it expires.
|
||||
val expirationDate = expirationTime.toFormattedPattern(pattern = "M/d/yy", clock = clock)
|
||||
val expirationDate = expirationTime.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
R.string.expires_on.asText(expirationDate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.other
|
||||
import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -21,12 +21,11 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.format.FormatStyle
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val KEY_STATE = "state"
|
||||
|
||||
private const val VAULT_LAST_SYNC_TIME_PATTERN: String = "M/d/yyyy h:mm a"
|
||||
|
||||
/**
|
||||
* View model for the other screen.
|
||||
*/
|
||||
@ -46,7 +45,11 @@ class OtherViewModel @Inject constructor(
|
||||
clearClipboardFrequency = settingsRepo.clearClipboardFrequency,
|
||||
lastSyncTime = settingsRepo
|
||||
.vaultLastSync
|
||||
?.toFormattedPattern(VAULT_LAST_SYNC_TIME_PATTERN, clock)
|
||||
?.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
.orEmpty(),
|
||||
dialogState = null,
|
||||
),
|
||||
@ -137,7 +140,11 @@ class OtherViewModel @Inject constructor(
|
||||
it.copy(
|
||||
lastSyncTime = action
|
||||
.vaultLastSyncTime
|
||||
?.toFormattedPattern(VAULT_LAST_SYNC_TIME_PATTERN, clock)
|
||||
?.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
.orEmpty(),
|
||||
dialogState = null,
|
||||
)
|
||||
|
||||
@ -4,7 +4,7 @@ import android.os.Parcelable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -25,6 +25,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val KEY_STATE = "state"
|
||||
@ -141,8 +142,9 @@ class PasswordHistoryViewModel @Inject constructor(
|
||||
val passwords = this?.map { passwordHistoryView ->
|
||||
GeneratedPassword(
|
||||
password = passwordHistoryView.password,
|
||||
date = passwordHistoryView.lastUsedDate.toFormattedPattern(
|
||||
pattern = "MM/dd/yy h:mm a",
|
||||
date = passwordHistoryView.lastUsedDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
)
|
||||
|
||||
@ -10,7 +10,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.components.model.CardStyle
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -22,6 +22,7 @@ import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import java.time.Clock
|
||||
import java.time.ZonedDateTime
|
||||
import java.time.format.FormatStyle
|
||||
import java.time.temporal.ChronoUnit
|
||||
import kotlin.time.Duration.Companion.days
|
||||
import kotlin.time.Duration.Companion.hours
|
||||
@ -94,7 +95,13 @@ private sealed class CustomDeletionOption : Parcelable {
|
||||
|
||||
override fun getText(
|
||||
clock: Clock,
|
||||
): Text = time.toFormattedPattern(pattern = "d MMM, yyyy, h:mma", clock = clock).asText()
|
||||
): Text = time
|
||||
.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
)
|
||||
.asText()
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.send.SendType
|
||||
import com.bitwarden.send.SendView
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.SendState
|
||||
import java.time.Clock
|
||||
|
||||
private const val DELETION_DATE_PATTERN: String = "MMM d, uuuu, hh:mm a"
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Transforms [SendData] into [SendState.ViewState].
|
||||
@ -34,8 +33,9 @@ private fun List<SendView>.toSendContent(
|
||||
SendState.ViewState.Content.SendItem(
|
||||
id = requireNotNull(sendView.id),
|
||||
name = sendView.name,
|
||||
deletionDate = sendView.deletionDate.toFormattedPattern(
|
||||
pattern = DELETION_DATE_PATTERN,
|
||||
deletionDate = sendView.deletionDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
type = when (sendView.type) {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send.viewsend.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.send.SendFileView
|
||||
import com.bitwarden.send.SendTextView
|
||||
import com.bitwarden.send.SendType
|
||||
@ -8,6 +8,7 @@ import com.bitwarden.send.SendView
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.util.toSendUrl
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.viewsend.ViewSendState
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Transforms the given [SendView] to a [ViewSendState.ViewState.Content].
|
||||
@ -23,9 +24,11 @@ fun SendView.toViewSendViewStateContent(
|
||||
},
|
||||
shareLink = this.toSendUrl(baseWebSendUrl = baseWebSendUrl),
|
||||
sendName = this.name,
|
||||
deletionDate = this
|
||||
.deletionDate
|
||||
.toFormattedPattern(pattern = "d MMM, yyyy, h:mma", clock = clock),
|
||||
deletionDate = this.deletionDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
maxAccessCount = this.maxAccessCount?.toInt(),
|
||||
currentAccessCount = this.accessCount.toInt(),
|
||||
notes = this.notes,
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
|
||||
package com.x8bit.bitwarden.ui.vault.feature.addedit.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateStyle
|
||||
import com.bitwarden.core.data.util.toFormattedTimeStyle
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.bitwarden.vault.CipherRepromptType
|
||||
import com.bitwarden.vault.CipherType
|
||||
@ -27,11 +28,9 @@ import com.x8bit.bitwarden.ui.vault.model.VaultIdentityTitle
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType.Companion.fromId
|
||||
import com.x8bit.bitwarden.ui.vault.model.findVaultCardBrandWithNameOrNull
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.UUID
|
||||
|
||||
private const val PASSKEY_CREATION_DATE_PATTERN: String = "M/d/yy"
|
||||
private const val PASSKEY_CREATION_TIME_PATTERN: String = "hh:mm a"
|
||||
|
||||
/**
|
||||
* Transforms [CipherView] into [VaultAddEditState.ViewState].
|
||||
*/
|
||||
@ -332,6 +331,6 @@ private fun List<Fido2Credential>?.getPrimaryFido2CredentialOrNull(
|
||||
* "M/d/yy, hh:mm a".
|
||||
*/
|
||||
private fun Fido2Credential.getCreationDateTime(clock: Clock) = R.string.created_xy.asText(
|
||||
creationDate.toFormattedPattern(pattern = PASSKEY_CREATION_DATE_PATTERN, clock = clock),
|
||||
creationDate.toFormattedPattern(pattern = PASSKEY_CREATION_TIME_PATTERN, clock = clock),
|
||||
creationDate.toFormattedDateStyle(dateStyle = FormatStyle.SHORT, clock = clock),
|
||||
creationDate.toFormattedTimeStyle(timeStyle = FormatStyle.SHORT, clock = clock),
|
||||
)
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.item.util
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateStyle
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.core.data.util.toFormattedTimeStyle
|
||||
import com.bitwarden.ui.platform.base.util.nullIfAllEqual
|
||||
import com.bitwarden.ui.platform.base.util.orNullIfBlank
|
||||
import com.bitwarden.ui.platform.base.util.orZeroWidthSpace
|
||||
@ -27,12 +29,9 @@ import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
||||
import com.x8bit.bitwarden.ui.vault.model.findVaultCardBrandWithNameOrNull
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import java.time.Clock
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.Locale
|
||||
|
||||
private const val LAST_UPDATED_DATE_TIME_PATTERN: String = "M/d/yy hh:mm a"
|
||||
private const val FIDO2_CREDENTIAL_CREATION_DATE_PATTERN: String = "M/d/yy"
|
||||
private const val FIDO2_CREDENTIAL_CREATION_TIME_PATTERN: String = "h:mm a"
|
||||
|
||||
/**
|
||||
* Transforms [VaultData] into [VaultItemState.ViewState].
|
||||
*/
|
||||
@ -62,8 +61,9 @@ fun CipherView.toViewState(
|
||||
?.find { it.id == fieldView.hashCode().toString() },
|
||||
)
|
||||
},
|
||||
lastUpdated = revisionDate.toFormattedPattern(
|
||||
pattern = LAST_UPDATED_DATE_TIME_PATTERN,
|
||||
lastUpdated = revisionDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
notes = notes,
|
||||
@ -124,8 +124,9 @@ fun CipherView.toViewState(
|
||||
uris = loginValues.uris.orEmpty().map { it.toUriData() },
|
||||
passwordRevisionDate = loginValues
|
||||
.passwordRevisionDate
|
||||
?.toFormattedPattern(
|
||||
pattern = LAST_UPDATED_DATE_TIME_PATTERN,
|
||||
?.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
isPremiumUser = isPremiumUser,
|
||||
@ -248,12 +249,12 @@ private fun LoginUriView.toUriData() =
|
||||
private fun Fido2Credential?.getCreationDateText(clock: Clock): Text? =
|
||||
this?.let {
|
||||
R.string.created_xy.asText(
|
||||
creationDate.toFormattedPattern(
|
||||
pattern = FIDO2_CREDENTIAL_CREATION_DATE_PATTERN,
|
||||
creationDate.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
creationDate.toFormattedPattern(
|
||||
pattern = FIDO2_CREDENTIAL_CREATION_TIME_PATTERN,
|
||||
creationDate.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.fido.Fido2CredentialAutofillView
|
||||
import com.bitwarden.send.SendType
|
||||
import com.bitwarden.send.SendView
|
||||
@ -35,8 +35,7 @@ import com.x8bit.bitwarden.ui.vault.feature.vault.util.toFilteredList
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toLoginIconData
|
||||
import com.x8bit.bitwarden.ui.vault.model.TotpData
|
||||
import java.time.Clock
|
||||
|
||||
private const val DELETION_DATE_PATTERN: String = "MMM d, uuuu, hh:mm a"
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Determines a predicate to filter a list of [CipherView] based on the
|
||||
@ -461,7 +460,11 @@ private fun SendView.toDisplayItem(
|
||||
titleTestTag = "SendNameLabel",
|
||||
secondSubtitle = null,
|
||||
secondSubtitleTestTag = null,
|
||||
subtitle = deletionDate.toFormattedPattern(DELETION_DATE_PATTERN, clock),
|
||||
subtitle = deletionDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = clock,
|
||||
),
|
||||
subtitleTestTag = "SendDateLabel",
|
||||
iconData = IconData.Local(
|
||||
iconRes = when (type) {
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
package com.x8bit.bitwarden.ui.vault.feature.vault.util
|
||||
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateStyle
|
||||
import com.bitwarden.core.data.util.toFormattedTimeStyle
|
||||
import com.bitwarden.ui.util.asText
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.datasource.disk.model.FlightRecorderDataSet
|
||||
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
/**
|
||||
* Helper function to create a [BitwardenSnackbarData] representing the active flight recorder.
|
||||
@ -21,8 +23,8 @@ fun FlightRecorderDataSet.toSnackbarData(
|
||||
?: return null
|
||||
return BitwardenSnackbarData(
|
||||
message = R.string.flight_recorder_banner_message.asText(
|
||||
expirationTime.toFormattedPattern(pattern = "M/d/yy", clock = clock),
|
||||
expirationTime.toFormattedPattern(pattern = "h:mm a", clock = clock),
|
||||
expirationTime.toFormattedDateStyle(dateStyle = FormatStyle.SHORT, clock = clock),
|
||||
expirationTime.toFormattedTimeStyle(timeStyle = FormatStyle.SHORT, clock = clock),
|
||||
),
|
||||
messageHeader = R.string.flight_recorder_banner_title.asText(),
|
||||
actionLabel = R.string.go_to_settings.asText(),
|
||||
|
||||
@ -183,7 +183,7 @@ class LoginApprovalViewModelTest : BaseViewModelTest() {
|
||||
email = EMAIL,
|
||||
fingerprint = AUTH_REQUEST.fingerprint,
|
||||
ipAddress = AUTH_REQUEST.ipAddress,
|
||||
time = "9/13/24 12:00 AM",
|
||||
time = "9/13/24, 12:00 AM",
|
||||
),
|
||||
)
|
||||
val viewModel = createViewModel()
|
||||
@ -455,7 +455,7 @@ private val DEFAULT_STATE: LoginApprovalState = LoginApprovalState(
|
||||
email = EMAIL,
|
||||
fingerprint = FINGERPRINT,
|
||||
ipAddress = "1.0.0.1",
|
||||
time = "9/13/24 12:00 AM",
|
||||
time = "9/13/24, 12:00 AM",
|
||||
),
|
||||
)
|
||||
private const val USER_ID = "userID"
|
||||
|
||||
@ -56,7 +56,7 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
||||
@Test
|
||||
fun `getPendingResults success with content should update state with some requests filtered`() {
|
||||
val dateTimeFormatter = DateTimeFormatter
|
||||
.ofPattern("M/d/yy hh:mm a")
|
||||
.ofPattern("M/d/yy, hh:mm a")
|
||||
.withZone(fixedClock.zone)
|
||||
val nowZonedDateTime = ZonedDateTime.now(fixedClock)
|
||||
val requestList = listOf(
|
||||
@ -284,15 +284,11 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Test
|
||||
fun `on LifecycleResume should update state`() = runTest {
|
||||
val dateTimeFormatter = DateTimeFormatter
|
||||
.ofPattern("M/d/yy hh:mm a")
|
||||
.withZone(fixedClock.zone)
|
||||
val nowZonedDateTime = ZonedDateTime.now()
|
||||
val fiveMinZonedDateTime = ZonedDateTime.now().minusMinutes(5)
|
||||
val sixMinZonedDateTime = ZonedDateTime.now().minusMinutes(6)
|
||||
val nowZonedDateTime = ZonedDateTime.now(fixedClock)
|
||||
val fiveMinZonedDateTime = ZonedDateTime.now(fixedClock).minusMinutes(5)
|
||||
val sixMinZonedDateTime = ZonedDateTime.now(fixedClock).minusMinutes(6)
|
||||
val requestList = listOf(
|
||||
AuthRequest(
|
||||
id = "1",
|
||||
@ -353,12 +349,12 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
||||
PendingRequestsState.ViewState.Content.PendingLoginRequest(
|
||||
fingerprintPhrase = "pantry-overdue-survive-sleep-jab",
|
||||
platform = "Android",
|
||||
timestamp = nowZonedDateTime.format(dateTimeFormatter),
|
||||
timestamp = "10/27/23, 12:00 PM",
|
||||
),
|
||||
PendingRequestsState.ViewState.Content.PendingLoginRequest(
|
||||
fingerprintPhrase = "erupt-anew-matchbook-disk-student",
|
||||
platform = "iOS",
|
||||
timestamp = fiveMinZonedDateTime.format(dateTimeFormatter),
|
||||
timestamp = "10/27/23, 11:55 AM",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@ -157,7 +157,7 @@ class OtherViewModelTest : BaseViewModelTest() {
|
||||
mutableVaultLastSyncStateFlow.tryEmit(newSyncTime)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
lastSyncTime = "10/27/2023 12:00 PM",
|
||||
lastSyncTime = "Oct 27, 2023, 12:00 PM",
|
||||
dialogState = null,
|
||||
),
|
||||
awaitItem(),
|
||||
@ -236,6 +236,6 @@ private val DEFAULT_STATE = OtherState(
|
||||
allowScreenCapture = false,
|
||||
allowSyncOnRefresh = false,
|
||||
clearClipboardFrequency = ClearClipboardFrequency.NEVER,
|
||||
lastSyncTime = "10/26/2023 12:00 PM",
|
||||
lastSyncTime = "Oct 26, 2023, 12:00 PM",
|
||||
dialogState = null,
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@ package com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.data.repository.model.DataState
|
||||
import com.bitwarden.core.data.util.toFormattedPattern
|
||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.bitwarden.ui.util.Text
|
||||
import com.bitwarden.ui.util.asText
|
||||
@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
||||
|
||||
@ -171,7 +172,7 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
||||
passwords = listOf(
|
||||
PasswordHistoryState.GeneratedPassword(
|
||||
password = "mockPassword-1",
|
||||
date = "10/27/23 12:00 PM",
|
||||
date = "10/27/23, 12:00 PM",
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -194,8 +195,9 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
||||
passwords = listOf(
|
||||
PasswordHistoryState.GeneratedPassword(
|
||||
password = "password",
|
||||
date = passwordHistoryView.lastUsedDate.toFormattedPattern(
|
||||
pattern = "MM/dd/yy h:mm a",
|
||||
date = passwordHistoryView.lastUsedDate.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
clock = fixedClock,
|
||||
),
|
||||
),
|
||||
|
||||
@ -48,7 +48,7 @@ class SendViewExtensionsTest {
|
||||
),
|
||||
shareLink = sendUrl,
|
||||
sendName = "mockName-1",
|
||||
deletionDate = "27 Oct, 2023, 12:00PM",
|
||||
deletionDate = "Oct 27, 2023, 12:00 PM",
|
||||
maxAccessCount = 1,
|
||||
currentAccessCount = 1,
|
||||
notes = "mockNotes-1",
|
||||
@ -76,7 +76,7 @@ class SendViewExtensionsTest {
|
||||
),
|
||||
shareLink = sendUrl,
|
||||
sendName = "mockName-2",
|
||||
deletionDate = "27 Oct, 2023, 12:00PM",
|
||||
deletionDate = "Oct 27, 2023, 12:00 PM",
|
||||
maxAccessCount = 1,
|
||||
currentAccessCount = 1,
|
||||
notes = "mockNotes-2",
|
||||
|
||||
@ -169,7 +169,7 @@ fun createCommonContent(
|
||||
if (isEmpty) {
|
||||
VaultItemState.ViewState.Content.Common(
|
||||
name = "mockName",
|
||||
lastUpdated = "1/1/70 12:16 AM",
|
||||
lastUpdated = "1/1/70, 12:16 AM",
|
||||
notes = null,
|
||||
customFields = emptyList(),
|
||||
requiresCloneConfirmation = false,
|
||||
@ -186,7 +186,7 @@ fun createCommonContent(
|
||||
} else {
|
||||
VaultItemState.ViewState.Content.Common(
|
||||
name = "mockName",
|
||||
lastUpdated = "1/1/70 12:16 AM",
|
||||
lastUpdated = "1/1/70, 12:16 AM",
|
||||
notes = "Lots of notes",
|
||||
customFields = listOf(
|
||||
FieldView(
|
||||
@ -267,7 +267,7 @@ fun createLoginContent(isEmpty: Boolean): VaultItemState.ViewState.Content.ItemT
|
||||
),
|
||||
)
|
||||
},
|
||||
passwordRevisionDate = "1/1/70 12:16 AM".takeUnless { isEmpty },
|
||||
passwordRevisionDate = "1/1/70, 12:16 AM".takeUnless { isEmpty },
|
||||
isPremiumUser = true,
|
||||
totpCodeItemData = TotpCodeItemData(
|
||||
periodSeconds = 30,
|
||||
|
||||
@ -1,17 +1,12 @@
|
||||
package com.bitwarden.core.data.util
|
||||
|
||||
import java.time.Clock
|
||||
import java.time.ZoneId
|
||||
import java.time.chrono.IsoChronology
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.DateTimeFormatterBuilder
|
||||
import java.time.format.FormatStyle
|
||||
import java.time.temporal.TemporalAccessor
|
||||
|
||||
/**
|
||||
* Converts the [TemporalAccessor] to a formatted string based on the provided pattern and timezone.
|
||||
*/
|
||||
fun TemporalAccessor.toFormattedPattern(
|
||||
pattern: String,
|
||||
zone: ZoneId,
|
||||
): String = DateTimeFormatter.ofPattern(pattern).withZone(zone).format(this)
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Converts the [TemporalAccessor] to a formatted string based on the provided pattern and timezone.
|
||||
@ -19,4 +14,74 @@ fun TemporalAccessor.toFormattedPattern(
|
||||
fun TemporalAccessor.toFormattedPattern(
|
||||
pattern: String,
|
||||
clock: Clock = Clock.systemDefaultZone(),
|
||||
): String = toFormattedPattern(pattern = pattern, zone = clock.zone)
|
||||
): String = DateTimeFormatter.ofPattern(pattern).withZone(clock.zone).format(this)
|
||||
|
||||
/**
|
||||
* Converts the [TemporalAccessor] to a formatted date string based on the provided style, locale,
|
||||
* and clock.
|
||||
*
|
||||
* In US English, the output string will be as follows for the given [dateStyle]:
|
||||
* * [FormatStyle.SHORT]: 6/6/25
|
||||
* * [FormatStyle.MEDIUM]: Jun 6, 2025
|
||||
* * [FormatStyle.LONG]: June 6, 2025
|
||||
* * [FormatStyle.FULL]: Friday, June 6, 2025
|
||||
*/
|
||||
fun TemporalAccessor.toFormattedDateStyle(
|
||||
dateStyle: FormatStyle,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
clock: Clock = Clock.systemDefaultZone(),
|
||||
): String =
|
||||
toFormattedPattern(
|
||||
pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
|
||||
dateStyle,
|
||||
null,
|
||||
IsoChronology.INSTANCE,
|
||||
locale,
|
||||
),
|
||||
clock = clock,
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the [TemporalAccessor] to a formatted time string based on the provided style, locale,
|
||||
* and clock.
|
||||
*
|
||||
* In US English, the output string will be as follows for the given [timeStyle]:
|
||||
* * [FormatStyle.SHORT]: 4:15 PM
|
||||
* * [FormatStyle.MEDIUM]: 4:15:21 PM
|
||||
* * [FormatStyle.LONG]: 4:15:21 PM CDT
|
||||
* * [FormatStyle.FULL]: 4:51:03 PM Central Daylight Time
|
||||
*/
|
||||
fun TemporalAccessor.toFormattedTimeStyle(
|
||||
timeStyle: FormatStyle,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
clock: Clock = Clock.systemDefaultZone(),
|
||||
): String =
|
||||
toFormattedPattern(
|
||||
pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
|
||||
null,
|
||||
timeStyle,
|
||||
IsoChronology.INSTANCE,
|
||||
locale,
|
||||
),
|
||||
clock = clock,
|
||||
)
|
||||
|
||||
/**
|
||||
* Converts the [TemporalAccessor] to a formatted string based on the provided style, locale, and
|
||||
* clock.
|
||||
*/
|
||||
fun TemporalAccessor.toFormattedDateTimeStyle(
|
||||
dateStyle: FormatStyle,
|
||||
timeStyle: FormatStyle,
|
||||
locale: Locale = Locale.getDefault(),
|
||||
clock: Clock = Clock.systemDefaultZone(),
|
||||
): String =
|
||||
toFormattedPattern(
|
||||
pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
|
||||
dateStyle,
|
||||
timeStyle,
|
||||
IsoChronology.INSTANCE,
|
||||
locale,
|
||||
),
|
||||
clock = clock,
|
||||
)
|
||||
|
||||
@ -4,33 +4,254 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.time.Clock
|
||||
import java.time.Instant
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.Locale
|
||||
|
||||
class TemporalAccessorExtensionsTest {
|
||||
|
||||
@Test
|
||||
fun `toFormattedPattern should return correctly formatted string with timezone`() {
|
||||
fun `toFormattedPattern should return correctly formatted string`() {
|
||||
val instant = Instant.parse("2023-12-10T15:30:00Z")
|
||||
val pattern = "MM/dd/yyyy hh:mm a"
|
||||
val zone = ZoneId.of("UTC")
|
||||
val expectedFormattedString = "12/10/2023 03:30 PM"
|
||||
val formattedString = instant.toFormattedPattern(pattern, zone)
|
||||
|
||||
assertEquals(expectedFormattedString, formattedString)
|
||||
assertEquals(
|
||||
"12/10/2023 03:30 PM",
|
||||
instant.toFormattedPattern(
|
||||
pattern = "MM/dd/yyyy hh:mm a",
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toFormattedPattern should return correctly formatted string with clock`() {
|
||||
fun `toFormattedDateStyle should return correctly formatted string with with locale`() {
|
||||
val instant = Instant.parse("2023-12-10T15:30:00Z")
|
||||
val pattern = "MM/dd/yyyy hh:mm a"
|
||||
val clock: Clock = Clock.fixed(
|
||||
Instant.parse("2023-10-27T12:00:00Z"),
|
||||
ZoneOffset.UTC,
|
||||
)
|
||||
val expectedFormattedString = "12/10/2023 03:30 PM"
|
||||
val formattedString = instant.toFormattedPattern(pattern, clock)
|
||||
|
||||
assertEquals(expectedFormattedString, formattedString)
|
||||
// US locale
|
||||
assertEquals(
|
||||
"12/10/23",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Dec 10, 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"December 10, 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.LONG,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Sunday, December 10, 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.FULL,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
|
||||
// UK locale
|
||||
assertEquals(
|
||||
"10/12/2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"10 Dec 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"10 December 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.LONG,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Sunday, 10 December 2023",
|
||||
instant.toFormattedDateStyle(
|
||||
dateStyle = FormatStyle.FULL,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toFormattedTimeStyle should return correctly formatted string with with locale`() {
|
||||
val instant = Instant.parse("2023-12-10T15:30:00Z")
|
||||
|
||||
// US locale
|
||||
assertEquals(
|
||||
"3:30 PM",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"3:30:00 PM",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"3:30:00 PM Z",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.LONG,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"3:30:00 PM Z",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.FULL,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
|
||||
// UK locale
|
||||
assertEquals(
|
||||
"15:30",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"15:30:00",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"15:30:00 Z",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.LONG,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"15:30:00 Z",
|
||||
instant.toFormattedTimeStyle(
|
||||
timeStyle = FormatStyle.FULL,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toFormattedDateTimeStyle should return correctly formatted string with with locale`() {
|
||||
val instant = Instant.parse("2023-12-10T15:30:00Z")
|
||||
|
||||
// US locale
|
||||
assertEquals(
|
||||
"12/10/23, 3:30 PM",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Dec 10, 2023, 3:30:00 PM",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"December 10, 2023 at 3:30:00 PM Z",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.LONG,
|
||||
timeStyle = FormatStyle.LONG,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Sunday, December 10, 2023 at 3:30:00 PM Z",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.FULL,
|
||||
timeStyle = FormatStyle.FULL,
|
||||
locale = Locale.US,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
|
||||
// UK locale
|
||||
assertEquals(
|
||||
"10/12/2023, 15:30",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.SHORT,
|
||||
timeStyle = FormatStyle.SHORT,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"10 Dec 2023, 15:30:00",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.MEDIUM,
|
||||
timeStyle = FormatStyle.MEDIUM,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"10 December 2023 at 15:30:00 Z",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.LONG,
|
||||
timeStyle = FormatStyle.LONG,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
"Sunday, 10 December 2023 at 15:30:00 Z",
|
||||
instant.toFormattedDateTimeStyle(
|
||||
dateStyle = FormatStyle.FULL,
|
||||
timeStyle = FormatStyle.FULL,
|
||||
locale = Locale.UK,
|
||||
clock = FIXED_CLOCK,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private val FIXED_CLOCK: Clock = Clock.fixed(
|
||||
Instant.parse("2023-10-27T12:00:00Z"),
|
||||
ZoneOffset.UTC,
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user