[GH-ISSUE #8567] [FR] Add relative date format ('2 days ago', 'in 3 hours') for date fields #3912

Open
opened 2026-03-23 21:34:06 +00:00 by mirror · 0 comments
Owner

Originally created by @diegodurs on GitHub (Mar 12, 2026).
Original GitHub issue: https://github.com/AppFlowy-IO/AppFlowy/issues/8567

Description

Add a Relative date format option to date/datetime fields that displays timestamps as human-readable relative time (e.g., "2 days ago", "in 3 hours", "just now") instead of absolute dates.

This is useful for task management, project tracking, and any workflow where recency matters more than the exact date — similar to how GitHub, Slack, and most modern tools display timestamps.

Current behavior

Date fields support 6 absolute format variants:

Variant Example
Local 03/12/2026
US 2026/03/12
ISO 2026-03-12
Friendly Mar 12, 2026
DayMonthYear 12/03/2026
FriendlyFull March 12, 2026

There is no option to display dates relative to the current time.

Proposed behavior

Add a new DateFormat::Relative variant (value 6) that renders timestamps as:

  • < 1 minute: "just now"
  • < 1 hour: "X minutes ago" / "in X minutes"
  • < 1 day: "X hours ago" / "in X hours"
  • < 1 week: "X days ago" / "in X days"
  • < 1 month: "X weeks ago" / "in X weeks"
  • < 1 year: "X months ago" / "in X months"
  • ≥ 1 year: "X years ago" / "in X years"

The exact timestamp should still be visible on hover (tooltip).

Implementation plan

This is a full-stack feature touching 3 repositories:

1. AppFlowy-Collab (Rust — source of truth)

  • File: collab-database/src/fields/type_option/date_type_option.rs
  • Add Relative = 6 to the DateFormat enum
  • Update From<i64> conversion
  • Special-case format_str() — relative dates can't use a static chrono format string, so stringify_cell / formatted_date_time_from_timestamp need to compute the diff against chrono::Utc::now() (or local time with timezone offset)
  • Use chrono::Duration for the delta calculation

2. AppFlowy (Flutter + Rust)

  • Rust adapter (frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/): Update protobuf DateFormatPB enum, handle the new variant in formatting logic
  • Flutter UI (frontend/appflowy_flutter/lib/workspace/application/settings/date_time/date_format_ext.dart): Add display name for the format ("Relative")
  • Format selector (frontend/appflowy_flutter/lib/plugins/database/widgets/field/type_option_editor/date/date_time_format.dart): Include in the dropdown
  • Cell rendering: Periodic refresh needed — cells must re-render as time passes (e.g., "5 minutes ago" → "6 minutes ago"). A timer-based approach or StreamBuilder with periodic ticks would work.

3. AppFlowy-Web (React/TypeScript)

  • Types (src/application/types.ts): Add Relative = 6 to the DateFormat enum
  • Formatting (src/utils/time.ts): Add dayjs relativeTime plugin, update getDateFormat() / renderDate() to use dayjs().to(timestamp) when format is Relative
  • Cell component (src/components/database/components/cell/date/DateTimeCell.tsx): Add tooltip showing absolute date, periodic re-render via useEffect + interval
  • Format selector (src/components/database/components/property/date/DateTimeFormatGroup.tsx): Add "Relative" option to the dropdown

Key design considerations

  1. Re-rendering: Relative timestamps go stale. Cells using this format need periodic refresh (suggested: every 60 seconds for cells showing minutes, less frequently for hours/days)
  2. Sorting: Should still sort by the underlying timestamp, not the display string
  3. Filtering: No change needed — filters operate on raw timestamps
  4. Date ranges: For range fields (start → end), both dates should render as relative. E.g., "3 days ago → in 2 days"
  5. Tooltip: Always show the absolute date/time on hover for precision
  6. i18n: The relative strings ("ago", "in", "minutes", etc.) need to be localized. dayjs and chrono-humanize both support this.
  7. Export/copy: When copying a relative date cell, the absolute date should be copied (not "2 days ago")

Impact

Anyone using AppFlowy for task management, project tracking, CRM, or content calendars — where knowing "this was 3 days ago" is more useful than "this was March 9, 2026".

Additional context

  • Related but distinct from #5666 (custom format strings) and #7972 (relative date filtering)
  • dayjs (already used in AppFlowy-Web) has a relativeTime plugin that handles this well
  • For Rust, the chrono-humanize crate provides similar functionality
  • For Flutter, the timeago package is a mature solution

I'm willing to contribute this feature. Happy to start with a PR to AppFlowy-Collab + AppFlowy-Web as a first pass.

Originally created by @diegodurs on GitHub (Mar 12, 2026). Original GitHub issue: https://github.com/AppFlowy-IO/AppFlowy/issues/8567 ### Description Add a **Relative** date format option to date/datetime fields that displays timestamps as human-readable relative time (e.g., "2 days ago", "in 3 hours", "just now") instead of absolute dates. This is useful for task management, project tracking, and any workflow where **recency matters more than the exact date** — similar to how GitHub, Slack, and most modern tools display timestamps. ### Current behavior Date fields support 6 absolute format variants: | Variant | Example | |---------|---------| | Local | 03/12/2026 | | US | 2026/03/12 | | ISO | 2026-03-12 | | Friendly | Mar 12, 2026 | | DayMonthYear | 12/03/2026 | | FriendlyFull | March 12, 2026 | There is no option to display dates relative to the current time. ### Proposed behavior Add a new `DateFormat::Relative` variant (value `6`) that renders timestamps as: - **< 1 minute**: "just now" - **< 1 hour**: "X minutes ago" / "in X minutes" - **< 1 day**: "X hours ago" / "in X hours" - **< 1 week**: "X days ago" / "in X days" - **< 1 month**: "X weeks ago" / "in X weeks" - **< 1 year**: "X months ago" / "in X months" - **≥ 1 year**: "X years ago" / "in X years" The exact timestamp should still be visible on hover (tooltip). ### Implementation plan This is a full-stack feature touching 3 repositories: #### 1. AppFlowy-Collab (Rust — source of truth) - **File**: `collab-database/src/fields/type_option/date_type_option.rs` - Add `Relative = 6` to the `DateFormat` enum - Update `From<i64>` conversion - Special-case `format_str()` — relative dates can't use a static chrono format string, so `stringify_cell` / `formatted_date_time_from_timestamp` need to compute the diff against `chrono::Utc::now()` (or local time with timezone offset) - Use `chrono::Duration` for the delta calculation #### 2. AppFlowy (Flutter + Rust) - **Rust adapter** (`frontend/rust-lib/flowy-database2/src/services/field/type_options/date_type_option/`): Update protobuf `DateFormatPB` enum, handle the new variant in formatting logic - **Flutter UI** (`frontend/appflowy_flutter/lib/workspace/application/settings/date_time/date_format_ext.dart`): Add display name for the format ("Relative") - **Format selector** (`frontend/appflowy_flutter/lib/plugins/database/widgets/field/type_option_editor/date/date_time_format.dart`): Include in the dropdown - **Cell rendering**: Periodic refresh needed — cells must re-render as time passes (e.g., "5 minutes ago" → "6 minutes ago"). A timer-based approach or `StreamBuilder` with periodic ticks would work. #### 3. AppFlowy-Web (React/TypeScript) - **Types** (`src/application/types.ts`): Add `Relative = 6` to the `DateFormat` enum - **Formatting** (`src/utils/time.ts`): Add `dayjs` `relativeTime` plugin, update `getDateFormat()` / `renderDate()` to use `dayjs().to(timestamp)` when format is Relative - **Cell component** (`src/components/database/components/cell/date/DateTimeCell.tsx`): Add tooltip showing absolute date, periodic re-render via `useEffect` + interval - **Format selector** (`src/components/database/components/property/date/DateTimeFormatGroup.tsx`): Add "Relative" option to the dropdown ### Key design considerations 1. **Re-rendering**: Relative timestamps go stale. Cells using this format need periodic refresh (suggested: every 60 seconds for cells showing minutes, less frequently for hours/days) 2. **Sorting**: Should still sort by the underlying timestamp, not the display string 3. **Filtering**: No change needed — filters operate on raw timestamps 4. **Date ranges**: For range fields (start → end), both dates should render as relative. E.g., "3 days ago → in 2 days" 5. **Tooltip**: Always show the absolute date/time on hover for precision 6. **i18n**: The relative strings ("ago", "in", "minutes", etc.) need to be localized. `dayjs` and `chrono-humanize` both support this. 7. **Export/copy**: When copying a relative date cell, the absolute date should be copied (not "2 days ago") ### Impact Anyone using AppFlowy for task management, project tracking, CRM, or content calendars — where knowing "this was 3 days ago" is more useful than "this was March 9, 2026". ### Additional context - Related but distinct from #5666 (custom format strings) and #7972 (relative date filtering) - `dayjs` (already used in AppFlowy-Web) has a [`relativeTime`](https://day.js.org/docs/en/plugin/relative-time) plugin that handles this well - For Rust, the [`chrono-humanize`](https://crates.io/crates/chrono-humanize) crate provides similar functionality - For Flutter, the [`timeago`](https://pub.dev/packages/timeago) package is a mature solution I'm willing to contribute this feature. Happy to start with a PR to AppFlowy-Collab + AppFlowy-Web as a first pass.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
AppFlowy-IO/AppFlowy#3912
No description provided.