|
| 1 | +/** |
| 2 | + * Nextcloud Android Common Library |
| 3 | + * |
| 4 | + * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors |
| 5 | + * SPDX-License-Identifier: MIT |
| 6 | + */ |
| 7 | +package com.nextcloud.android.common.core.utils |
| 8 | + |
| 9 | +import android.content.Context |
| 10 | +import android.text.format.DateFormat |
| 11 | +import com.nextcloud.android.common.core.R |
| 12 | +import java.text.SimpleDateFormat |
| 13 | +import java.util.Calendar |
| 14 | + |
| 15 | +/** |
| 16 | + * Helper implementation for date formatting. |
| 17 | + */ |
| 18 | +class DateFormatter( |
| 19 | + private val context: Context |
| 20 | +) { |
| 21 | + private val sdfDays: SimpleDateFormat |
| 22 | + private val sdfMonths: SimpleDateFormat |
| 23 | + private val sdfYears: SimpleDateFormat |
| 24 | + |
| 25 | + /** |
| 26 | + * constructor. |
| 27 | + * |
| 28 | + * @param context Context needed to load locale-specific date/time-patterns and translation strings. |
| 29 | + */ |
| 30 | + init { |
| 31 | + val locale = this.context.resources.configuration.locale |
| 32 | + this.sdfDays = SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "EEE"), locale) |
| 33 | + this.sdfMonths = |
| 34 | + SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "MMM d"), locale) |
| 35 | + this.sdfYears = |
| 36 | + SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "MMM d, yyyy"), locale) |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Returns a conditionally relative date formated string. |
| 41 | + * For anything less than 1h hours a relative time in minutes will be returned, |
| 42 | + * for anything less than 24h hours a relative time in hours will be returned, |
| 43 | + * for anything less than 6 days the day of the week in short form, |
| 44 | + * for anything up to 364 days a day and moth string will be returned, |
| 45 | + * for anything more than 364 days from now a complete date will be returned. |
| 46 | + * |
| 47 | + * @param calendar to be formatted calendar |
| 48 | + * @return formatted date strings |
| 49 | + */ |
| 50 | + fun getConditionallyRelativeFormattedTimeSpan(calendar: Calendar): String { |
| 51 | + var timeSpan = "" |
| 52 | + val span = System.currentTimeMillis() - calendar.getTimeInMillis() |
| 53 | + if (span < ONE_MINUTE_IN_MILLIS) { |
| 54 | + // less than 1m |
| 55 | + timeSpan = context.getString(R.string.date_formatting_now) |
| 56 | + } else if (span < ONE_HOUR_IN_MILLIS) { |
| 57 | + // less than 1h |
| 58 | + timeSpan = |
| 59 | + context.getString( |
| 60 | + R.string.date_formatting_relative_minutes, |
| 61 | + span / ONE_MINUTE_IN_MILLIS |
| 62 | + ) |
| 63 | + } else if (span < ONE_DAY_IN_MILLIS) { |
| 64 | + // less than 24h |
| 65 | + val hours: Int = span.toInt() / ONE_HOUR_IN_MILLIS |
| 66 | + timeSpan = |
| 67 | + context |
| 68 | + .resources |
| 69 | + .getQuantityString(R.plurals.date_formatting_relative_hours, hours, hours) |
| 70 | + } else if (span <= SIX_DAYS_IN_MILLIS) { |
| 71 | + // less than 6 days |
| 72 | + timeSpan = sdfDays.format(calendar.getTime()) |
| 73 | + } else if (span <= YEAR_IN_MILLIS) { |
| 74 | + // up to 364 days |
| 75 | + timeSpan = sdfMonths.format(calendar.getTime()) |
| 76 | + } else { |
| 77 | + // more than 364 days |
| 78 | + timeSpan = sdfYears.format(calendar.getTime()) |
| 79 | + } |
| 80 | + return timeSpan |
| 81 | + } |
| 82 | + |
| 83 | + companion object { |
| 84 | + private const val ONE_MINUTE_IN_MILLIS = 60000 |
| 85 | + private const val ONE_HOUR_IN_MILLIS: Int = ONE_MINUTE_IN_MILLIS * 60 |
| 86 | + private const val ONE_DAY_IN_MILLIS: Int = ONE_HOUR_IN_MILLIS * 24 |
| 87 | + private const val SIX_DAYS_IN_MILLIS: Int = ONE_DAY_IN_MILLIS * 6 |
| 88 | + private const val YEAR_IN_MILLIS: Long = ONE_DAY_IN_MILLIS * 364L |
| 89 | + } |
| 90 | +} |
0 commit comments