Skip to content

Commit daed5db

Browse files
committed
fix: backup relative dates
1 parent 59d9b48 commit daed5db

File tree

1 file changed

+62
-88
lines changed

1 file changed

+62
-88
lines changed

app/src/main/java/to/bitkit/ext/DateTime.kt

Lines changed: 62 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ package to.bitkit.ext
44

55
import android.icu.text.DateFormat
66
import android.icu.text.DisplayContext
7+
import android.icu.text.NumberFormat
78
import android.icu.text.RelativeDateTimeFormatter
9+
import android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit
10+
import android.icu.text.RelativeDateTimeFormatter.Direction
11+
import android.icu.text.RelativeDateTimeFormatter.RelativeUnit
812
import android.icu.util.ULocale
913
import kotlinx.datetime.Clock
1014
import kotlinx.datetime.LocalDate
@@ -62,67 +66,33 @@ fun Long.toRelativeTimeString(
6266
val now = nowMillis(clock)
6367
val diffMillis = now - this
6468

69+
val uLocale = ULocale.forLocale(locale)
70+
val numberFormat = NumberFormat.getNumberInstance(uLocale)?.apply { maximumFractionDigits = 0 }
71+
6572
val formatter = RelativeDateTimeFormatter.getInstance(
66-
ULocale.forLocale(locale),
67-
null,
73+
uLocale,
74+
numberFormat,
6875
RelativeDateTimeFormatter.Style.LONG,
69-
DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE,
76+
DisplayContext.CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE,
7077
) ?: return toLocalizedTimestamp()
7178

72-
val seconds = diffMillis / Constants.MILLIS_TO_SECONDS
73-
val minutes = (seconds / Constants.SECONDS_TO_MINUTES).toInt()
74-
val hours = (minutes / Constants.MINUTES_TO_HOURS).toInt()
75-
val days = (hours / Constants.HOURS_TO_DAYS).toInt()
76-
val weeks = (days / Constants.DAYS_TO_WEEKS).toInt()
77-
val months = (days / Constants.DAYS_TO_MONTHS).toInt()
78-
val years = (days / Constants.DAYS_TO_YEARS).toInt()
79+
val seconds = diffMillis / Factor.MILLIS_TO_SECONDS
80+
val minutes = seconds / Factor.SECONDS_TO_MINUTES
81+
val hours = minutes / Factor.MINUTES_TO_HOURS
82+
val days = hours / Factor.HOURS_TO_DAYS
83+
val weeks = days / Factor.DAYS_TO_WEEKS
84+
val months = days / Factor.DAYS_TO_MONTHS
85+
val years = days / Factor.DAYS_TO_YEARS
7986

8087
return when {
81-
seconds < Constants.SECONDS_THRESHOLD -> formatter.format(
82-
RelativeDateTimeFormatter.Direction.PLAIN,
83-
RelativeDateTimeFormatter.AbsoluteUnit.NOW,
84-
)
85-
86-
minutes < Constants.MINUTES_THRESHOLD -> formatter.format(
87-
minutes.toDouble(),
88-
RelativeDateTimeFormatter.Direction.LAST,
89-
RelativeDateTimeFormatter.RelativeUnit.MINUTES,
90-
)
91-
92-
hours < Constants.HOURS_THRESHOLD -> formatter.format(
93-
hours.toDouble(),
94-
RelativeDateTimeFormatter.Direction.LAST,
95-
RelativeDateTimeFormatter.RelativeUnit.HOURS,
96-
)
97-
98-
days < Constants.YESTERDAY_THRESHOLD -> formatter.format(
99-
RelativeDateTimeFormatter.Direction.LAST,
100-
RelativeDateTimeFormatter.AbsoluteUnit.DAY,
101-
)
102-
103-
days < Constants.DAYS_THRESHOLD -> formatter.format(
104-
days.toDouble(),
105-
RelativeDateTimeFormatter.Direction.LAST,
106-
RelativeDateTimeFormatter.RelativeUnit.DAYS,
107-
)
108-
109-
weeks < Constants.WEEKS_THRESHOLD -> formatter.format(
110-
weeks.toDouble(),
111-
RelativeDateTimeFormatter.Direction.LAST,
112-
RelativeDateTimeFormatter.RelativeUnit.WEEKS,
113-
)
114-
115-
months < Constants.MONTHS_THRESHOLD -> formatter.format(
116-
months.toDouble(),
117-
RelativeDateTimeFormatter.Direction.LAST,
118-
RelativeDateTimeFormatter.RelativeUnit.MONTHS,
119-
)
120-
121-
else -> formatter.format(
122-
years.toDouble(),
123-
RelativeDateTimeFormatter.Direction.LAST,
124-
RelativeDateTimeFormatter.RelativeUnit.YEARS,
125-
)
88+
seconds < Threshold.SECONDS -> formatter.format(Direction.PLAIN, AbsoluteUnit.NOW)
89+
minutes < Threshold.MINUTES -> formatter.format(minutes, Direction.LAST, RelativeUnit.MINUTES)
90+
hours < Threshold.HOURS -> formatter.format(hours, Direction.LAST, RelativeUnit.HOURS)
91+
days < Threshold.YESTERDAY -> formatter.format(Direction.LAST, AbsoluteUnit.DAY)
92+
days < Threshold.DAYS -> formatter.format(days, Direction.LAST, RelativeUnit.DAYS)
93+
weeks < Threshold.WEEKS -> formatter.format(weeks, Direction.LAST, RelativeUnit.WEEKS)
94+
months < Threshold.MONTHS -> formatter.format(months, Direction.LAST, RelativeUnit.MONTHS)
95+
else -> formatter.format(years, Direction.LAST, RelativeUnit.YEARS)
12696
}
12797
}
12898

@@ -158,41 +128,43 @@ fun getDaysInMonth(month: LocalDate): List<LocalDate?> {
158128
}
159129

160130
fun isLeapYear(year: Int): Boolean {
161-
return (year % Constants.LEAP_YEAR_DIVISOR_4 == 0 && year % Constants.LEAP_YEAR_DIVISOR_100 != 0) || (year % Constants.LEAP_YEAR_DIVISOR_400 == 0)
131+
return (year % Constants.LEAP_YEAR_DIVISOR_4 == 0 && year % Constants.LEAP_YEAR_DIVISOR_100 != 0) ||
132+
(year % Constants.LEAP_YEAR_DIVISOR_400 == 0)
162133
}
163134

164-
fun isDateInRange(dateMillis: Long, startMillis: Long?, endMillis: Long?): Boolean {
135+
fun isDateInRange(
136+
dateMillis: Long,
137+
startMillis: Long?,
138+
endMillis: Long?,
139+
zone: TimeZone = TimeZone.currentSystemDefault(),
140+
): Boolean {
165141
if (startMillis == null) return false
166142
val end = endMillis ?: startMillis
167143

168-
val normalizedDate =
169-
kotlinx.datetime.Instant.fromEpochMilliseconds(dateMillis).toLocalDateTime(TimeZone.currentSystemDefault()).date
170-
val normalizedStart = kotlinx.datetime.Instant.fromEpochMilliseconds(startMillis)
171-
.toLocalDateTime(TimeZone.currentSystemDefault()).date
172-
val normalizedEnd =
173-
kotlinx.datetime.Instant.fromEpochMilliseconds(end).toLocalDateTime(TimeZone.currentSystemDefault()).date
144+
val normalizedDate = kotlinx.datetime.Instant.fromEpochMilliseconds(dateMillis).toLocalDateTime(zone).date
145+
val normalizedStart = kotlinx.datetime.Instant.fromEpochMilliseconds(startMillis).toLocalDateTime(zone).date
146+
val normalizedEnd = kotlinx.datetime.Instant.fromEpochMilliseconds(end).toLocalDateTime(zone).date
174147

175-
return normalizedDate >= normalizedStart && normalizedDate <= normalizedEnd
148+
return normalizedDate in normalizedStart..normalizedEnd
176149
}
177150

178-
fun LocalDate.toMonthYearString(): String {
179-
val formatter = SimpleDateFormat(DatePattern.MONTH_YEAR_FORMAT, Locale.getDefault())
151+
fun LocalDate.toMonthYearString(locale: Locale = Locale.getDefault()): String {
152+
val formatter = SimpleDateFormat(DatePattern.MONTH_YEAR_FORMAT, locale)
180153
val calendar = Calendar.getInstance()
181154
calendar.set(year, monthNumber - CalendarConstants.MONTH_INDEX_OFFSET, Constants.FIRST_DAY_OF_MONTH)
182155
return formatter.format(calendar.time)
183156
}
184157

185158
fun LocalDate.minusMonths(months: Int): LocalDate =
186-
this.toJavaLocalDate().minusMonths(months.toLong()).withDayOfMonth(1) // Always use first day of month for display
159+
toJavaLocalDate().minusMonths(months.toLong()).withDayOfMonth(1) // Always use first day of month for display
187160
.toKotlinLocalDate()
188161

189162
fun LocalDate.plusMonths(months: Int): LocalDate =
190-
this.toJavaLocalDate().plusMonths(months.toLong()).withDayOfMonth(1) // Always use first day of month for display
163+
toJavaLocalDate().plusMonths(months.toLong()).withDayOfMonth(1) // Always use first day of month for display
191164
.toKotlinLocalDate()
192165

193-
fun LocalDate.endOfDay(): Long {
194-
return this.atStartOfDayIn(TimeZone.currentSystemDefault()).plus(1.days).minus(1.milliseconds).toEpochMilliseconds()
195-
}
166+
fun LocalDate.endOfDay(zone: TimeZone = TimeZone.currentSystemDefault()): Long =
167+
atStartOfDayIn(zone).plus(1.days).minus(1.milliseconds).toEpochMilliseconds()
196168

197169
fun utcDateFormatterOf(pattern: String) = SimpleDateFormat(pattern, Locale.US).apply {
198170
timeZone = java.util.TimeZone.getTimeZone("UTC")
@@ -215,31 +187,33 @@ object DatePattern {
215187
}
216188

217189
private object Constants {
218-
// Time conversion factors
190+
// Calendar
191+
const val FIRST_DAY_OF_MONTH = 1
192+
193+
// Leap year calculation
194+
const val LEAP_YEAR_DIVISOR_4 = 4
195+
const val LEAP_YEAR_DIVISOR_100 = 100
196+
const val LEAP_YEAR_DIVISOR_400 = 400
197+
}
198+
199+
private object Factor {
219200
const val MILLIS_TO_SECONDS = 1000.0
220201
const val SECONDS_TO_MINUTES = 60.0
221202
const val MINUTES_TO_HOURS = 60.0
222203
const val HOURS_TO_DAYS = 24.0
223204
const val DAYS_TO_WEEKS = 7.0
224205
const val DAYS_TO_MONTHS = 30.0
225206
const val DAYS_TO_YEARS = 365.0
207+
}
226208

227-
// Time unit thresholds
228-
const val SECONDS_THRESHOLD = 60
229-
const val MINUTES_THRESHOLD = 60
230-
const val HOURS_THRESHOLD = 24
231-
const val YESTERDAY_THRESHOLD = 2
232-
const val DAYS_THRESHOLD = 7
233-
const val WEEKS_THRESHOLD = 4
234-
const val MONTHS_THRESHOLD = 12
235-
236-
// Calendar
237-
const val FIRST_DAY_OF_MONTH = 1
238-
239-
// Leap year calculation
240-
const val LEAP_YEAR_DIVISOR_4 = 4
241-
const val LEAP_YEAR_DIVISOR_100 = 100
242-
const val LEAP_YEAR_DIVISOR_400 = 400
209+
private object Threshold {
210+
const val SECONDS = 60
211+
const val MINUTES = 60
212+
const val HOURS = 24
213+
const val YESTERDAY = 2
214+
const val DAYS = 7
215+
const val WEEKS = 4
216+
const val MONTHS = 12
243217
}
244218

245219
object CalendarConstants {

0 commit comments

Comments
 (0)