Introduction

The now() function, introduced in Ansible 2.8, gives you access to the current date and time directly inside Jinja2 templates. Unlike ansible_date_time facts (which are captured once during fact gathering), now() evaluates at the moment the task runs — making it ideal for accurate timestamps in deployments, log files, and time-based logic.

Syntax and Arguments

{{ now() }}                              # Full datetime object (local time)
{{ now(utc=true) }}                      # Full datetime object (UTC)
{{ now(fmt='%Y-%m-%d') }}               # Formatted string
{{ now(utc=true, fmt='%Y-%m-%d %H:%M') }}  # UTC formatted string
ArgumentTypeDefaultDescription
utcboolfalseReturn UTC time instead of local time
fmtstringNonestrftime format string. If omitted, returns a Python datetime object

When fmt is provided, now() returns a string. Without fmt, it returns a datetime object that supports arithmetic operations.

Common strftime Format Codes

CodeOutputExample
%Y4-digit year2024
%mZero-padded month03
%dZero-padded day07
%HHour (24-hour)14
%MMinute30
%SSecond45
%sUnix epoch1709821845
%BFull month nameMarch
%AFull day nameThursday
%ZTimezone nameUTC
%jDay of year067
%UWeek number09

Practical Examples

Timestamped Backup Directories

- name: Create timestamped backup
  hosts: all
  tasks:
    - name: Set backup directory name
      ansible.builtin.set_fact:
        backup_dir: "/backups/{{ now(utc=true, fmt='%Y%m%d_%H%M%S') }}"

    - name: Create backup directory
      ansible.builtin.file:
        path: "{{ backup_dir }}"
        state: directory
        mode: '0755'

    - name: Archive configuration
      ansible.builtin.archive:
        path: /etc/myapp/
        dest: "{{ backup_dir }}/config.tar.gz"

Deployment Metadata

- name: Write deployment info
  ansible.builtin.copy:
    content: |
      ---
      deployed_at: "{{ now(utc=true, fmt='%Y-%m-%dT%H:%M:%SZ') }}"
      deployed_by: "{{ ansible_user_id }}"
      version: "{{ app_version }}"
      environment: "{{ env }}"
    dest: /opt/app/DEPLOY_INFO.yml
    mode: '0644'

Log File Naming

- name: Run migration with timestamped log
  ansible.builtin.shell: |
    /opt/app/migrate.sh 2>&1 | tee /var/log/migrations/migrate-{{ now(fmt='%Y%m%d-%H%M%S') }}.log
  args:
    creates: /opt/app/.migration-complete

Conditional Execution Based on Time

Run tasks only during maintenance windows:

- name: Check if within maintenance window (22:00-06:00 UTC)
  ansible.builtin.set_fact:
    current_hour: "{{ now(utc=true, fmt='%H') | int }}"

- name: Run maintenance tasks
  ansible.builtin.include_tasks: maintenance.yml
  when: current_hour | int >= 22 or current_hour | int < 6

Day-of-Week Scheduling

- name: Run weekly report on Fridays
  ansible.builtin.script: /opt/scripts/weekly-report.sh
  when: now(fmt='%A') == 'Friday'

Calculating Uptime

Combine now() with ansible_uptime_seconds to display human-readable uptime:

- name: Show host uptime
  ansible.builtin.debug:
    msg: >-
      Uptime: {{ now().replace(microsecond=0) - 
      now().fromtimestamp(now(fmt='%s') | int - ansible_uptime_seconds) }}

This subtracts the boot timestamp from the current time, producing output like Uptime: 14 days, 3:42:15.

Date Arithmetic

Since now() without fmt returns a datetime object, you can perform arithmetic:

- name: Calculate future dates
  ansible.builtin.set_fact:
    # Current epoch + 7 days
    expiry_epoch: "{{ now(fmt='%s') | int + (7 * 86400) }}"

- name: Format expiry date
  ansible.builtin.set_fact:
    expiry_date: "{{ '%Y-%m-%d' | strftime(expiry_epoch | int) }}"

- name: Set certificate expiry
  ansible.builtin.debug:
    msg: "Certificate expires: {{ expiry_date }}"

Comparing Timestamps

- name: Check if file is older than 24 hours
  ansible.builtin.stat:
    path: /tmp/cache.json
  register: cache_stat

- name: Rebuild cache if stale
  ansible.builtin.command: /opt/rebuild-cache.sh
  when: >
    not cache_stat.stat.exists or
    (now(fmt='%s') | int - cache_stat.stat.mtime | int) > 86400

now() vs ansible_date_time

Featurenow()ansible_date_time
When capturedAt task evaluation timeDuring fact gathering
Updates during playYesNo
Requires gather_factsNoYes
Returnsdatetime object or stringDictionary of strings
Supports arithmeticYes (without fmt)No
Available sinceAnsible 2.8Always

When to use ansible_date_time: Simple date references where precision doesn't matter.

When to use now(): Timestamps that must reflect actual execution time — deployments, logs, calculations.

now() vs pipe Lookup

# now() — runs on control node, Jinja2-native
deploy_time: "{{ now(utc=true, fmt='%Y-%m-%d %H:%M:%S') }}"

# pipe lookup — runs system date command on control node
deploy_time: "{{ lookup('pipe', 'date -u +%Y-%m-%d\\ %H:%M:%S') }}"

Use now() for standard formatting. Use pipe lookup when you need system-specific date features like date -d "next Monday".

Timezone Handling

now() returns local time by default. For UTC:

- name: Show both local and UTC time
  ansible.builtin.debug:
    msg:
      local: "{{ now(fmt='%Y-%m-%d %H:%M:%S %Z') }}"
      utc: "{{ now(utc=true, fmt='%Y-%m-%d %H:%M:%S %Z') }}"

For specific timezones, use the pipe lookup:

- name: Get time in specific timezone
  ansible.builtin.set_fact:
    tokyo_time: "{{ lookup('pipe', 'TZ=Asia/Tokyo date +%Y-%m-%d\\ %H:%M:%S') }}"
    new_york_time: "{{ lookup('pipe', 'TZ=America/New_York date +%Y-%m-%d\\ %H:%M:%S') }}"

Common Patterns

Rotate Log Files by Date

- name: Rotate application logs
  ansible.builtin.command:
    cmd: "mv /var/log/app.log /var/log/app.log.{{ now(fmt='%Y%m%d') }}"
  args:
    removes: /var/log/app.log

Tag Resources with Timestamps

- name: Create AWS snapshot with timestamp
  amazon.aws.ec2_snapshot:
    volume_id: "{{ vol_id }}"
    description: "Backup {{ now(utc=true, fmt='%Y-%m-%dT%H:%M:%SZ') }}"
    snapshot_tags:
      Created: "{{ now(utc=true, fmt='%Y-%m-%d') }}"
      CreatedBy: "ansible"

Idempotent Daily Tasks

- name: Run daily task only once per day
  ansible.builtin.command: /opt/daily-job.sh
  args:
    creates: "/var/run/daily-job-{{ now(fmt='%Y-%m-%d') }}.done"

- name: Mark daily task complete
  ansible.builtin.file:
    path: "/var/run/daily-job-{{ now(fmt='%Y-%m-%d') }}.done"
    state: touch

Conclusion

The now() function is Ansible's most flexible tool for working with dates and times. It evaluates at task execution time (unlike ansible_date_time), supports both datetime objects and formatted strings, and enables arithmetic for calculations like expiry dates and uptime. For any playbook that needs accurate timestamps — deployments, backups, logs, or time-based scheduling — now() is the right choice.