Linux
Bash
Programming
Epoch Time
Time Conversion

Get current time in seconds since the Epoch on Linux, Bash

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

On Linux, date +%s prints the current Unix timestamp as the number of whole seconds since 1970-01-01 00:00:00 UTC. This is the standard shell idiom for epoch time and works in Bash, Zsh, Dash, and any POSIX-compatible shell on systems with GNU coreutils.

bash
date +%s
# Output: 1718700000

The rest of this guide covers capturing the value in variables, getting millisecond and nanosecond precision, converting back to human-readable dates, and avoiding common timezone and arithmetic mistakes.

Capture the Timestamp in a Variable

Most scripts need the epoch value stored in a variable, not printed to stdout.

bash
now=$(date +%s)
echo "Script started at epoch: $now"

This is the most common pattern in shell scripts for logging timestamps, generating cache keys, or computing elapsed time.

Measure Elapsed Time

Subtracting two epoch timestamps gives you elapsed seconds without any date string parsing:

bash
1start=$(date +%s)
2
3# ... your work here ...
4sleep 3
5
6end=$(date +%s)
7elapsed=$((end - start))
8echo "Took $elapsed seconds"

This works reliably because epoch seconds are a simple integer. You do not need to handle hours, minutes, or day boundaries. The subtraction is pure arithmetic.

For more readable output on longer durations:

bash
1start=$(date +%s)
2# ... long-running task ...
3end=$(date +%s)
4elapsed=$((end - start))
5
6printf "Duration: %02d:%02d:%02d\n" $((elapsed/3600)) $((elapsed%3600/60)) $((elapsed%60))

Get Milliseconds and Nanoseconds

date +%s gives only whole seconds. When you need finer precision, GNU date supports %N for nanoseconds (9 digits):

bash
1# Nanoseconds since epoch as a single integer string
2date +%s%N
3# Output: 1718700000123456789
4
5# Milliseconds (truncate nanoseconds to 3 digits)
6millis=$(($(date +%s%N) / 1000000))
7echo "$millis"
8
9# Seconds with fractional part
10date +%s.%N
11# Output: 1718700000.123456789

The %s.%N format is useful for benchmarking because it produces a float-like string. However, Bash arithmetic only handles integers, so you will need bc or awk for fractional math:

bash
1start=$(date +%s.%N)
2sleep 1.5
3end=$(date +%s.%N)
4
5elapsed=$(echo "$end - $start" | bc)
6echo "Elapsed: ${elapsed}s"

Convert Epoch Seconds Back to a Date

On GNU/Linux, use date -d @SECONDS to convert an epoch timestamp to a human-readable date:

bash
ts=1718700000
date -d "@$ts"
# Output: Tue Jun 18 12:00:00 UTC 2024

With a custom format:

bash
date -d "@$ts" "+%Y-%m-%d %H:%M:%S %Z"
# Output: 2024-06-18 12:00:00 UTC

On macOS/BSD, the flag is -r instead of -d @:

bash
# macOS/BSD
date -r 1718700000
PlatformConvert Epoch to DateGet Epoch Seconds
GNU/Linuxdate -d @EPOCHdate +%s
macOS/BSDdate -r EPOCHdate +%s
Busyboxdate -d @EPOCHdate +%s

Timezones Do Not Change the Epoch Value

A common misconception is that changing TZ affects the epoch timestamp. It does not. The epoch is always UTC-referenced. Changing TZ only changes how the date is displayed.

bash
1TZ="UTC" date +%s
2# 1718700000
3
4TZ="America/New_York" date +%s
5# 1718700000  (same value)
6
7TZ="Asia/Tokyo" date +%s
8# 1718700000  (same value)

The displayed date differs, but the epoch value is identical because it represents the same absolute moment in time. This is exactly why epoch timestamps are useful for logging and storage: they are timezone-independent.

Using Epoch Time in Practical Scripts

Log Rotation

bash
1#!/usr/bin/env bash
2LOG_DIR="/var/log/myapp"
3CUTOFF=$(($(date +%s) - 86400 * 30))  # 30 days ago
4
5for f in "$LOG_DIR"/*.log; do
6  file_epoch=$(date -r "$f" +%s)
7  if [ "$file_epoch" -lt "$CUTOFF" ]; then
8    rm "$f"
9    echo "Deleted: $f"
10  fi
11done

Simple Rate Limiting

bash
1LAST_RUN_FILE="/tmp/last_run_epoch"
2
3now=$(date +%s)
4if [ -f "$LAST_RUN_FILE" ]; then
5  last=$(cat "$LAST_RUN_FILE")
6  diff=$((now - last))
7  if [ "$diff" -lt 60 ]; then
8    echo "Rate limited. Wait $((60 - diff)) seconds."
9    exit 1
10  fi
11fi
12
13echo "$now" > "$LAST_RUN_FILE"
14# ... proceed with the task ...

Cache Expiration

bash
1CACHE_FILE="/tmp/api_cache.json"
2MAX_AGE=300  # 5 minutes
3
4if [ -f "$CACHE_FILE" ]; then
5  cached_at=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE")
6  now=$(date +%s)
7  age=$((now - cached_at))
8  if [ "$age" -lt "$MAX_AGE" ]; then
9    echo "Using cached response (age: ${age}s)"
10    cat "$CACHE_FILE"
11    exit 0
12  fi
13fi
14
15curl -s https://api.example.com/data > "$CACHE_FILE"
16cat "$CACHE_FILE"

Other Ways to Get Epoch Time

Bash Built-in EPOCHSECONDS (Bash 5.0+)

Bash 5.0 introduced a built-in variable that avoids the overhead of forking a date process:

bash
1echo "$EPOCHSECONDS"
2# Output: 1718700000
3
4echo "$EPOCHREALTIME"
5# Output: 1718700000.123456 (microsecond precision)

These are faster than $(date +%s) in tight loops because no subprocess is created.

Python One-Liner

bash
python3 -c "import time; print(int(time.time()))"

Perl One-Liner

bash
perl -e 'print time, "\n"'

Common Pitfalls

Assuming date +%s returns milliseconds instead of seconds is the most frequent mistake. The value is always whole seconds. For milliseconds, you need date +%s%N with division.

Forgetting to quote command substitutions can cause subtle bugs in larger scripts. Always write "$(date +%s)" in conditionals and assignments.

Mixing human-readable timestamps and epoch values in the same variable or log field makes debugging harder. Pick one format per field and convert only when displaying.

Expecting timezone changes to alter the epoch value confuses display formatting with absolute time. date +%s always returns UTC-based seconds regardless of TZ.

Using %N on macOS fails silently because the BSD date command does not support nanoseconds. Use gdate (GNU date via Homebrew) or python3 for sub-second precision on macOS.

Using second-precision timing for benchmarks that need microsecond accuracy produces misleading data. Use $EPOCHREALTIME or date +%s.%N with bc for high-resolution timing.

Summary

  • date +%s returns current time in whole seconds since the Unix epoch.
  • Capture it with now=$(date +%s) and subtract two values for elapsed time.
  • Use date +%s%N for nanosecond precision; divide by 1,000,000 for milliseconds.
  • Convert back with date -d @EPOCH on GNU/Linux or date -r EPOCH on macOS.
  • Epoch timestamps are timezone-independent; TZ only affects display formatting.
  • On Bash 5.0+, use $EPOCHSECONDS or $EPOCHREALTIME to avoid subprocess overhead.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.