Timezones and DST in Python

It’s incredible how fiddly it is to work with timezones.

Today, 14th of June—and this is important—I was trying to convert a made-up datetime from “Europe/London” to UTC.

I instinctively tried out this:
>>> almostMidnight = datetime.now().replace(hour=23, minute=59, second=59, microsecond=999999, tzinfo=pytz.timezone('Europe/London'))
>>> almostMidnight
datetime.datetime(2017, 6, 14, 23, 59, 59, 999999, tzinfo=<DstTzInfo 'Europe/London' GMT0:00:00 STD>)

At this point you will notice it didn’t take into account the DST offset (it should read BST).

As a further confirmation, converting to UTC keeps the same time:
>>> pytz.UTC.normalize(almostMidnight)
datetime.datetime(2017, 6, 14, 23, 59, 59, 999999, tzinfo=<UTC>)

Notice this result would be fine during the winter, so depending how much attention you devote and when you write the code you might miss out on this bug – which is why I love having the same suite of tests always running on a system that lives right after the upcoming DST change.

Even more subtler, if you were to try and convert to a different timezone, a geographical timezone that observes DST, you would see this:
>>> almostMidnight.astimezone(pytz.timezone('Europe/Rome'))
datetime.datetime(2017, 6, 15, 1, 59, 59, 999999, tzinfo=<DstTzInfo 'Europe/Rome' CEST+2:00:00 DST>)

Interesting. Now DST is accounted for. So converting to geographical timezones might also mask the problem.

Long story short, the correct way *I believe* to convert the timezone of a datetime object to UTC is to create a naive datetime object (no timezone info attached) representing localtime, and then call the “localize” of the timezone of interest. In code:
>>> almostMidnight = datetime.now().replace(hour=23, minute=59, second=59, microsecond=999999)
>>> almostMidnight
datetime.datetime(2017, 6, 14, 23, 59, 59, 999999)
>>> pytz.timezone('Europe/London').localize(almostMidnight).astimezone(pytz.UTC)
datetime.datetime(2017, 6, 14, 22, 59, 59, 999999, tzinfo=<UTC>)

There’s a very nice read on timezones by Armin Ronacher, which I recommend.


Nosetests and the docstrings

For some reason when you use the -v switch in nosetests, instead of using the test name, the runner uses the docstring (and only first line, for that matter).

Solution: install the “nose-ignore-docstring” plugin:
sudo easy_install nose-ignore-docstring
and then enable it by adding:

to ~/.noserc

For additional information, I’ll point you to the plugin web page on PyPy.

PowerShell and vSphere

In the last post I showed very quickly how you can use PowerShell to connect to a vSphere server and change the NIC for a VM.

Today I was faced with another problem. As I discovered, much to my horror, that the %windir%\winsxs folder was taking up a good amount of the space on the HD and that you should not delete anything in there and that resistance is futile but the occupied disk can be (a little) reduced.

The only alternative was to increase the size of the HD. When trying to do it manually, I got this error:

Error on eor-bts-prebv:Permission to perform this operation was denied.
You do not hold privilege “Virtual machine > Configuration > Change resource” on virtual machine “myVM”
Error Stack
Call “VirtualMachine.Reconfigure” for object “myVM” on vCenter Server “vCenter” failed.

So I gave a go to PowerShell. After connecting (see the previous post), I:

  1. Got hold of my VM: $myvm = Get-VM -Name "myVM"
  2. Looked at the HDs, and retrieved ID and capacity: Get-HardDisk -VM $myvm | % {$_.Id, $_.CapacityGB}
  3. Grabbed the HD of interest: $hd = Get-HardDisk -vm $myvm -Id "VirtualMachine-vm-2767/2000"
  4. Set the capacity to 20 GB: Set-HardDisk -HardDisk $hd -CapacityGB 20

Needless to say, it worked like a charm.

PowerShell and vSphere

There is a PowerShell snap-in (a mechanism to add new cmdlets, I’ll try and write something more about modules, snap-ins etc in the future) which is quite useful – and sometimes vital – to manage virtual machines in vSphere. To add it to the shell you just need to issue Add-PSSnapin VMware.VimAutomation.Core

If all goes well you can now connect to the vCenter server, that is: Connect-VIServer $VcenterHostname

At this point is quite easy to get the list of all VMs currently present on the server: Get-VM (told you it was easy :). If you specify a machine name, then obviously you’ll get that VM.

With the VM, you will be able to perform tasks, such as changing the network adapter – which, incidentally, you cannot do via the vSphere client. For instance, to change the adapter from E1000 to Vmxnet3, just type:  Get-VM myVM | Get-NetworkAdapter | Set-NetworkAdapter -Type "vmxnet3"

A popup will appear, asking if you want to continue. Notice that the previous command assumes you only have one NIC. If two or more NICs are present on the VM you’ll have to specify a properly crafted Where-Object clause after Get-NetworkAdapter (Get-Member is your friend!)