Full reference for Timify’s time entry Server Actions: start, edit, stop, delete, and query entries, plus calculateDuration and formatDuration utilities.
Use this file to discover all available pages before exploring further.
Time entries are the core data unit in Timify — each entry represents a discrete period of tracked work linked to a project. The Server Actions in this section manage the full lifecycle of a time entry: starting a timer, editing metadata, stopping a running timer, and deleting stale records. Two pure utility functions, calculateDuration and formatDuration, are also documented here because they power the duration display logic throughout the application.
import { createTimeEntry } from "@/actions/time-entries/create-time-entry";
Starts a new time entry for a given project. Before inserting, the action finds all currently running entries belonging to the authenticated user, calculates their elapsed duration, and marks them as stopped. This ensures only one timer is active at any time. The new entry is inserted with isRunning: true and a server-side default title and description.
The action atomically stops all other running entries before creating the new one. If an existing running entry has no startTime recorded, it is skipped with a console error rather than causing the whole action to fail.
import { editTimeEntry } from "@/actions/time-entries/edit-time-entry";
Updates the title, description, and time bounds of an existing entry. The action recalculates duration from the provided startTime and endTime before writing to the database — the stored duration value always reflects (endTime - startTime) in whole seconds. If endTime is omitted, duration is calculated as (0 - startTime) which effectively stores a negative value, so always supply endTime when the entry has stopped.
Always pass endTime for entries that are no longer running. Omitting it causes the duration to be stored as a large negative number because the formula uses 0 in place of endTime.getTime().
import { stopTimeEntry } from "@/actions/time-entries/stop-time-entry";
Stops a specific running time entry. The action looks up the entry, confirms isRunning is true, then computes duration = Math.floor((now - startTime) / 1000) and persists isRunning: false, endTime: now, and duration. Returns an error state if the entry is already stopped or if it has no startTime.
import { deleteTimeEntry } from "@/actions/time-entries/delete-time-entry";
Permanently removes a time entry row. Unlike most other actions, deleteTimeEntry accepts a plain string argument rather than FormData — call it directly from a useTransition handler or a Server Action wrapper. The cascade rules on the time_entry_tags table also remove any associated tag relationships automatically.
import { getTimeEntries } from "@/actions/time-entries/get-time-entry";
Fetches all time entries for a given project, with their associated tags eagerly joined. The function uses a left join across time_entry_tags and tags, then reduces the flat result set into an array of entries where each entry’s tags field is a fully hydrated array of tag objects. Results are cached under the get-time-entries tag.
The following functions live in src/lib/calculate-duration.ts. They are not Server Actions — they are pure, synchronous helpers that can be called in both Server Components and Client Components.
Computes elapsed time between a start timestamp and an optional end timestamp. When endTime is omitted, the current moment (new Date()) is used, making it suitable for displaying live running timers.
import { calculateDuration } from "@/lib/calculate-duration";
export function calculateDuration({ startTime, endTime, showFormatted,}: { startTime: Date | null; endTime?: Date | null; showFormatted: boolean;}): string | number
Converts a raw second count into a display string. Shows H:MM:SS format when the duration is one hour or longer, and MM:SS format for sub-hour durations.
import { formatDuration } from "@/lib/calculate-duration";
Use calculateDuration when you have Date objects and want a one-step call. Use formatDuration directly when you already have a stored duration integer from the database — for example, when rendering a completed (non-running) time entry.