Repository: mlemgroup/mlem
Pull request #2033: [#2032] Fix localized elapsed time on profile
Author: login: pylapp
Created: 2025-05-15T11:29:59Z | Merged: 2025-05-16T19:38:44Z

<!--
Thank you for opening a pull request!

We assume you have read CONTRIBUTING.md. If you have not, do not be surprised if your PR is rejected for reasons listed therein.

Please note that if your PR does not address an issue that was assigned to you, you are still welcome to open it; however, it will not receive merge priority and may be rejected for scope reasons.
-->

## Issues

- closes #2032

## Description

<!-- Describe what this PR does at a high level (e.g., "adds a toggle to do <thing>") -->

The elapsed time since the creation of the Lemmy account displayed on the profile now has the expected value.
The value is computed and does not display for example "-1" if the account is more than 2 years.
The string is also displayed in full format so as to help understandability and *Voice Over* vocalization.

## Implementation Notes

<!-- Any information about the code that would be helpful for reviewing -->
- Use the dates in the expected format so as to allow the `RelativeDateTimeFormatter` to process them (i.e. otherwise fail if hours are in dates)
- Change units style to have a more understandable string representation of the elapsed time
- Add unit tests to ensure the date calculations remain the expected ones
- Make some properties and function public to allow unit tests



Linked issue #2032: Elapsed time on profile since creation is not the expected time
### Requirements

- [x] There are no existing issues for this bug report.

# Description

Given a Lemmy account created at 04/11/2023
When I display my profile with Mlem 2.1 (322)
Then I see in my profile it was created less than one year ago

Given a Lemmy account created at 04/11/2023
When I display my profile with Mlem 2.1 (322)
Then I see in my profile it was created "-1 a" which can be hardly understandable

# Screenshots

<img src="https://github.com/user-attachments/assets/9daacb90-82ba-4b0f-a774-e1db11700080" alt="Lemmy web profile" width="200"/>

<img src="https://github.com/user-attachments/assets/5c4d0224-9d13-481b-9106-cff78f907e66" alt="Mlem 2.1 profile with bug" width="200"/>

### Mlem Version

Mlem 2.1 (322)
Linked issue comments: user: login: pylapp
created_at: 2025-05-15T11:21:31Z
body: FYI a pull request will be submitted in next minutes :)
author_association: CONTRIBUTOR
user: login: pylapp
created_at: 2025-05-15T11:33:25Z
body: After investigations in the source code, it seems the issue is on the use of the `RelativeDateTiemFormatter`which fails to process dates if it contains hours.

You can use the following code in a Xocde playground to test.

```swift
import SwiftUI

// Cake day
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/mm/yyyy"
let cakeDayDate = dateFormatter.date(from: "04/11/2023")! // Pure day, month and year, no hours nor time zone

// Formatter used in Mlem
let formatter = RelativeDateTimeFormatter()
formatter.unitsStyle = .abbreviated

// Date displayed in Mlem user profile
let displayedDate = formatter.localizedString(for: cakeDayDate, relativeTo: Date.now)

// Results
print("Display date: \(displayedDate)")
// displayedDate = "2 yr ago"
// but in Mlem: "-1 a"
```

@EricBAndrews @Sjmarf  FYI the pull request is ready for review :)
author_association: CONTRIBUTOR

Diff:
diff --git a/Mlem/App/Utility/Extensions/Date+Extensions.swift b/Mlem/App/Utility/Extensions/Date+Extensions.swift
index 80fbba9849..c28db6c0b1 100644
--- a/Mlem/App/Utility/Extensions/Date+Extensions.swift
+++ b/Mlem/App/Utility/Extensions/Date+Extensions.swift
@@ -8,19 +8,29 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
-
         return formatter.localizedString(for: self, relativeTo: date)
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023".
+    /// Uses the current locale to let the `DateFormatter` apply the suitable date format depending to the user needs.
+    public var dateString: String {
         let dateFormatter = DateFormatter()
         dateFormatter.dateStyle = .short
         dateFormatter.timeStyle = .none
+        dateFormatter.locale = Locale.current
         return dateFormatter.string(from: self)
     }
     
diff --git a/Mlem/App/Views/Shared/ProfileDateView.swift b/Mlem/App/Views/Shared/ProfileDateView.swift
index 3c76812f69..ae1eb7c394 100644
--- a/Mlem/App/Views/Shared/ProfileDateView.swift
+++ b/Mlem/App/Views/Shared/ProfileDateView.swift
@@ -34,6 +34,11 @@ struct ProfileDateView: View {
         profilable.createdRecently ? .lemmy.newAccountFlair : .lemmy.cakeDay
     }
     
+    /// Returns a `String` with the cake date and a custom message depending to if today is cake day or not.
+    /// If the current day is not the cake day, forges a `String` with relative time between the cake date and today.
+    /// In that case the result string is in *full* unit style so as to improve vocalization of the date with *Voice Over¨.
+    /// - Parameter date: the date to process, here the profile creation daye
+    /// - Returns String: The enriched string to add in the profile
     func format(_ date: Date) -> String {
         if profilable.isCakeDay {
             // It's possible for it to be a user's cake day without their account age quite being 365 days.
@@ -42,6 +47,6 @@ struct ProfileDateView: View {
             let components = Calendar.current.dateComponents([.year], from: startDate, to: .now)
             return "\(date.dateString), " + String(localized: "\(components.year ?? 0) years ago today!")
         }
-        return "\(date.dateString), \(date.getRelativeTime(unitsStyle: .abbreviated))"
+        return "\(date.dateString), \(date.getRelativeTime(unitsStyle: .full))"
     }
 }
diff --git a/MlemTests/DateTests.swift b/MlemTests/DateTests.swift
new file mode 100644
index 0000000000..a02b98ced4
--- /dev/null
+++ b/MlemTests/DateTests.swift
@@ -0,0 +1,139 @@
+//
+// Software Name: Mlem
+// SPDX-FileCopyrightText: Copyright (c) Mlem Group
+// SPDX-License-Identifier: GPL-3.0
+//
+// This software is distributed under the GNU General Public License v3.0 license,
+// the text of which is available at https://www.gnu.org/licenses/gpl-3.0-standalone.html
+// or see the "LICENSE" file for more details.
+//
+
+import SwiftUI
+import Testing
+
+/// Contains tests cases to check some `Date` extensions utils.
+/// NOTE: Supposed the language of the device / simulator under tests is english
+struct DateTests {
+    @Test(
+        "Get relative time must return the localized expected elapsed time for not cake day and more than one year",
+        .bug("https://github.com/mlemgroup/mlem/issues/2032")
+    )
+    func get_relative_time_returns_localized_string_for_more_than_one_year() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, someDate: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2023-11-14 12:05:00 +0000")!
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        someDate = dateFormatter.date(from: "15/05/2025")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: someDate, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "1 year ago")
+    }
+    
+    @Test("Get relative time must return the elapsed days for accounts of several days old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_days_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-20 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "4 days ago")
+    }
+
+    @Test("Get relative time must return the elapsed weeks for accounts of several weeks old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_weeks_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-01 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-15 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "2 weeks ago")
+    }
+
+    @Test("Get relative time must return the elapsed months for accounts of several months old")
+    func get_relative_time_must_return_elapsed_months_for_accounts_of_several_months_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-12-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "7 months ago")
+    }
+    
+    @Test("Get relative time must return the elapsed hours for accounts younger than one day but older than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_several_hours_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "3 hours ago")
+    }
+
+    @Test("Get relative time must return the elapsed minutes for accounts younger than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_less_one_hour_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "25 minutes ago")
+    }
+
+    @Test("Get relative time must return the elapsed seconds for accounts of some seconds old")
+    func get_relative_time_must_return_elapsed_seconds_for_accounts_of_some_seconds_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:05:42 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "42 seconds ago")
+    }
+}


Reviews:
user: login: Sjmarf
body:  Thanks. I am at work right now, will give this a more thorough review later. Is this maybe related to [this issue](https://github.com/mlemgroup/mlem/issues/1988)?
 
 If an account was created less than two years ago, I don't think we should be displaying "2 years ago" in the English version of the app. Rather, I think it would be less confusing to round down and display "1 year ago".  

You mention that it doesn't make sense to display "-1 a" for a 1.5-year-old account in French. I'm curious as to whether we might need to handle this differently for French, in that case? The minus isn't present in the English version - does it have any special meaning?
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-15T12:38:48Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T12:46:30Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T18:01:33Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T18:07:33Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T18:16:19Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T19:18:43Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T19:24:38Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T19:27:53Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T19:48:09Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T19:55:41Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T20:20:48Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T20:34:56Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T20:50:54Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T13:38:30Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T14:05:17Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T15:10:52Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T15:11:49Z
user: login: Sjmarf
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T16:09:40Z
user: login: Sjmarf
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-16T16:10:14Z
user: login: pylapp
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T16:11:17Z
user: login: Sjmarf
body: Nice job! 😄
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-16T18:54:07Z

Review comments:
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: We should use the user's preferred date format rather than hard-coding it. `dd/mm/yyyy` is the preferred format in areas of Europe, but in the US it's `mm/dd/yyyy`, and in other places it's `yyyy-mm-dd`. The user can configure this in System Settings under General -> Language & Region -> Date Format
created_at: 2025-05-15T12:34:05Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: Nope, it does not matter that much.
In fact, this is just a format to force the date to get rid of hours, timezones etc.
The returned type is still a `Date`, the `dateFormat` is just to eliminate useless data the `RelativeDateTimeFormatter` cannot parse.
Indeed if the *shortered* value is used as a string it will be more interesting to use user preferences of course, but that's not the aim of this property :D
created_at: 2025-05-15T12:46:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: Ah, I see! That makes sense. My apologies, I was just skim reading the code on my phone earlier and missed what this was being used for.

This is a working way to remove the hours from the `Date`, but I suspect that there might be a better way of doing this that avoids converting to a string. A better way to do this would be to create a `DateComponents` object from the `Date` - the `DateComponents` initializer lets you choose which components to include (so here, we'd be including only the year, month and date). Then, either convert the DateComponents back into a `Date` object. 

A while ago [I implemented a `roundingDownToMostSignificantComponent` function](https://github.com/mlemgroup/mlem/pull/2001/files#diff-dc7c81bdfd0ef0db51ab05c51c3f660065f2b2de1d8820c7600913a95dbd5c29) that may be useful here. If you call that function on a `DateComponents`, it removes all of the components except for the largest one.

> my fix provides "2 years agos" ; indeed it its better than current solution but not perfect as rounded higher, but this is the behaviour of the formatter (and basically 2023 was 2 years ago)

In the context of accounts, I think it's better to always round down rather than to the nearest year. For human beings, you are only "2 years old" when you have been alive for *at least* two years - if you are less than two years old, you are considered to be one year old. I think we should use the same logic here. Using `roundingDownToMostSignificantComponents` would fix this, I think.
created_at: 2025-05-15T18:01:33Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: There's a `getShortRelativeTime` function in `Date+Extensions` that does a lot of this already, actually. Maybe we could reuse that function
created_at: 2025-05-15T18:07:33Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: Ok I will give a try tomorrow. However keep in mind the relative date time formatter you used is quite "high level" so for an event occurred two years ago (i.e. in 2023), it will return "2 years ago".

I will make some trials, and if relevant share with you in this PR the results.

Let's keep in touch!
created_at: 2025-05-15T18:16:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: Sounds good 👍 

> Ok I will give a try tomorrow. However keep in mind the relative date time formatter you used is quite "high level" so for an event occurred two years ago (i.e. in 2023), it will return "2 years ago".

It returns "1 year ago" for me. I just noticed in your test case that you're using a format of `dd/mm/yyyy` - `mm` is for minutes, not for months. For months, use `MM`. Maybe that's the reason?
created_at: 2025-05-15T19:18:43Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: The returned value depends to the logic of the relative date time formatter, I don't have details in mind 😅

Here are the outputs I have for my account with the current implementation.

I keep you in touch with further tests tomorrow 😄

![image](https://github.com/user-attachments/assets/a7e11b2c-17cb-4aa3-86c8-5b4754f4c79c)
![image](https://github.com/user-attachments/assets/f123813d-132a-4fca-af80-f951dc84b425)
created_at: 2025-05-15T19:24:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: Sure 👍 

The date 04/11/2023 is less than two years ago, so we should display "1 year ago". `getShortRelativeTime` returns "1 year ago" for that date :)
created_at: 2025-05-15T19:27:53Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: Ok! FMPOV this is not the best solution but it's your project before all, so I will make the updates tomorrow with these conditions 😄
created_at: 2025-05-15T19:48:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: @Sjmarf Just in case of, are you aware that if we take the rounded lower value the display is not isofunctional with some "legacy" web frontends?

I share you the screenshot for the web portal of the [instance I am in](https://programming.dev/u/pylapp). 

Just wanted to share ; I will round lower the date if you don't change your POV 😄

![image](https://github.com/user-attachments/assets/8d13f7eb-0803-4ecf-9909-73d98c4eb136)
created_at: 2025-05-15T19:55:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: Yes, I'd still prefer to round down to "1 year". What do you think @EricBAndrews?

There are plenty of places where we intentionally differ from the web frontend for design reasons, rather than being consistent - e.g by renaming "feature post" to "pin post". A large portion of our users only use Lemmy through Mlem, so if there's something we can do better than Lemmy-ui, I don't think consistency with Lemmy-ui should be holding us back. 
created_at: 2025-05-15T20:20:48Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: Ok, sounds clear! It's nice to have such details to understand the story and background of the project, In understand!
So let's take your proposals, I should take that tomorrow 😊
created_at: 2025-05-15T20:34:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,33 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "2 years ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to comapre with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/mm/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: And I am one of these users using Lemmy only with Mlem ☺️
created_at: 2025-05-15T20:50:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,35 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        // Using date components to truncate useless data is not relevant as relative date time formatter
+        // cannot process sunch down rounded values
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023"
+    public var dateString: String {
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: This computed property returns a localized version of the `Date`. For my device, it returns `2023-10-05`, not `5/10/2023`. This breaks the `shortered` computed property. We need specify the date format we need (`dd/MM/yyyy`) explicitly in `dateString` in order for it to work properly in all locales.

The StackOverflow post you linked mentions that removing the hours is necessary for "yesterday" to display correctly. Is that the only case where removing the hours is needed? If so, we could stop the formatter from showing `yesterday` like this, and then we wouldn't need to remove the hours.

```swift
        let formatter = RelativeDateTimeFormatter()
        formatter.dateTimeStyle = .numeric
```

Another consideration is that for very new accounts, we currently display the minutes since creation. I suppose that removing the hours from the date would break this?

<img src="https://github.com/user-attachments/assets/b67ffb04-e781-41a5-88b4-7540873e4ac9" width=50%>
created_at: 2025-05-16T13:38:30Z
author_association: MEMBER
diff_hunk: @@ -8,16 +8,35 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        // Using date components to truncate useless data is not relevant as relative date time formatter
+        // cannot process sunch down rounded values
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023"
+    public var dateString: String {
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: I'll have a look on these cases :)
created_at: 2025-05-16T14:05:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,35 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        // Using date components to truncate useless data is not relevant as relative date time formatter
+        // cannot process sunch down rounded values
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023"
+    public var dateString: String {
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: @Sjmarf Branch has been updated.
So, current changes are:
- updated unit tests to ensure the `getRelativeTime()` returns the suitable values (years, days, seconds, etc.)
- used `Local.current` to not force the date format for the formatter and let it define the format depending to user preferences
- removed the now useless proeprty `shortened`

I made also quick-and-dirty screenshots to display the elapsed time (so don't deal with the non-green color or the lead, just wanted to see the values after the commas).

The several tests cases (account with age of seconds, less than one day, some days, more than one year etc.) are covered.

In few words: the bug is fixed and no issues with format of date and minutes / seconds are kept :D 

![hour](https://github.com/user-attachments/assets/01535d13-1700-4271-8bec-11921d390e09)
![hours](https://github.com/user-attachments/assets/7a2fa8a2-38fa-4ee9-9da9-ef71c24d5964)
![seconds](https://github.com/user-attachments/assets/b8b37621-ec2f-4748-b4b8-01aade47d3a9)
![year](https://github.com/user-attachments/assets/c4c397b0-fbb1-40ce-9630-50f38f4157d9)

created_at: 2025-05-16T15:10:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,35 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        // Using date components to truncate useless data is not relevant as relative date time formatter
+        // cannot process sunch down rounded values
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023"
+    public var dateString: String {
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: pylapp
body: @Sjmarf As a user I have a question: what does the green leaf mean?
(Don't mind with my previous screenshots if it was suppoed to have on leaf or not ; I juste tinkered the view in a dirty way for tests)
created_at: 2025-05-16T15:11:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -8,16 +8,35 @@
 import SwiftUI
 
 extension Date {
-    // Returns strings like "3 seconds ago" and "10 days ago"
-    func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
+    /// Forges a localized `String` with inside the computed elapsed time between `self` and another `Date`.
+    /// Uses a `RelativeDateTimeFormatter` and a given units style.
+    ///
+    /// For example, if the `self` is date 04/11/2023 and `date` is 15/05/2025, will return "1 year ago" (localized).
+    ///
+    /// - Parameters:
+    ///    - date: The date to compare with `self`, by default `Date.now`
+    ///    - unitsStyle: The style of the string to forge, by default `RelativeDateTimeFormatter.UnitsStyle.full`
+    /// - Returns String: The localized string based.
+    public func getRelativeTime(date: Date = .now, unitsStyle: RelativeDateTimeFormatter.UnitsStyle = .full) -> String {
         let formatter = RelativeDateTimeFormatter()
         formatter.unitsStyle = unitsStyle
+        // Need to get rid of hours and keep only a simple pure date to have the relative date time formatter working
+        // Using date components to truncate useless data is not relevant as relative date time formatter
+        // cannot process sunch down rounded values
+        return formatter.localizedString(for: shortered, relativeTo: date)
+    }
 
-        return formatter.localizedString(for: self, relativeTo: date)
+    /// Returns `self` but with only the day, the month and the year, i.e. the current date without hours.
+    /// If the conversion fails, returns `self` as is.
+    public var shortered: Date {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        return dateFormatter.date(from: dateString) ?? self
     }
-    
-    // Returns strings like "5/10/2023"
-    var dateString: String {
+
+    /// Returns the current `Date` as a shorter version in `String`.
+    /// For example if the date in the 5th of October 2023, returns "5/10/2023"
+    public var dateString: String {
path: Mlem/App/Utility/Extensions/Date+Extensions.swift
user: login: Sjmarf
body: Nice, works perfectly :)

The green leaf means that the account is less than 30 days old. It's also shown next to the user's name in posts and comments:

<img src="https://github.com/user-attachments/assets/93950118-3aaf-4990-8fac-87e76a44a9fe" width=50%>



created_at: 2025-05-16T16:09:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,153 @@
+//
+// Software Name: Mlem
+// SPDX-FileCopyrightText: Copyright (c) Mlem Group
+// SPDX-License-Identifier: GPL-3.0
+//
+// This software is distributed under the GNU General Public License v3.0 license,
+// the text of which is available at https://www.gnu.org/licenses/gpl-3.0-standalone.html
+// or see the "LICENSE" file for more details.
+//
+
+import SwiftUI
+import Testing
+
+/// Contains tests cases to check some `Date` extensions utils.
+/// NOTE: Supposed the language of the device / simulator under tests is english
+struct DateTests {
+    @Test(
+        "Get relative time must return the localized expected elapsed time for not cake day and more than one year",
+        .bug("https://github.com/mlemgroup/mlem/issues/2032")
+    )
+    func get_relative_time_returns_localized_string_for_more_than_one_year() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, someDate: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2023-11-14 12:05:00 +0000")!
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        someDate = dateFormatter.date(from: "15/05/2025")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: someDate, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "1 year ago")
+    }
+    
+    @Test("Get relative time must return the elapsed days for accounts of several days old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_days_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-20 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "4 days ago")
+    }
+
+    @Test("Get relative time must return the elapsed weeks for accounts of several weeks old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_weeks_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-01 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-15 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "2 weeks ago")
+    }
+
+    @Test("Get relative time must return the elapsed months for accounts of several months old")
+    func get_relative_time_must_return_elapsed_months_for_accounts_of_several_months_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-12-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "7 months ago")
+    }
+    
+    @Test("Get relative time must return the elapsed hours for accounts younger than one day but older than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_several_hours_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "3 hours ago")
+    }
+
+    @Test("Get relative time must return the elapsed minutes for accounts younger than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_less_one_hour_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "25 minutes ago")
+    }
+
+    @Test("Get relative time must return the elapsed seconds for accounts of some seconds old")
+    func get_relative_time_must_return_elapsed_seconds_for_accounts_of_some_seconds_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:05:42 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "42 seconds ago")
+    }
+    
+    @Test("Date string of some date must be in dd/mm/yyyy format")
+    func date_string_must_be_in_ddmmyyy_format() {
+        // Given
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        let someDate = dateFormatter.date(from: "2023-11-04 10:05:00 +0000")!
+        
+        // When
+        let dateString = someDate.dateString
+        
+        // Then
+        #expect(dateString == "04/11/2023")
+    }
path: MlemTests/DateTests.swift
user: login: Sjmarf
body: This should be removed, right?

```suggestion
```
created_at: 2025-05-16T16:10:11Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,153 @@
+//
+// Software Name: Mlem
+// SPDX-FileCopyrightText: Copyright (c) Mlem Group
+// SPDX-License-Identifier: GPL-3.0
+//
+// This software is distributed under the GNU General Public License v3.0 license,
+// the text of which is available at https://www.gnu.org/licenses/gpl-3.0-standalone.html
+// or see the "LICENSE" file for more details.
+//
+
+import SwiftUI
+import Testing
+
+/// Contains tests cases to check some `Date` extensions utils.
+/// NOTE: Supposed the language of the device / simulator under tests is english
+struct DateTests {
+    @Test(
+        "Get relative time must return the localized expected elapsed time for not cake day and more than one year",
+        .bug("https://github.com/mlemgroup/mlem/issues/2032")
+    )
+    func get_relative_time_returns_localized_string_for_more_than_one_year() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, someDate: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2023-11-14 12:05:00 +0000")!
+        dateFormatter.dateFormat = "dd/MM/yyyy"
+        someDate = dateFormatter.date(from: "15/05/2025")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: someDate, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "1 year ago")
+    }
+    
+    @Test("Get relative time must return the elapsed days for accounts of several days old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_days_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-20 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "4 days ago")
+    }
+
+    @Test("Get relative time must return the elapsed weeks for accounts of several weeks old")
+    func get_relative_time_must_return_elapsed_days_for_accounts_of_several_weeks_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-01 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-15 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "2 weeks ago")
+    }
+
+    @Test("Get relative time must return the elapsed months for accounts of several months old")
+    func get_relative_time_must_return_elapsed_months_for_accounts_of_several_months_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-12-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "7 months ago")
+    }
+    
+    @Test("Get relative time must return the elapsed hours for accounts younger than one day but older than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_several_hours_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 15:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+        
+        // Then
+        #expect(relativeTimeString == "3 hours ago")
+    }
+
+    @Test("Get relative time must return the elapsed minutes for accounts younger than one hour")
+    func get_relative_time_must_return_elapsed_hours_for_accounts_of_less_one_hour_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:30:22 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "25 minutes ago")
+    }
+
+    @Test("Get relative time must return the elapsed seconds for accounts of some seconds old")
+    func get_relative_time_must_return_elapsed_seconds_for_accounts_of_some_seconds_old() {
+        let dateFormatter = DateFormatter()
+        var profileCreationDate: Date, profileCreationDateABitLater: Date
+
+        // Given
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        profileCreationDate = dateFormatter.date(from: "2025-05-16 12:05:00 +0000")!
+        profileCreationDateABitLater = dateFormatter.date(from: "2025-05-16 12:05:42 +0000")!
+        
+        // When
+        let relativeTimeString = profileCreationDate.getRelativeTime(date: profileCreationDateABitLater, unitsStyle: .full)
+
+        // Then
+        #expect(relativeTimeString == "42 seconds ago")
+    }
+    
+    @Test("Date string of some date must be in dd/mm/yyyy format")
+    func date_string_must_be_in_ddmmyyy_format() {
+        // Given
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
+        let someDate = dateFormatter.date(from: "2023-11-04 10:05:00 +0000")!
+        
+        // When
+        let dateString = someDate.dateString
+        
+        // Then
+        #expect(dateString == "04/11/2023")
+    }
path: MlemTests/DateTests.swift
user: login: pylapp
body: I will have a look soon, but yes indeed 
created_at: 2025-05-16T16:11:17Z
author_association: CONTRIBUTOR

PR comments:
user: login: pylapp
created_at: 2025-05-15T11:33:57Z
body: @EricBAndrews @Sjmarf FYI the pull request is ready for review :)
author_association: CONTRIBUTOR
user: login: pylapp
created_at: 2025-05-15T11:44:29Z
body: FYI as usual I only submitted a pull request with cherry-picked commits.
My working branch is [that one](https://github.com/pylapp/mlem/tree/fix/2032-elapsed-time-on-profile), based on my own [dev branch](https://github.com/pylapp/mlem/tree/fix/dev) aligned to [your](https://github.com/mlemgroup/mlem/dev).
It should work on your side :)
author_association: CONTRIBUTOR
user: login: pylapp
created_at: 2025-05-15T12:51:33Z
body: > Thanks. I am at work right now, will give this a more thorough review later. Is this maybe related to [this issue](https://github.com/mlemgroup/mlem/issues/1988)?
> 
> If an account was created less than two years ago, I don't think we should be displaying "2 years ago" in the English version of the app. Rather, I think it would be less confusing to round down and display "1 year ago".
> 
> You mention that it doesn't make sense to display "-1 a" for a 1.5-year-old account in French. I'm curious as to whether we might need to handle this differently for French, in that case? The minus isn't present in the English version - does it have any special meaning?

I cannot say of this is related to issue #1988, but when I compile locally the code with your current *dev* branch (last commit 2712ed77b8da165c37f626fab89694e3cc95c5b6) the issue I spotted is still here :D 

About the "-1 a" case, I would have said that "-1 a" or '-1 y" is not helpful for everybody, and should be extanded to "- 1 an" or "- 1 year", ie. use plain words :) 

I did not change the logic of the formatter ; just helped it to parse the date and return the suitable value.

My case is that one : 
- my account was created at 04/11/2023
- current code base displays "- 1 a", and I suppose it means "less than 1 year", which is not correct
- my fix provides "2 years agos" ; indeed it its better than current solution but not perfect as rounded higher, but this is the behaviour of the formatter (and basically 2023 was 2 years ago)

In a nutshell the current code base provides a too short value which is not correct ; my fix brings longer string with more accurate value.  You can run the code sample I shared in the issue (I used it in a playground) ; with the same date (i.e. 04/11/2023) the formatter returns 2 years, not one, and it seems it fails with dates having hours ([see this thread for exammple](https://stackoverflow.com/questions/71069385/relativedatetimeformatter-says-a-date-from-2-days-ago-is-yesterday))

I use te outputs of the formatter you use ; if you want for example "1.5 years" for a less than two years olds account, the relative parser you call should not be used. In fact, I do not change the logic how the elapsed time is computed ; I fix a misbehavior because of dates the parser cannot process :-D
author_association: CONTRIBUTOR
user: login: pylapp
created_at: 2025-05-16T12:39:20Z
body: @Sjmarf I updated the branch to display the "lower" rounded time as required ;)

I also made some tests about how the string can be computed, and here are my conclusions:
- using `DateComponents` is not enough as if we round them we lose details and computation fails
- the use of `getShortRelativeTime` is interesting however it does not produce the suitable wording (missing "ago" words)
- compute date from rounded date components give a bad object the formater cannot use properly
- so, using the string formatter as I provided (and with the mm/MM fix you spotted) does the job

You can find attached the plaground with my test cases ;)

Feel free to review / amend or merge :D 

[#2032.playground.zip](https://github.com/user-attachments/files/20243965/2032.playground.zip)

author_association: CONTRIBUTOR
user: login: Sjmarf
created_at: 2025-05-16T13:35:41Z
body: Thanks, that's a very thorough investigation :)
author_association: MEMBER
user: login: pylapp
created_at: 2025-05-16T18:53:40Z
body: @Sjmarf I removed the useless unit test and rebased the branch ; now your turn to review again and again (^_^)
author_association: CONTRIBUTOR
user: login: pylapp
created_at: 2025-05-16T18:58:27Z
body: > Nice job! 😄

Thank you a lot for your comments, patience and details!

Just a dumb question for myself as a user: I see in some profiles a kind of green leaf aside green text: what does it mean?

Thank you for this awesome app, I am glad to help 😄
author_association: CONTRIBUTOR
user: login: Sjmarf
created_at: 2025-05-16T19:45:54Z
body: You're welcome, thank _you_ for contributing! I answered the leaf question [here](https://github.com/mlemgroup/mlem/pull/2033#discussion_r2093326265) :)
author_association: MEMBER