Execute copy and set only if something changed

You can do that by using register and when changed.

By using register the result of the copy command is saved into a variable. This variable can then be utilized to create a when conditional in the update timezone task.

Also, make sure to add a line break \n at the end of the timezone content, otherwise Ansible will always perform the copy.

- name: set timezone
  copy: content='Europe/Berlin\n'
        dest=/etc/timezone
        owner=root
        group=root
        mode=0644
        backup=yes
  register: timezone

- name: update timezone
  command: dpkg-reconfigure --frontend noninteractive tzdata
  when: timezone.changed

But you could also solve this problem by creating a handler for the dpkg-reconfigure command as described here :

tasks:
  - name: Set timezone variables
    copy: content='Europe/Berlin\n'
          dest=/etc/timezone
          owner=root
          group=root
          mode=0644
          backup=yes
    notify:
      - update timezone
handlers:
 - name: update timezone
   command: dpkg-reconfigure --frontend noninteractive tzdata

You simply need to register a variable for the copy play, then check to see whether it has changed.

For instance:

- name: make a file
  copy: ...
  register: whatever

- name: run a command
  command: ...
  when: whatever.changed

Depending on the Ubuntu version used using systemd features might also be useful:

- name: Set timezone
  command: timedatectl set-timezone Europe/Berlin
  changed_when: false

To set a timezone with Ansible (>=1.6) on Ubuntu use the locale_gen command.

- name: set timezone
  locale_gen: name=Europe/Berlin state=present

Note: locale_gen is an extras module that currently ships with Ansible. It may be removed in future versions.