Duncan's blog

November 17, 2017

JS dates British Summer Time oddness

Filed under: Javascript — duncan @ 7:00 am
Tags: ,

This must be widely documented, but I came across it today and got a bit perplexed by it. I’m sure I must have encountered this in the past, but probably a long while ago.

I was working with some date pickers and comparing the number of months between two dates and getting unexpected results. Say you do this:

date = new Date(2017, 3, 1);

You’d expect it to create a date object for the 1st April. April Fool’s! Instead it seems to create a date for the 31st March, 23:00. Here’s what I get in my browser console:

new Date(2017, 3, 1);
Date 2017-03-31T23:00:00.000Z

If I specify an additional parameter for the hours, and go for 1am, then this gives me the correct date, but with the time set to 00:00, not 01:00:

new Date(2017, 3, 1, 1)
Date 2017-04-01T00:00:00.000Z

Let’s try the same thing with the 2nd April, same problem. It seems to be subtracting 1hr from whatever DateTime I’m creating:

new Date(2017, 3, 2)
Date 2017-04-01T23:00:00.000Z

new Date(2017, 3, 2, 1)
Date 2017-04-02T00:00:00.000Z

Let’s try all the months of the year:

new Date(2017, 0, 1)
Date 2017-01-01T00:00:00.000Z

new Date(2017, 1, 1)
Date 2017-02-01T00:00:00.000Z

new Date(2017, 2, 1)
Date 2017-03-01T00:00:00.000Z

new Date(2017, 3, 1)
Date 2017-03-31T23:00:00.000Z

new Date(2017, 4, 1)
Date 2017-04-30T23:00:00.000Z

new Date(2017, 5, 1)
Date 2017-05-31T23:00:00.000Z

new Date(2017, 6, 1)
Date 2017-06-30T23:00:00.000Z

new Date(2017, 7, 1)
Date 2017-07-31T23:00:00.000Z

new Date(2017, 8, 1)
Date 2017-08-31T23:00:00.000Z

new Date(2017, 9, 1)
Date 2017-09-30T23:00:00.000Z

new Date(2017, 10, 1)
Date 2017-11-01T00:00:00.000Z

new Date(2017, 11, 1)
Date 2017-12-01T00:00:00.000Z

So we can see it’s clearly doing this for any month from April to October, inclusive. i.e. British Summer Time months. It’s not a bug as such, but just added complication to take into account when working with dates.

If we turn the date into a string, it becomes a bit clearer what’s going on, it’s converting the time into British Summer Time, i.e. GMT + 1 (your results may vary depending on your local timezone):

new Date(2017, 3, 1).toString();
"Sat Apr 01 2017 00:00:00 GMT+0100 (GMT Daylight Time)"

More specifically, the BST dates this year start 26th March and end 29th October. If we check those dates at either end of the range, we can see it’s only doing this on the dates just at the edges of that range:

new Date(2017, 2, 25)
Date 2017-03-25T00:00:00.000Z

new Date(2017, 2, 26)
Date 2017-03-26T00:00:00.000Z

new Date(2017, 2, 27)
Date 2017-03-26T23:00:00.000Z

And:

new Date(2017, 9, 28)
Date 2017-10-27T23:00:00.000Z

new Date(2017, 9, 29)
Date 2017-10-28T23:00:00.000Z

new Date(2017, 9, 30)
Date 2017-10-30T00:00:00.000Z

So in other words it’s creating me a time at BST 2017-04-01 00:00:00, but in UTC that’s 2017-03-31 23:00:00. So any Date functions we call on it like getUTCMonth could potentially give us a different value from getMonth:

new Date(2017, 3, 1).getUTCMonth()
2

new Date(2017, 3, 1).getMonth()
3

To get around this, you could just add 1 hr to any date you’re creating, either in the constructor, or with the setHours method:

date = new Date(2017, 3, 1);
date.setHours(1);

Taking care that this doesn’t mess up anything else of course.

A better approach would be, instead of just using the Date() constructor, to use it in combination with the Date.UTC() method. This gets us a value in milliseconds without reference to the local timezone.

new Date(Date.UTC(2017, 3, 1))
Date 2017-04-01T00:00:00.000Z

As the MDN documentation states:

“Note: Where Date is called as a constructor with more than one argument, the specifed arguments represent local time. If UTC is desired, use new Date(Date.UTC(…)) with the same arguments.”

Someone I work with seemed to think I’d just got confused by the fact Javascript uses zero-indexed months!

Advertisements

November 16, 2017

PHPUnit @usesDefaultClass

Filed under: PHP — duncan @ 7:11 pm
Tags: , ,

When writing unit tests for PHPUnit, you can specify a @covers annotation to indicate what function or functions a unit test is for. This can be useful to correctly identify what you’re testing, if it’s not immediately obvious from the function itself.

A while ago we used to specify the full namespace of whatever class we were testing, e.g.

class StaffServiceTest extends TestCase
{
    /** @covers \projectName\services\staff\StaffService::getStaff */
    public function testGetStaff() {...}

    /** @covers \projectName\services\staff\StaffService::addStaff */
    public function testAddStaff() {...}
}

etc.

Then realised there’s a @coversDefaultClass attribute you can specify to your test class itself. Using this means you don’t need to then repeat that path with every @covers annotation:

/** @coversDefaultClass \projectName\services\staff\StaffService */
class StaffServiceTest extends TestCase
{
    /** @covers ::getStaff */
    public function testGetStaff() {...}

    /** @covers ::addStaff */
    public function testAddStaff() {...}
}

Great stuff. I was code reviewing someone’s unit tests yesterday, and he was using the @uses annotation on all his tests, to indicate functions that were being used but didn’t need test coverage, something like:

/** @coversDefaultClass \projectName\services\staff\StaffService */
class StaffServiceTest extends TestCase
{
    /**
     * @covers ::getStaff
     * @uses \projectName\services\staff\StaffService::__construct
     */
    public function testGetStaff() {...}

    /**
     * @covers ::addStaff
     * @uses \projectName\services\staff\StaffService::__construct
     */
    public function testAddStaff() {...}
 }

Unfortunately the @uses annotation needs you to specify the full path. It struck me that it would be useful if there was an equivalent @usesDefaultClass… and it turns out there is!

Someone raised an issue to get this added to PHPUnit over 3 years ago.

So the above code could then become:

/**
 * @coversDefaultClass \projectName\services\staff\StaffService
 * @usesDefaultClass \projectName\services\staff\StaffService
 */
class StaffServiceTest extends TestCase
{
    /**
     * @covers ::getStaff
     * @uses ::__construct
     */
    public function testGetStaff() {...}

    /**
     * @covers ::addStaff
     * @uses ::__construct
     */
    public function testAddStaff() {...}
}

It’s undocumented, so I’ve raised an issue to get it added to the PHPUnit Documentation: https://github.com/sebastianbergmann/phpunit-documentation/issues/477

Blog at WordPress.com.