27
votes

How to Correct Timezone

Last time, I figured out how to adjust a system clock in vagrant server. However, when I halt the vagrant and start it again, the system clock is always 9 hours late. I can adjust by using ntp command manually, but I'd like to know how to adjust the system clock automatically.

I have tried the below, but it still doesn't work. Are there any suggestions?

How to sync time on host wake-up within VirtualBox?

9

9 Answers

42
votes

The method I use and it should not be provider specific is to add the following in my Vagrantfile

  config.vm.provision :shell, :inline => "sudo rm /etc/localtime && sudo ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime", run: "always"

you would need to replace '/Europe/Paris' with the timezone you want to set

10
votes

Accepted answer is not robust enough, as it does not account for people who travel between timezones, and requires end users to modify Vagrantfile instead of just doing vagrant up.

Building up on Scott P.'s answer, here's a better more flexible solution that matches VM timezone to host's tz automatically. There's a typo/mistake in his snippet's Etc/GMT time zone selection, as per POSIX GMT+7 sets clock 7 hours behind (see Wiki explanation), hence we need to swap offsets:

Vagrant.configure("2") do |config|
require 'time'
offset = ((Time.zone_offset(Time.now.zone) / 60) / 60)
timezone_suffix = offset >= 0 ? "-#{offset.to_s}" : "+#{offset.to_s}"
timezone = 'Etc/GMT' + timezone_suffix
config.vm.provision :shell, :inline => "sudo rm /etc/localtime && sudo ln -s /usr/share/zoneinfo/" + timezone + " /etc/localtime", run: "always"
end
9
votes

The simplest way is to set the timezone automatically is to use the vagrant-timezone plugin.

Install the vagrant-timezone plugin with

vagrant plugin install vagrant-timezone

After that, add the below to your Vagrantfile

if Vagrant.has_plugin?("vagrant-timezone")
    config.timezone.value = "UTC"
end

You may replace "UTC" with any of the tz values listed here. For example: "Asia/Kolkata".

4
votes

A slightly improved version that auto-detects timezone:

The auto-detect portion came from here.

Vagrant.configure("2") do |config|
  require 'time'
  offset = ((Time.zone_offset(Time.now.zone) / 60) / 60)
  timezone_suffix = offset >= 0 ? "+#{offset.to_s}" : "#{offset.to_s}"
  timezone = 'Etc/GMT' + timezone_suffix
  config.vm.provision :shell, :inline => "sudo rm /etc/localtime && sudo ln -s /usr/share/zoneinfo/" + timezone + " /etc/localtime", run: "always"
end
4
votes

I got:

[vagrant@ansiblecontrol ~]$ date -s \"$(curl -I google.com 2>&1 | grep Date: | cut -d' ' -f3-6)Z\"
date: extra operand ‘2018’
Try 'date --help' for more information.

This works for me:

sudo date -s "$(curl -I google.com 2>&1 | grep Date: | cut -d' ' -f3-6)Z"
Sun Apr  1 16:36:59 CEST 2018

So removed the "\" escape character.

3
votes

My Vagrant Guest OS time was out of sync by 7 days. The above methods did not work for me, since Guest additions and ntp were not installed in my Guest machine.

I finally solved the issue by using the hack from https://askubuntu.com/a/683136/119371

cfg.vm.provision "shell", inline: "date -s \"$(wget -qSO- --max-redirect=0 google.com 2>&1 | grep Date: | cut -d' ' -f5-8)Z\"", run: "always", privileged: true, upload_path: "/home/vagrant/tmp/vagrant-shell"

The above method does not sync the Guest OS time with your host machine or any NTP server. It sends an HTTP request to google.com and updates the system time with the time in the HTTP response header field.

Hence, depending on your internet connection speed and latency, the updated time could be off by several milliseconds to a few seconds (usually < 100ms). But it shouldn't matter for most cases.

Following is the curl version, if you don't want to use wget for any reason

cfg.vm.provision "shell", inline: "date -s \"$(curl -I google.com 2>&1 | grep Date: | cut -d' ' -f3-6)Z\""
2
votes

@Benny K and @Scott P.'s solution giving me the negative value of a timezone, like in @rubo77's case. Worth to note that my host OS is Windows. If timedatectl is present on your guests (like Debian 9+), this is what I used to change timezone settings:

config.vm.provision "shell",
    inline: "timedatectl set-timezone Europe/Budapest",
    run: "always" 

This one returns the expected timezone, not the negative value:

# before timedatectl
vagrant@master:~$ timedatectl
               Local time: Fri 2020-07-03 11:52:31 -02
           Universal time: Fri 2020-07-03 13:52:31 UTC
                 RTC time: Fri 2020-07-03 13:52:31
                Time zone: Etc/GMT+2 (-02, -0200)
System clock synchronized: no
              NTP service: inactive
          RTC in local TZ: no

# after timedatectl
vagrant@master:~$ timedatectl
               Local time: Fri 2020-07-03 15:53:24 CEST
           Universal time: Fri 2020-07-03 13:53:24 UTC
                 RTC time: Fri 2020-07-03 13:53:24
                Time zone: Europe/Budapest (CEST, +0200)
System clock synchronized: no
              NTP service: inactive
          RTC in local TZ: no
1
votes

Based on @Benny K.'s answer (https://stackoverflow.com/a/46778032/3194807), with the daylight saving time taken into account:

require "time"
offset = ((Time.zone_offset(Time.now.zone) / 60) / 60) + (Time.now.dst? ? 1 : 0)
timezone_suffix = offset >= 0 ? "-#{offset.to_s}" : "+#{offset.to_s}"
timezone = 'Etc/GMT' + timezone_suffix

tzShellProvision = <<_SHELL_
    ln -fs /usr/share/zoneinfo/#{timezone} /etc/localtime
    dpkg-reconfigure -f noninteractive tzdata
_SHELL_

default.vm.provision :shell, inline: tzShellProvision, run: "always"
0
votes

The way is to set the timezone automatically same like host using the vagrant-timezone plugin.

Install the vagrant-timezone plugin with

vagrant plugin install vagrant-timezone

After that, add the below to your Vagrantfile

config.timezone.value = :host

Note that this functionality has only been tested with an OS X host and Linux guest.