Merge lp:~veebers/autopilot/fix-1328600-large-datetime into lp:autopilot

Proposed by Christopher Lee
Status: Superseded
Proposed branch: lp:~veebers/autopilot/fix-1328600-large-datetime
Merge into: lp:autopilot
Diff against target: 622 lines (+375/-66)
6 files modified
autopilot/introspection/types.py (+97/-7)
autopilot/tests/functional/fixtures.py (+15/-1)
autopilot/tests/functional/test_types.py (+87/-17)
autopilot/tests/unit/test_test_fixtures.py (+20/-0)
autopilot/tests/unit/test_types.py (+153/-41)
debian/control (+3/-0)
To merge this branch: bzr merge lp:~veebers/autopilot/fix-1328600-large-datetime
Reviewer Review Type Date Requested Status
Nicholas Skaggs (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Thomi Richards (community) Needs Fixing
Robert Bruce Park Pending
Barry Warsaw Pending
Christopher Lee Pending
Review via email: mp+236815@code.launchpad.net

This proposal supersedes a proposal from 2014-07-18.

This proposal has been superseded by a proposal from 2014-10-22.

Commit message

Workaround around 32-bit platform limitations with regards to timestamps. Bug 1328600

Description of the change

Fixes bug 1328600. Includes a test for "large" timestamps as well

This works around 32-bit platform limitations.

Resubmitted with updates.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:506
http://jenkins.qa.ubuntu.com/job/autopilot-ci/804/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/79
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/79/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/78
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/78/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/78
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/78/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/2206
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic-autopilot/219
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/2415
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/3380
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/3380/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/10094
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic-autopilot/283
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/2059
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/2059/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/autopilot-ci/804/rebuild

review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote : Posted in a previous version of this proposal

This doesn't actually fix the problem, it just creates new problems. Please see my comment on the bug report:

https://bugs.launchpad.net/ubuntu-calendar-app/+bug/1328600/comments/9

Thanks for the patch though, but it looks like this is going to be a bit more of an involved fix.

Cheers,

review: Disapprove
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

So the idea of using tzlocal seems to suffer from daylight savings problem, unless I'm missing something.

>>> from datetime import datetime, time, timedelta
>>> from dateutil.tz import tzlocal, tzutc
>>> print(datetime.fromtimestamp(1377209927))
2013-08-22 18:18:47
>>> print(datetime.fromtimestamp(1377209927,tzutc()))
2013-08-22 22:18:47+00:00
>>> naive = datetime.fromtimestamp(0) + timedelta(seconds=1377209927)
>>> print(naive)
2013-08-22 17:18:47
>>> aware = naive.replace(tzinfo=tzlocal())
>>> print(aware)
2013-08-22 17:18:47-04:00
>>> print(aware.astimezone(tzutc()))
2013-08-22 21:18:47+00:00
>>> aware2 = datetime.fromtimestamp(0, tzlocal())
>>> print(aware2)
1969-12-31 19:00:00-05:00
>>> print(aware2.astimezone(tzutc()))
1970-01-01 00:00:00+00:00
>>> try2 = aware2 + timedelta(seconds=1377209927)
>>> print(try2)
2013-08-22 17:18:47-04:00
>>> print(try2.astimezone(tzutc()))
2013-08-22 21:18:47+00:00

Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

Going to grab the local offset at the time of the timestamp and apply it against the fromtimestamp date.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote : Posted in a previous version of this proposal

I have a couple of comments in the diff.

Overall, this looks excellent - thank you for taking this on.

There's one change I'd like you to make in the tests, and I'd really like Barry Warsaw to review the implementation.

I'm setting this to approve, so you don't need a re-review once those two things have happeend (I trust ya :D )

review: Approve
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote : Posted in a previous version of this proposal

Oh, also, CI has to pass (obviously)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

Tests don't want to run now?

/var/local/autopilot/setup.log: I: Running autopilot
/var/local/autopilot/setup.log: I: Using python2
tail: '/var/lib/lxc//utopic-amd64-20140619-0752/run/delta//var/local/autopilot/autopilot.log' has become accessible
/var/local/autopilot/autopilot.log: Loading tests from: /usr/lib/python2.7/dist-packages
/var/local/autopilot/autopilot.log:
/var/local/autopilot/autopilot.log: Did not find any tests
/var/local/autopilot/autopilot.log:
/var/local/autopilot/autopilot.log: ----------------------------------------------------------------------
/var/local/autopilot/autopilot.log: Ran 0 tests in 0.126s
/var/local/autopilot/autopilot.log:
/var/local/autopilot/autopilot.log: OK
/var/local/autopilot/setup.log: I: Using python3
tail: /var/lib/lxc//utopic-amd64-20140619-0752/run/delta//var/local/autopilot/autopilot.log: file truncated
/var/local/autopilot/autopilot.log:
/var/local/autopilot/autopilot.log: ----------------------------------------------------------------------
/var/local/autopilot/autopilot.log: Ran 0 tests in 0.110s
/var/local/autopilot/autopilot.log:
/var/local/autopilot/autopilot.log: OK
/var/local/autopilot/setup.log: I: No test left to run

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

Why is this running 0 tests?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

I see a crash:

PythonArgs: ['/usr/sbin/aa-status']
Traceback:
 Traceback (most recent call last):
   File "/usr/sbin/aa-status", line 194, in <module>
     commands[cmd]()
   File "/usr/sbin/aa-status", line 17, in cmd_enabled
     if get_profiles() == {}:
   File "/usr/sbin/aa-status", line 92, in get_profiles
     for p in open(apparmor_profiles).readlines():
 PermissionError: [Errno 13] Permission denied: '/sys/kernel/security/apparmor/profiles'

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/autopilot/tests/functional/test_types.py", line 28, in test_date
    datetime(2014, 1, 1, 0, 0, 0)
  File "/usr/lib/python3/dist-packages/testtools/testcase.py", line 338, in assertEqual
    self.assertThat(observed, matcher, message)
  File "/usr/lib/python3/dist-packages/testtools/testcase.py", line 423, in assertThat
    raise mismatch_error
testtools.matchers._impl.MismatchError: DateTime(2014-01-01 00:00:00) != datetime.datetime(2014, 1, 1, 0, 0)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Christopher Lee (veebers) wrote : Posted in a previous version of this proposal

A couple of minor indent issues. Deeper review to come.

review: Needs Fixing
Revision history for this message
Robert Bruce Park (robru) wrote : Posted in a previous version of this proposal

Packaging looks good, thanks for the wrap-and-sort, makes for a noisy diff now but easier to read later.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:535
http://jenkins.qa.ubuntu.com/job/autopilot-ci/865/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/140
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/140/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/139
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/139/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/139
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/139/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/4627
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic-autopilot/303
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/4409
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5879
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5879/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/12911
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic-autopilot/342
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3727
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3727/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/autopilot-ci/865/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:536
http://jenkins.qa.ubuntu.com/job/autopilot-ci/866/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/141
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/141/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/140
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/140/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/140
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/140/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/4631
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic-autopilot/304
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/4413
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5883
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5883/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/12920
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic-autopilot/343
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3732
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3732/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/autopilot-ci/866/rebuild

review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:537
http://jenkins.qa.ubuntu.com/job/autopilot-ci/867/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/142
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-amd64-ci/142/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/141
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-armhf-ci/141/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/141
        deb: http://jenkins.qa.ubuntu.com/job/autopilot-utopic-i386-ci/141/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/4633
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic-autopilot/305
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/4415
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5885
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/5885/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/12923
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic-autopilot/344
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3733
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/3733/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/autopilot-ci/867/rebuild

review: Approve (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote : Posted in a previous version of this proposal

Can you provide an update on what you'd like to see with mp?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
542. By Christopher Lee

Commented out part of test to explore failure.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
543. By Christopher Lee

Avoid use of calls that use fromtimestamp (or _isdst) as they aren't large timestamp safe.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
544. By Christopher Lee

Fix creation of localtime + re-added test.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
545. By Christopher Lee

Removed unneeded check

546. By Christopher Lee

Cleanup tz setting in functional test.

547. By Christopher Lee

WIP comments for working out the DST applications.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
548. By Christopher Lee

Rough (further)WIP. About to all change.

549. By Christopher Lee

Code confirmation and cleanup. Using aware datetime objects now

550. By Christopher Lee

Change __eq__ operator and update test

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
551. By Christopher Lee

Improve naming and comments explaining what is going on.

552. By Christopher Lee

flake8 cleanup.

553. By Christopher Lee

Commit and whitespace cleanup

554. By Christopher Lee

Re-enable test.

555. By Christopher Lee

Remove un-needed package from d/control

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
556. By Christopher Lee

Updated docstrings.

557. By Christopher Lee

Further docstring update

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Getting very close now, but still need to make a few changes

review: Needs Fixing
558. By Christopher Lee

Clarify docstrings, comments and variables

559. By Christopher Lee

Added SetTimezone fixture + tests for it

560. By Christopher Lee

Update tests skip tests only when the platform doesn't support the large time_t

561. By Christopher Lee

Clarified comment a little bit.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
562. By Christopher Lee

Added and clarified details around DateTime.timestamp

563. By Christopher Lee

Really minor comment change.

564. By Christopher Lee

Backout packaging changes to be put in a separate patch

565. By Christopher Lee

Cleanup double-up in debian/control

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

I retested the original failing tests (both calendar as well as UITK) and confirmed this change fixes the test. We also tested the trunk version of these tests and the tests reacted the same way as trunk autopilot; no regressions on date handling.

review: Approve
566. By Christopher Lee

Minor whitespace fix

567. By Christopher Lee

Better name for Timezone fixture.

568. By Christopher Lee

Alter test to not use Europe/Moscow for now.

569. By Christopher Lee

Fix flake8 issue

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'autopilot/introspection/types.py'
--- autopilot/introspection/types.py 2014-05-29 19:44:44 +0000
+++ autopilot/introspection/types.py 2014-10-22 20:43:57 +0000
@@ -37,7 +37,9 @@
3737
38"""38"""
3939
40from datetime import datetime, time40from datetime import datetime, time, timedelta
41from dateutil.tz import gettz, tzutc
42
41import dbus43import dbus
42import logging44import logging
43from testtools.matchers import Equals45from testtools.matchers import Equals
@@ -547,6 +549,15 @@
547 """The DateTime class represents a date and time in the UTC timezone.549 """The DateTime class represents a date and time in the UTC timezone.
548550
549 DateTime is constructed by passing a unix timestamp in to the constructor.551 DateTime is constructed by passing a unix timestamp in to the constructor.
552 The incoming timestamp is assumed to be in UTC.
553
554 .. note:: This class expects the passed in timestamp to be in UTC but will
555 display the resulting date and time in local time (using the local
556 timezone).
557
558 This is done to mimic the behaviour of most applications which will
559 display date and time in local time by default
560
550 Timestamps are expressed as the number of seconds since 1970-01-01T00:00:00561 Timestamps are expressed as the number of seconds since 1970-01-01T00:00:00
551 in the UTC timezone::562 in the UTC timezone::
552563
@@ -588,10 +599,48 @@
588 Finally, you can also compare a DateTime instance with a python datetime599 Finally, you can also compare a DateTime instance with a python datetime
589 instance::600 instance::
590601
591 >>> my_datetime = datetime.datetime.fromutctimestamp(1377209927)602 >>> my_datetime = datetime.datetime.utcfromtimestamp(1377209927)
592 True603 True
593604
594 DateTime instances can be converted to datetime instances:605
606 .. note:: Autopilot supports dates beyond 2038 on 32-bit platforms. To
607 achieve this the underlying mechanisms require to work with timezone aware
608 datetime objects.
609
610 This means that the following won't always be true (due to the naive
611 timestamp not having the correct daylight-savings time details)::
612
613 >>> # This time stamp is within DST in the 'Europe/London' timezone
614 >>> dst_ts = 1405382400
615 >>> os.environ['TZ'] ='Europe/London'
616 >>> time.tzset()
617 >>> datetime.fromtimestamp(dst_ts).hour == DateTime(dst_ts).hour
618 False
619
620 But this will work::
621
622 >>> from dateutil.tz import gettz
623 >>> datetime.fromtimestamp(
624 dst_ts, gettz()).hour == DateTime(dst_ts).hour
625 True
626
627 And this will always work to::
628
629 >>> dt1 = DateTime(nz_dst_timestamp)
630 >>> dt2 = datetime(
631 dt1.year, dt1.month, dt1.day, dt1.hour, dt1.minute, dt1.second
632 )
633 >>> dt1 == dt2
634 True
635
636 .. note:: DateTime.timestamp() will not always equal the passed in
637 timestamp.
638 To paraphrase a message from [http://bugs.python.org/msg229393]
639 "datetime.timestamp is supposed to be inverse of
640 datetime.fromtimestamp(), but since the later is not monotonic, no such
641 inverse exists in the strict mathematical sense."
642
643 DateTime instances can be converted to datetime instances::
595644
596 >>> isinstance(my_dt.datetime, datetime.datetime)645 >>> isinstance(my_dt.datetime, datetime.datetime)
597 True646 True
@@ -599,7 +648,41 @@
599 """648 """
600 def __init__(self, *args, **kwargs):649 def __init__(self, *args, **kwargs):
601 super(DateTime, self).__init__(*args, **kwargs)650 super(DateTime, self).__init__(*args, **kwargs)
602 self._cached_dt = datetime.fromtimestamp(self[0])651 # Using timedelta in this manner is a workaround so that we can support
652 # timestamps larger than the 32bit time_t limit on 32bit hardware.
653 # We then apply another workaround where timedelta doesn't apply
654 # daylight savings, so we need to work out the offsets for the
655 # localtime manually and apply them to give us the correct local time.
656 #
657 # Note. self[0] is a UTC timestamp
658 EPOCH = datetime(1970, 1, 1, tzinfo=tzutc())
659 utc_dt = EPOCH + timedelta(seconds=self[0])
660
661 local_tzinfo = gettz()
662
663 # Get the localtimes timezone offset (known as standard offset) by
664 # subtracting its dst offset (if any) from its utc offset.
665 # We apply this to the utc datetime object to get datetime object in
666 # localtime.
667 # (We will check (once we have a local datetime) if the time is in dst
668 # and make that adjustment then.)
669 utc_offset = local_tzinfo.utcoffset(utc_dt)
670 dst_offset = local_tzinfo.dst(utc_dt)
671 standard_offset = utc_offset - dst_offset
672
673 # Create a local timezone aware datetime object from the utc_dt
674 # (i.e. attaching a timezone to it) and apply the standard offset to
675 # give us the local time.
676 local_dt = utc_dt.replace(tzinfo=local_tzinfo) + standard_offset
677
678 # If the new local time is firmly in std time then the standard offset
679 # will be 0 (i.e. timedelta(0)).
680 # If the delta isn't 0 then we need to use the timezone information to
681 # apply the dst delta to the local time.
682 if standard_offset != timedelta(0):
683 local_dt = local_dt + local_tzinfo.dst(local_dt)
684
685 self._cached_dt = local_dt
603686
604 @property687 @property
605 def year(self):688 def year(self):
@@ -627,14 +710,21 @@
627710
628 @property711 @property
629 def timestamp(self):712 def timestamp(self):
630 return self[0]713 return self._cached_dt.timestamp()
631714
632 @property715 @property
633 def datetime(self):716 def datetime(self):
634 return self._cached_dt717 return self._cached_dt
635718
636 def __eq__(self, other):719 def __eq__(self, other):
720 # A little 'magic' here, if the datetime object to test against is
721 # naive, use the tzinfo from the cached datetime (just for the
722 # comparison)
637 if isinstance(other, datetime):723 if isinstance(other, datetime):
724 if other.tzinfo is None:
725 return other.replace(
726 tzinfo=self._cached_dt.tzinfo
727 ) == self._cached_dt
638 return other == self._cached_dt728 return other == self._cached_dt
639 return super(DateTime, self).__eq__(other)729 return super(DateTime, self).__eq__(other)
640730
641731
=== modified file 'autopilot/tests/functional/fixtures.py'
--- autopilot/tests/functional/fixtures.py 2014-05-23 13:44:36 +0000
+++ autopilot/tests/functional/fixtures.py 2014-10-22 20:43:57 +0000
@@ -25,8 +25,9 @@
25from shutil import rmtree25from shutil import rmtree
26import tempfile26import tempfile
27from textwrap import dedent27from textwrap import dedent
28import time
2829
29from fixtures import Fixture30from fixtures import EnvironmentVariable, Fixture
3031
3132
32logger = logging.getLogger(__name__)33logger = logging.getLogger(__name__)
@@ -166,3 +167,16 @@
166 with open(tmp_file_path, 'w') as desktop_file:167 with open(tmp_file_path, 'w') as desktop_file:
167 desktop_file.write(file_contents)168 desktop_file.write(file_contents)
168 return tmp_file_path169 return tmp_file_path
170
171
172class SetTimezone(Fixture):
173 def __init__(self, timezone):
174 self._timezone = timezone
175
176 def setUp(self):
177 super().setUp()
178 # These steps need to happen in the right order otherwise they won't
179 # get cleaned up properly and we'll be left in an incorrect timezone.
180 self.addCleanup(time.tzset)
181 self.useFixture(EnvironmentVariable('TZ', self._timezone))
182 time.tzset()
169183
=== modified file 'autopilot/tests/functional/test_types.py'
--- autopilot/tests/functional/test_types.py 2014-05-22 06:41:16 +0000
+++ autopilot/tests/functional/test_types.py 2014-10-22 20:43:57 +0000
@@ -1,29 +1,99 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Autopilot Functional Test Tool
4# Copyright (C) 2013-2014 Canonical
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
119
2from datetime import datetime20from datetime import datetime
321
4from autopilot.testcase import AutopilotTestCase22from autopilot.testcase import AutopilotTestCase
5from autopilot.tests.functional import QmlScriptRunnerMixin23from autopilot.tests.functional import QmlScriptRunnerMixin
24from autopilot.tests.functional.fixtures import SetTimezone
625
7from textwrap import dedent26from textwrap import dedent
827
928
10class TypeTests(AutopilotTestCase, QmlScriptRunnerMixin):29class DateTimeTests(AutopilotTestCase, QmlScriptRunnerMixin):
1130 scenarios = [
12 def test_date(self):31 ('UTC', dict(
13 proxy = self.start_qml_script(32 TZ='UTC',
14 dedent(33 expected_string='2014-09-29T12:00:00',
15 """\34 )),
16 import QtQuick 2.035 ('NZ', dict(
1736 TZ='Pacific/Auckland',
18 Item {37 expected_string='2014-09-30T01:00:00',
19 objectName: "TestMePlease"38 )),
20 property date foo: "2014-01-01"39 ('US Central', dict(
40 TZ='US/Central',
41 expected_string='2014-09-29T07:00:00',
42 )),
43 ('US Eastern', dict(
44 TZ='US/Eastern',
45 expected_string='2014-09-29T08:00:00',
46 )),
47 ('MSK', dict(
48 TZ='Europe/Moscow',
49 expected_string='2014-09-29T16:00:00',
50 )),
51 ]
52
53 def get_test_qml_string(self, date_string):
54 return dedent("""
55 import QtQuick 2.0
56 import QtQml 2.2
57 Rectangle {
58 property date testingTime: new Date(%s);
59 Text {
60 text: testingTime;
21 }61 }
22 """62 }""" % date_string)
23 )63
24 )64 def test_qml_applies_timezone_to_timestamp(self):
25 item = proxy.select_single('*', objectName="TestMePlease")65 """Test that when given a timestamp the datetime displayed has the
66 timezone applied to it.
67
68 QML will apply a timezone calculation to a timestamp (but not a
69 timestring).
70
71 """
72 self.useFixture(SetTimezone(self.TZ))
73
74 qml_script = self.get_test_qml_string('1411992000000')
75
76 proxy = self.start_qml_script(qml_script)
26 self.assertEqual(77 self.assertEqual(
27 item.foo,78 proxy.select_single('QQuickText').text,
28 datetime(2014, 1, 1, 0, 0, 0)79 self.expected_string
29 )80 )
81
82 def test_timezone_not_applied_to_timestring(self):
83 """Test that, in all timezones, the literal representation we get in
84 the proxy object matches the one in the Qml script.
85
86 """
87 self.useFixture(SetTimezone(self.TZ))
88
89 qml_script = self.get_test_qml_string("'2014-01-15 12:34:52'")
90 proxy = self.start_qml_script(qml_script)
91 date_object = proxy.select_single("QQuickRectangle").testingTime
92
93 self.assertEqual(date_object.year, 2014)
94 self.assertEqual(date_object.month, 1)
95 self.assertEqual(date_object.day, 15)
96 self.assertEqual(date_object.hour, 12)
97 self.assertEqual(date_object.minute, 34)
98 self.assertEqual(date_object.second, 52)
99 self.assertEqual(datetime(2014, 1, 15, 12, 34, 52), date_object)
30100
=== modified file 'autopilot/tests/unit/test_test_fixtures.py'
--- autopilot/tests/unit/test_test_fixtures.py 2014-05-20 08:53:21 +0000
+++ autopilot/tests/unit/test_test_fixtures.py 2014-10-22 20:43:57 +0000
@@ -19,6 +19,7 @@
1919
20from autopilot.tests.functional.fixtures import (20from autopilot.tests.functional.fixtures import (
21 ExecutableScript,21 ExecutableScript,
22 SetTimezone,
22 TempDesktopFile,23 TempDesktopFile,
23)24)
2425
@@ -213,3 +214,22 @@
213 def test_creates_file_with_execute_bit_set(self):214 def test_creates_file_with_execute_bit_set(self):
214 fixture = self.useFixture(ExecutableScript(script=""))215 fixture = self.useFixture(ExecutableScript(script=""))
215 self.assertTrue(os.stat(fixture.path).st_mode & stat.S_IXUSR)216 self.assertTrue(os.stat(fixture.path).st_mode & stat.S_IXUSR)
217
218
219class SetTimezoneTests(TestCase):
220
221 def test_sets_environment_variable_to_timezone(self):
222 token = self.getUniqueString()
223
224 self.useFixture(SetTimezone(token))
225
226 self.assertEqual(os.environ.get('TZ'), token)
227
228 def test_resets_timezone_back_to_original(self):
229 original_tz = os.environ.get('TZ', None)
230 token = self.getUniqueString()
231
232 fixture = self.useFixture(SetTimezone(token))
233 fixture.cleanUp()
234
235 self.assertEqual(os.environ.get('TZ', None), original_tz)
216236
=== modified file 'autopilot/tests/unit/test_types.py'
--- autopilot/tests/unit/test_types.py 2014-07-22 02:39:26 +0000
+++ autopilot/tests/unit/test_types.py 2014-10-22 20:43:57 +0000
@@ -18,13 +18,14 @@
18#18#
1919
20from datetime import datetime, time20from datetime import datetime, time
21from testscenarios import TestWithScenarios21from testscenarios import TestWithScenarios, multiply_scenarios
22from testtools import TestCase22from testtools import TestCase
23from testtools.matchers import Equals, IsInstance, NotEquals, raises23from testtools.matchers import Equals, IsInstance, NotEquals, raises
2424
25import dbus25import dbus
26from unittest.mock import patch, Mock26from unittest.mock import patch, Mock
2727
28from autopilot.tests.functional.fixtures import SetTimezone
28from autopilot.introspection.types import (29from autopilot.introspection.types import (
29 Color,30 Color,
30 create_value_instance,31 create_value_instance,
@@ -51,6 +52,8 @@
51from autopilot.introspection.dbus import DBusIntrospectionObject52from autopilot.introspection.dbus import DBusIntrospectionObject
52from autopilot.utilities import compatible_repr53from autopilot.utilities import compatible_repr
5354
55from dateutil import tz
56
5457
55class PlainTypeTests(TestWithScenarios, TestCase):58class PlainTypeTests(TestWithScenarios, TestCase):
5659
@@ -281,19 +284,32 @@
281 self.assertEqual(repr(c), str(c))284 self.assertEqual(repr(c), str(c))
282285
283286
284class DateTimeTests(TestCase):287def unable_to_handle_timestamp(timestamp):
288 """Return false if the platform can handle timestamps larger than 32bit
289 limit.
290
291 """
292 try:
293 datetime.fromtimestamp(timestamp)
294 return False
295 except:
296 return True
297
298
299class DateTimeCreationTests(TestCase):
300
301 timestamp = 1405382400 # No significance, just a timestamp
285302
286 def test_can_construct_datetime(self):303 def test_can_construct_datetime(self):
287 dt = DateTime(1377209927)304 dt = DateTime(self.timestamp)
288 self.assertThat(dt, IsInstance(dbus.Array))305 self.assertThat(dt, IsInstance(dbus.Array))
289306
290 def test_datetime_has_slice_access(self):307 def test_datetime_has_slice_access(self):
291 dt = DateTime(1377209927)308 dt = DateTime(self.timestamp)
292309 self.assertThat(dt[0], Equals(self.timestamp))
293 self.assertThat(dt[0], Equals(1377209927))
294310
295 def test_datetime_has_properties(self):311 def test_datetime_has_properties(self):
296 dt = DateTime(1377209927)312 dt = DateTime(self.timestamp)
297313
298 self.assertTrue(hasattr(dt, 'timestamp'))314 self.assertTrue(hasattr(dt, 'timestamp'))
299 self.assertTrue(hasattr(dt, 'year'))315 self.assertTrue(hasattr(dt, 'year'))
@@ -303,58 +319,154 @@
303 self.assertTrue(hasattr(dt, 'minute'))319 self.assertTrue(hasattr(dt, 'minute'))
304 self.assertTrue(hasattr(dt, 'second'))320 self.assertTrue(hasattr(dt, 'second'))
305321
322 def test_repr(self):
323 # Use a well known timezone for comparison
324 self.useFixture(SetTimezone('UTC'))
325 dt = DateTime(self.timestamp)
326 observed = repr(dt)
327
328 expected = "DateTime({:%Y-%m-%d %H:%M:%S})".format(
329 datetime.fromtimestamp(self.timestamp)
330 )
331 self.assertEqual(expected, observed)
332
333 def test_repr_equals_str(self):
334 dt = DateTime(self.timestamp)
335 self.assertEqual(repr(dt), str(dt))
336
337 def test_can_create_DateTime_using_large_timestamp(self):
338 """Must be able to create a DateTime object using a timestamp larger
339 than the 32bit time_t limit.
340
341 """
342 # Use a well known timezone for comparison
343 self.useFixture(SetTimezone('UTC'))
344 large_timestamp = 2**32+1
345 dt = DateTime(large_timestamp)
346
347 self.assertEqual(dt.year, 2106)
348 self.assertEqual(dt.month, 2)
349 self.assertEqual(dt.day, 7)
350 self.assertEqual(dt.hour, 6)
351 self.assertEqual(dt.minute, 28)
352 self.assertEqual(dt.second, 17)
353 self.assertEqual(dt.timestamp, large_timestamp)
354
355
356class DateTimeTests(TestWithScenarios, TestCase):
357
358 timestamps = [
359 # This timestamp uncovered an issue during development.
360 ('Explicit US/Pacific test', dict(
361 timestamp=1090123200
362 )),
363
364 ('NZ DST example', dict(
365 timestamp=2047570047
366 )),
367
368 ('Winter', dict(
369 timestamp=1389744000
370 )),
371
372 ('Summer', dict(
373 timestamp=1405382400
374 )),
375
376 ('32bit max', dict(
377 timestamp=2**32+1
378 )),
379
380 ('32bit limit', dict(
381 timestamp=2983579200
382 )),
383
384 ]
385
386 timezones = [
387 ('UTC', dict(
388 timezone='UTC'
389 )),
390
391 ('London', dict(
392 timezone='Europe/London'
393 )),
394
395 ('New Zealand', dict(
396 timezone='NZ',
397 )),
398
399 ('Pacific', dict(
400 timezone='US/Pacific'
401 )),
402
403 ('Hongkong', dict(
404 timezone='Hongkong'
405 )),
406
407 ('Moscow', dict(
408 timezone='Europe/Moscow'
409 ))
410 ]
411
412 scenarios = multiply_scenarios(timestamps, timezones)
413
414 def skip_if_timestamp_too_large(self, timestamp):
415 if unable_to_handle_timestamp(self.timestamp):
416 self.skip("Timestamp to large for platform time_t")
417
306 def test_datetime_properties_have_correct_values(self):418 def test_datetime_properties_have_correct_values(self):
307 dt = DateTime(1377209927)419 self.skip_if_timestamp_too_large(self.timestamp)
308 dt_with_tz = datetime.fromtimestamp(1377209927)420 self.useFixture(SetTimezone(self.timezone))
309421
310 self.assertThat(dt.timestamp, Equals(dt_with_tz.timestamp()))422 dt1 = DateTime(self.timestamp)
311 self.assertThat(dt.year, Equals(dt_with_tz.year))423 dt2 = datetime.fromtimestamp(self.timestamp, tz.gettz())
312 self.assertThat(dt.month, Equals(dt_with_tz.month))424
313 self.assertThat(dt.day, Equals(dt_with_tz.day))425 self.assertThat(dt1.year, Equals(dt2.year))
314 self.assertThat(dt.hour, Equals(dt_with_tz.hour))426 self.assertThat(dt1.month, Equals(dt2.month))
315 self.assertThat(dt.minute, Equals(dt_with_tz.minute))427 self.assertThat(dt1.day, Equals(dt2.day))
316 self.assertThat(dt.second, Equals(dt_with_tz.second))428 self.assertThat(dt1.hour, Equals(dt2.hour))
429 self.assertThat(dt1.minute, Equals(dt2.minute))
430 self.assertThat(dt1.second, Equals(dt2.second))
431 self.assertThat(dt1.timestamp, Equals(dt2.timestamp()))
317432
318 def test_equality_with_datetime(self):433 def test_equality_with_datetime(self):
319 dt1 = DateTime(1377209927)434 self.skip_if_timestamp_too_large(self.timestamp)
320 dt2 = DateTime(1377209927)435 self.useFixture(SetTimezone(self.timezone))
436
437 dt1 = DateTime(self.timestamp)
438 dt2 = datetime(
439 dt1.year, dt1.month, dt1.day, dt1.hour, dt1.minute, dt1.second
440 )
321441
322 self.assertThat(dt1, Equals(dt2))442 self.assertThat(dt1, Equals(dt2))
323443
324 def test_equality_with_list(self):444 def test_equality_with_list(self):
325 dt1 = DateTime(1377209927)445 self.skip_if_timestamp_too_large(self.timestamp)
326 dt2 = [1377209927]446 self.useFixture(SetTimezone(self.timezone))
447
448 dt1 = DateTime(self.timestamp)
449 dt2 = [self.timestamp]
327450
328 self.assertThat(dt1, Equals(dt2))451 self.assertThat(dt1, Equals(dt2))
329452
330 def test_equality_with_datetime_timestamp(self):453 def test_equality_with_datetime_object(self):
331 # DateTime no longer assumes UTC and uses local TZ.454 self.skip_if_timestamp_too_large(self.timestamp)
332 dt1 = DateTime(1377209927)455 self.useFixture(SetTimezone(self.timezone))
333 dt2 = datetime.fromtimestamp(1377209927)456
334 dt3 = datetime.fromtimestamp(1377209928)457 dt1 = DateTime(self.timestamp)
458 dt2 = datetime.fromtimestamp(self.timestamp, tz.gettz())
459 dt3 = datetime.fromtimestamp(self.timestamp + 1, tz.gettz())
335460
336 self.assertThat(dt1, Equals(dt2))461 self.assertThat(dt1, Equals(dt2))
337 self.assertThat(dt1, NotEquals(dt3))462 self.assertThat(dt1, NotEquals(dt3))
338463
339 def test_can_convert_to_datetime(self):464 def test_can_convert_to_datetime(self):
340 dt1 = DateTime(1377209927)465 self.skip_if_timestamp_too_large(self.timestamp)
341466
467 dt1 = DateTime(self.timestamp)
342 self.assertThat(dt1.datetime, IsInstance(datetime))468 self.assertThat(dt1.datetime, IsInstance(datetime))
343469
344 def test_repr(self):
345 expected = repr_type(
346 u"DateTime({:%Y-%m-%d %H:%M:%S})".format(
347 datetime.fromtimestamp(1377209927)
348 )
349 )
350 dt = DateTime(1377209927)
351 observed = repr(dt)
352 self.assertEqual(expected, observed)
353
354 def test_repr_equals_str(self):
355 dt = DateTime(1377209927)
356 self.assertEqual(repr(dt), str(dt))
357
358470
359class TimeTests(TestCase):471class TimeTests(TestCase):
360472
361473
=== modified file 'debian/control'
--- debian/control 2014-08-05 21:58:41 +0000
+++ debian/control 2014-10-22 20:43:57 +0000
@@ -15,6 +15,7 @@
15 libjs-underscore,15 libjs-underscore,
16 liblttng-ust-dev,16 liblttng-ust-dev,
17 python3-all-dev (>= 3.4),17 python3-all-dev (>= 3.4),
18 python3-dateutil,
18 python3-dbus,19 python3-dbus,
19 python3-decorator,20 python3-decorator,
20 python3-evdev,21 python3-evdev,
@@ -44,6 +45,7 @@
44 ${python3:Depends},45 ${python3:Depends},
45 gir1.2-ubuntu-app-launch-2 | gir1.2-upstart-app-launch-2,46 gir1.2-ubuntu-app-launch-2 | gir1.2-upstart-app-launch-2,
46 libjs-underscore, libjs-jquery,47 libjs-underscore, libjs-jquery,
48 python3-dateutil,
47 python3-dbus,49 python3-dbus,
48 python3-decorator,50 python3-decorator,
49 python3-fixtures,51 python3-fixtures,
@@ -135,6 +137,7 @@
135 libautopilot-gtk (>= 1.4),137 libautopilot-gtk (>= 1.4),
136 libautopilot-qt (>= 1.4),138 libautopilot-qt (>= 1.4),
137 python3-autopilot,139 python3-autopilot,
140 python3-dateutil,
138 python3-dbus.mainloop.qt,141 python3-dbus.mainloop.qt,
139 python3-evdev,142 python3-evdev,
140 python3-pyqt4,143 python3-pyqt4,

Subscribers

People subscribed via source and target branches