Skip to content

Commit 8426233

Browse files
Merge pull request #771 from nextcloud/feat/noid/dateFormatter
Conditional, relative/absolute date/time formatter
2 parents 652e447 + 89291a0 commit 8426233

File tree

5 files changed

+124
-11
lines changed

5 files changed

+124
-11
lines changed

.tx/config

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[main]
2+
host = https://www.transifex.com
3+
4+
[o:nextcloud:p:nextcloud:r:android-common]
5+
file_filter = core/src/main/res/values-<lang>/strings.xml
6+
source_file = core/src/main/res/values/strings.xml
7+
source_lang = en
8+
type = ANDROID
9+
lang_map = en_NZ: en-rNZ, qut_GT: qut-rGT, fo_FO: fo-rFO, ky_KG: ky-rKG, pl_PL: pl-rPL, ar_SA: ar-rSA, sa_IN: sa-rIN, ar_OM: ar-rOM, sr_RS: sr-rRS, bn_BD: bn-rBD, en_BZ: en-rBZ, ga_IE: ga-rIE, gsw_FR: gsw-rFR, rm_CH: rm-rCH, es_AR: es-rAR, ja_JP: ja-rJP, kok_IN: kok-rIN, zh_CN.GB2312: zh-rBG, it_CH: it-rCH, bo_CN: bo-rCN, ta_LK: ta-rLK, de_LU: de-rLU, fr_CH: fr-rCH, ug_CN: ug-rCN, az_AZ: az-rAZ, hu_HU: hu-rHU, lb_LU: lb-rLU, quz_EC: quz-rEC, tr_TR: tr-rTR, es_GT: es-rGT, tg_TJ: tg-rTJ, tk_TM: tk-rTM, ar_EG: ar-rEG, en_ZA: en-rZA, mn_MN: mn-rMN, sms_FI: sms-rFI, ar_LY: ar-rLY, ba_RU: ba-rRU, kk_KZ: kk-rKZ, nl_BE: nl-rBE, tzm_DZ: tzm-rDZ, de_AT: de-rAT, es_NI: es-rNI, or_IN: or-rIN, da_DK: da-rDK, dsb_DE: dsb-rDE, en@pirate: en-rpirate, lt_LT: lt-rLT, es_PY: es-rPY, bs_BA: bs-rBA, es_CO: es-rCO, pt_BR: pt-rBR, smj_NO: smj-rNO, ar_YE: ar-rYE, es_DO: es-rDO, fr_FR: fr-rFR, si_LK: si-rLK, sv_FI: sv-rFI, en_JM: en-rJM, sma_NO: sma-rNO, sma_SE: sma-rSE, zu_ZA: zu-rZA, ii_CN: ii-rCN, arn_CL: arn-rCL, be_BY: be-rBY, en_IN: en-rIN, es_EC: es-rEC, sq_AL: sq-rAL, ar_TN: ar-rTN, fr_LU: fr-rLU, xh_ZA: xh-rZA, am_ET: am-rET, ca_ES: ca-rES, fy_NL: fy-rNL, sr_ME: sr-rME, ar_KW: ar-rKW, hy_AM: hy-rAM, prs_AF: prs-rAF, en_AU: en-rAU, syr_SY: syr-rSY, uz_UZ: uz-rUZ, yo_NG: yo-rNG, es_HN: es-rHN, de_DE: de-rDE, es_CR: es-rCR, eu_ES: eu-rES, quz_BO: quz-rBO, sr_CS: sr-rCS, bn_IN: bn-rIN, dv_MV: dv-rMV, en_IE: en-rIE, mr_IN: mr-rIN, ne_NP: ne-rNP, co_FR: co-rFR, en_GB: b+en+001, ar_LB: ar-rLB, sw_KE: sw-rKE, hr_HR: hr-rHR, en_TT: en-rTT, smj_SE: smj-rSE, as_IN: as-rIN, id_ID: id-rID, mk_MK: mk-rMK, de_CH: de-rCH, oc_FR: oc-rFR, zh_CN: zh-rCN, zh_HK: zh-rHK, zh_SG: zh-rSG, ar_MA: ar-rMA, es_VE: es-rVE, ko_KR: ko-rKR, sr@latin: sr-rSP, ar_IQ: ar-rIQ, ig_NG: ig-rNG, mt_MT: mt-rMT, se_NO: se-rNO, bg_BG: bg-rBG, en_SG: en-rSG, ku_IQ: ku-rIQ, lo_LA: lo-rLA, ml_IN: ml-rIN, smn_FI: smn-rFI, uk_UA: uk-rUA, sr_BA: sr-rBA, mi_NZ: mi-rNZ, ar_DZ: ar-rDZ, hi_IN: hi-rIN, se_FI: se-rFI, fi_FI: fi-rFI, en_PH: en-rPH, ms_BN: ms-rBN, nn_NO: nn-rNO, pt_PT: pt-rPT, af_ZA: af-rZA, km_KH: km-rKH, es_SV: es-rSV, sah_RU: sah-rRU, en_US: en-rUS, id: in, pa_IN: pa-rIN, tt_RU: tt-rRU, ar_SY: ar-rSY, gu_IN: gu-rIN, my_MM: my, es_ES: es-rES, hr_BA: hr-rBA, br_FR: br-rFR, fr_MC: fr-rMC, ms_MY: ms-rMY, vi_VN: vi-rVN, ar_JO: ar-rJO, es_CL: es-rCL, fa_IR: fa-rIR, gl_ES: gl-rES, ps_AF: ps-rAF, ar_QA: ar-rQA, rw_RW: rw-rRW, ro_RO: ro-rRO, de_LI: de-rLI, cs_CZ: cs-rCZ, kl_GL: kl-rGL, es_PE: es-rPE, zh_TW: zh-rTW, fr_BE: fr-rBE, kn_IN: kn-rIN, tn_ZA: tn-rZA, hsb_DE: hsb-rDE, ar_BH: ar-rBH, ar_AE: ar-rAE, en_CA: en-rCA, he_IL: he-rIL, sv_SE: sv-rSE, ta_IN: ta-rIN, es_419: b+es+419, is_IS: is-rIS, iu_CA: iu-rCA, fil_PH: fil-rPH, mn_CN: mn-rCN, nso_ZA: nso-rZA, es_PA: es-rPA, nl_NL: nl-rNL, sk_SK: sk-rSK, en_MY: en-rMY, moh_CA: moh-rCA, cy_GB: cy-rGB, en_ZW: en-rZW, es_BO: es-rBO, es_MX: es-rMX, fr_CA: fr-rCA, it_IT: it-rIT, zh_MO: zh-rMO, sl_SI: sl-rSI, et_EE: et-rEE, gd_GB: gd-rGB, ka_GE: ka-rGE, nb_NO: nb-rNO, se_SE: se-rSE, ur_PK: ur-rPK, wo_SN: wo-rSN, el_GR: el-rGR, es_UY: es-rUY, quz_PE: quz-rPE, he: iw, ru_RU: ru-rRU, es_PR: es-rPR, lv_LV: lv-rLV, te_IN: te-rIN, th_TH: th-rTH, ha_NG: ha-rNG
10+

.tx/config.license

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
2+
SPDX-License-Identifier: MIT

core/src/main/java/com/nextcloud/android/common/core/SampleLibraryClass.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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.os.Build
11+
import android.text.format.DateFormat
12+
import com.nextcloud.android.common.core.R
13+
import java.text.SimpleDateFormat
14+
import java.util.Calendar
15+
import kotlin.text.toInt
16+
17+
/**
18+
* Helper implementation for date formatting.
19+
*/
20+
class DateFormatter(
21+
private val context: Context
22+
) {
23+
private val sdfDays: SimpleDateFormat
24+
private val sdfMonths: SimpleDateFormat
25+
private val sdfYears: SimpleDateFormat
26+
27+
/**
28+
* constructor.
29+
*/
30+
init {
31+
val locale =
32+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
33+
this.context.resources.configuration
34+
.getLocales()
35+
.get(0)
36+
} else {
37+
this.context.resources.configuration.locale
38+
}
39+
this.sdfDays = SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "EEE"), locale)
40+
this.sdfMonths =
41+
SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "MMM d"), locale)
42+
this.sdfYears =
43+
SimpleDateFormat(DateFormat.getBestDateTimePattern(locale, "MMM d, yyyy"), locale)
44+
}
45+
46+
/**
47+
* Returns a conditionally relative date formated string.
48+
* For anything less than 1h hours a relative time in minutes will be returned,
49+
* for anything less than 24h hours a relative time in hours will be returned,
50+
* for anything less than 6 days the day of the week in short form,
51+
* for anything up to 364 days a day and moth string will be returned,
52+
* for anything more than 364 days from now a complete date will be returned.
53+
*
54+
* @param calendar to be formatted calendar
55+
* @return formatted date strings
56+
*/
57+
fun getConditionallyRelativeFormattedTimeSpan(calendar: Calendar): String {
58+
val span = System.currentTimeMillis() - calendar.getTimeInMillis()
59+
return when {
60+
// less than 1m
61+
span < ONE_MINUTE_IN_MILLIS -> context.getString(R.string.date_formatting_now)
62+
// less than 1h
63+
span < ONE_HOUR_IN_MILLIS ->
64+
context.getString(
65+
R.string.date_formatting_relative_minutes,
66+
span / ONE_MINUTE_IN_MILLIS
67+
)
68+
// less than 1d
69+
span < ONE_DAY_IN_MILLIS -> {
70+
val hours: Int = span.toInt() / ONE_HOUR_IN_MILLIS
71+
context
72+
.resources
73+
.getQuantityString(R.plurals.date_formatting_relative_hours, hours, hours)
74+
}
75+
// less than 1w
76+
span <= SIX_DAYS_IN_MILLIS -> sdfDays.format(calendar.getTime())
77+
// less than 1y -> up to 364 days
78+
span <= YEAR_IN_MILLIS -> sdfMonths.format(calendar.getTime())
79+
// more than 1y -> more than 364 days
80+
else -> sdfYears.format(calendar.getTime())
81+
}
82+
}
83+
84+
/**
85+
* Time constants for conditional formatting.
86+
*/
87+
companion object {
88+
private const val ONE_MINUTE_IN_MILLIS: Int = 60000
89+
private const val ONE_HOUR_IN_MILLIS: Int = ONE_MINUTE_IN_MILLIS * 60
90+
private const val ONE_DAY_IN_MILLIS: Int = ONE_HOUR_IN_MILLIS * 24
91+
private const val SIX_DAYS_IN_MILLIS: Int = ONE_DAY_IN_MILLIS * 6
92+
private const val YEAR_IN_MILLIS: Long = ONE_DAY_IN_MILLIS * 364L
93+
}
94+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
~ Nextcloud Android Common Library
4+
~
5+
~ SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
6+
~ SPDX-License-Identifier: MIT
7+
-->
8+
<resources>
9+
<!-- relative time less than 1 minute using the term: Now -->
10+
<string name="date_formatting_now">Now</string>
11+
<!-- relative time in minutes, less than 1 hour, i.e. 1m, 5m, 59m -->
12+
<string name="date_formatting_relative_minutes">%dm</string>
13+
<!-- relative time in hours, less than 1 day, i.e. 1h, 5h, 23h -->
14+
<plurals name="date_formatting_relative_hours">
15+
<item quantity="one">%dh</item>
16+
<item quantity="other">%dh</item>
17+
</plurals>
18+
</resources>

0 commit comments

Comments
 (0)