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
| Argument | Type | Default | Description |
|---|---|---|---|
utc | bool | false | Return UTC time instead of local time |
fmt | string | None | strftime 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
| Code | Output | Example |
|---|---|---|
%Y | 4-digit year | 2024 |
%m | Zero-padded month | 03 |
%d | Zero-padded day | 07 |
%H | Hour (24-hour) | 14 |
%M | Minute | 30 |
%S | Second | 45 |
%s | Unix epoch | 1709821845 |
%B | Full month name | March |
%A | Full day name | Thursday |
%Z | Timezone name | UTC |
%j | Day of year | 067 |
%U | Week number | 09 |
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
| Feature | now() | ansible_date_time |
|---|---|---|
| When captured | At task evaluation time | During fact gathering |
| Updates during play | Yes | No |
| Requires gather_facts | No | Yes |
| Returns | datetime object or string | Dictionary of strings |
| Supports arithmetic | Yes (without fmt) | No |
| Available since | Ansible 2.8 | Always |
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
Related Articles
- Automating Dynamic Time Date Facts with Ansible
- Mastering Dynamic Variable Creation with set_fact
- Ansible Jinja2 Length Filter Guide
- Schedule a Cron Job with Ansible
- Ansible Magic Variables Reference
- Ansible Debug Module Guide
- Ansible Best Practices Guide
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.