Commit 61da3a31 authored by Patrik Dufresne's avatar Patrik Dufresne

Migrate rdwTime to librdiff.RdiffTime.

Move the rdwTime class to librdiff module since it's related to the way
rdiff-backup manage dates.
parent f142a83d
......@@ -21,9 +21,12 @@ from __future__ import unicode_literals
import bisect
from builtins import bytes
from builtins import map
from builtins import object
from builtins import str
import calendar
from collections import OrderedDict
from datetime import timedelta
import encodings
from future.utils import iteritems
from future.utils import python_2_unicode_compatible
......@@ -32,6 +35,8 @@ import gzip
import io
import logging
import os
from past.builtins import cmp
from past.utils import old_div
import psutil
import re
from shutil import copyfileobj
......@@ -39,6 +44,7 @@ import shutil
import sys
import tempfile
import threading
import time
import weakref
import zlib
......@@ -47,7 +53,6 @@ from rdiffweb.archiver import archive, ARCHIVERS
from rdiffweb.i18n import ugettext as _
from rdiffweb.rdw_config import Configuration
try:
import subprocess32 as subprocess # @UnresolvedImport @UnusedImport
except:
......@@ -105,6 +110,166 @@ class UnknownError(FileError):
pass
@python_2_unicode_compatible
class RdiffTime(object):
"""Time information has two components: the local time, stored in GMT as
seconds since Epoch, and the timezone, stored as a seconds offset. Since
the server may not be in the same timezone as the user, we cannot rely on
the built-in localtime() functions, but look at the rdiff-backup string
for timezone information. As a general rule, we always display the
"local" time, but pass the timezone information on to rdiff-backup, so
it can restore to the correct state"""
def __init__(self, value=None, tz_offset=None):
assert value is None or isinstance(value, int) or isinstance(value, str)
if value is None:
# Get GMT time.
self.timeInSeconds = int(time.time())
self.tzOffset = tz_offset or 0
elif isinstance(value, int):
self.timeInSeconds = value
self.tzOffset = tz_offset or 0
else:
self._initFromString(value)
def initFromMidnightUTC(self, daysFromToday):
self.timeInSeconds = time.time()
self.timeInSeconds -= self.timeInSeconds % (24 * 60 * 60)
self.timeInSeconds += daysFromToday * 24 * 60 * 60
self.tzOffset = 0
def _initFromString(self, timeString):
try:
date, daytime = timeString[:19].split("T")
year, month, day = list(map(int, date.split("-")))
hour, minute, second = list(map(int, daytime.split(":")))
assert 1900 < year < 2100, year
assert 1 <= month <= 12
assert 1 <= day <= 31
assert 0 <= hour <= 23
assert 0 <= minute <= 59
assert 0 <= second <= 61 # leap seconds
timetuple = (year, month, day, hour, minute, second, -1, -1, 0)
self.timeInSeconds = calendar.timegm(timetuple)
self.tzOffset = self._tzdtoseconds(timeString[19:])
self.getTimeZoneString() # to get assertions there
except (TypeError, ValueError, AssertionError):
raise ValueError(timeString)
def getLocalDaysSinceEpoch(self):
return self.getLocalSeconds() // (24 * 60 * 60)
def getLocalSeconds(self):
return self.timeInSeconds
def getSeconds(self):
return self.timeInSeconds - self.tzOffset
def getDisplayString(self):
value = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(self.getLocalSeconds()))
if isinstance(value, bytes):
value = value.decode(encoding='latin1')
return value
def getTimeZoneString(self):
if self.tzOffset:
tzinfo = self._getTimeZoneDisplayInfo()
return "%s%s:%s" % (tzinfo["plusMinus"], tzinfo["hours"], tzinfo["minutes"])
else:
return "Z"
def setTime(self, hour, minute, second):
year = time.gmtime(self.timeInSeconds)[0]
month = time.gmtime(self.timeInSeconds)[1]
day = time.gmtime(self.timeInSeconds)[2]
self.timeInSeconds = calendar.timegm(
(year, month, day, hour, minute, second, -1, -1, 0))
def _getTimeZoneDisplayInfo(self):
hours, minutes = divmod(old_div(abs(self.tzOffset), 60), 60)
assert 0 <= hours <= 23
assert 0 <= minutes <= 59
if self.tzOffset > 0:
plusMinus = "+"
else:
plusMinus = "-"
return {"plusMinus": plusMinus,
"hours": "%02d" % hours,
"minutes": "%02d" % minutes}
def _tzdtoseconds(self, tzd):
"""Given w3 compliant TZD, converts it to number of seconds from UTC"""
if tzd == "Z":
return 0
assert len(tzd) == 6 # only accept forms like +08:00 for now
assert (tzd[0] == "-" or tzd[0] == "+") and tzd[3] == ":"
if tzd[0] == "+":
plusMinus = 1
else:
plusMinus = -1
return plusMinus * 60 * (60 * int(tzd[1:3]) + int(tzd[4:]))
def __add__(self, other):
"""Support plus (+) timedelta"""
assert isinstance(other, timedelta)
return RdiffTime(self.timeInSeconds + int(other.total_seconds()), self.tzOffset)
def __sub__(self, other):
"""Support minus (-) timedelta"""
assert isinstance(other, timedelta) or isinstance(other, RdiffTime)
# Sub with timedelta, return RdiffTime
if isinstance(other, timedelta):
return RdiffTime(self.timeInSeconds - int(other.total_seconds()), self.tzOffset)
# Sub with RdiffTime, return timedelta
if isinstance(other, RdiffTime):
return timedelta(seconds=self.timeInSeconds - other.timeInSeconds)
def __int__(self):
"""Return this date as seconds since epoch."""
return self.timeInSeconds
def __lt__(self, other):
assert isinstance(other, RdiffTime)
return self.getSeconds() < other.getSeconds()
def __le__(self, other):
assert isinstance(other, RdiffTime)
return self.getSeconds() <= other.getSeconds()
def __gt__(self, other):
assert isinstance(other, RdiffTime)
return self.getSeconds() > other.getSeconds()
def __ge__(self, other):
assert isinstance(other, RdiffTime)
return self.getSeconds() >= other.getSeconds()
def __cmp__(self, other):
assert isinstance(other, RdiffTime)
return cmp(self.getSeconds(), other.getSeconds())
def __eq__(self, other):
return (isinstance(other, RdiffTime) and
self.getSeconds() == other.getSeconds())
def __hash__(self):
return hash(self.getSeconds())
def __str__(self):
"""return utf-8 string"""
return self.getDisplayString()
def __repr__(self):
"""return second since epoch"""
return str(self.getSeconds())
# Interfaced objects #
class DirEntry(object):
......@@ -299,7 +464,7 @@ class HistoryEntry(object):
def __init__(self, repo, date):
assert isinstance(repo, RdiffRepo)
assert isinstance(date, rdw_helpers.rdwTime)
assert isinstance(date, RdiffTime)
self._repo = weakref.proxy(repo)
self.date = date
......@@ -677,7 +842,7 @@ class RdiffRepo(object):
# Unquote string
date_string = self.unquote(date_string)
try:
return rdw_helpers.rdwTime(date_string.decode())
return RdiffTime(date_string.decode())
except:
logger.warn('fail to parse date [%r]', date_string, exc_info=1)
return None
......@@ -727,9 +892,9 @@ class RdiffRepo(object):
assert isinstance(numLatestEntries, int)
assert (earliestDate is None or
isinstance(earliestDate, rdw_helpers.rdwTime))
isinstance(earliestDate, RdiffTime))
assert (latestDate is None or
isinstance(latestDate, rdw_helpers.rdwTime))
isinstance(latestDate, RdiffTime))
logger.debug("get history entries for [%r]", self.full_path)
......@@ -831,7 +996,7 @@ class RdiffRepo(object):
def restore(self, path, restore_date, kind='zip'):
"""Used to restore the given file located in this path."""
assert isinstance(path, bytes) or isinstance(path, DirEntry)
assert isinstance(restore_date, rdw_helpers.rdwTime) or isinstance(restore_date, int)
assert isinstance(restore_date, RdiffTime) or isinstance(restore_date, int)
assert kind in ARCHIVERS
# Get the info we need from DirEntry
......@@ -848,7 +1013,7 @@ class RdiffRepo(object):
file_to_restore = self.unquote(file_to_restore)
# Convert the date into epoch.
if isinstance(restore_date, rdw_helpers.rdwTime):
if isinstance(restore_date, RdiffTime):
restore_date = restore_date.getSeconds()
# Define a nice filename for the archive or file to be created.
......
......@@ -26,12 +26,11 @@ from cherrypy.lib.static import _serve_fileobj
import logging
from rdiffweb import page_main
from rdiffweb import rdw_helpers
import rdiffweb
from rdiffweb.archiver import ARCHIVERS
from rdiffweb.i18n import ugettext as _
from rdiffweb.librdiff import RdiffTime
from rdiffweb.rdw_helpers import quote_url
from rdiffweb.archiver import ARCHIVERS
# Define the logger
logger = logging.getLogger(__name__)
......@@ -78,7 +77,7 @@ class RestorePage(page_main.MainPage):
# Get the restore date
try:
rdw_helpers.rdwTime(int(date))
RdiffTime(int(date))
except:
logger.warning("invalid date %s", date)
raise cherrypy.HTTPError(400, _("Invalid date."))
......
......@@ -19,8 +19,8 @@
from __future__ import absolute_import
from __future__ import unicode_literals
from builtins import str
from builtins import bytes
from builtins import str
import cherrypy
import logging
......@@ -62,7 +62,7 @@ class StatusPage(page_main.MainPage):
self.assertIsInstance(date, str)
# Validate date
try:
entry_time = rdw_helpers.rdwTime(int(date))
entry_time = librdiff.RdiffTime(int(date))
except:
logger.exception("invalid date")
raise cherrypy.HTTPError(400, _("Invalid date."))
......@@ -122,12 +122,12 @@ class StatusPage(page_main.MainPage):
# Set the start and end time to be the start and end of the day,
# respectively, to get all entries for that day
startTime = rdw_helpers.rdwTime()
startTime = librdiff.RdiffTime()
startTime.timeInSeconds = date.timeInSeconds
startTime.tzOffset = date.tzOffset
startTime.setTime(0, 0, 0)
endTime = rdw_helpers.rdwTime()
endTime = librdiff.RdiffTime()
endTime.timeInSeconds = date.timeInSeconds
endTime.tzOffset = date.tzOffset
endTime.setTime(23, 59, 59)
......@@ -137,7 +137,7 @@ class StatusPage(page_main.MainPage):
def _get_recent_user_messages(self, failuresOnly):
user_repos = self.app.currentuser.repos
asOfDate = rdw_helpers.rdwTime()
asOfDate = librdiff.RdiffTime()
asOfDate.initFromMidnightUTC(-5)
return self._getUserMessages(user_repos, not failuresOnly, True,
......
......@@ -37,7 +37,6 @@ from xml.etree.ElementTree import fromstring, tostring
from rdiffweb import librdiff
from rdiffweb.core import RdiffError, RdiffWarning
from rdiffweb.i18n import ugettext as _
from rdiffweb.rdw_helpers import rdwTime
from rdiffweb.rdw_plugin import IPreferencesPanelProvider, JobPlugin, \
IUserChangeListener
......@@ -203,7 +202,7 @@ class NotificationPlugin(IPreferencesPanelProvider, JobPlugin, IUserChangeListen
Loop trough all the user repository and send notifications.
"""
now = rdwTime()
now = librdiff.RdiffTime()
def _user_repos():
"""Return a generator trought user repos to be notified."""
......
......@@ -34,7 +34,6 @@ from rdiffweb import rdw_spider_repos, page_main, librdiff
from rdiffweb.dispatch import poppath
from rdiffweb.i18n import ugettext as _
from rdiffweb.page_main import MainPage
from rdiffweb.rdw_helpers import rdwTime
from rdiffweb.rdw_plugin import IPreferencesPanelProvider, ITemplateFilterPlugin, \
IDeamonPlugin, JobPlugin
......@@ -126,7 +125,7 @@ class RemoveOlderPlugin(ITemplateFilterPlugin, JobPlugin):
if not r.last_backup_date:
_logger.info("no backup dates for [%r]", r.full_path)
return
d = rdwTime() - r.last_backup_date
d = librdiff.RdiffTime() - r.last_backup_date
d = d.days + keepdays
_logger.info("execute rdiff-backup --force --remove-older-than=%sD %r", d, r.full_path)
......
......@@ -35,7 +35,6 @@ from rdiffweb import rdw_spider_repos, page_main, librdiff
from rdiffweb.dispatch import poppath
from rdiffweb.i18n import ugettext as _
from rdiffweb.page_main import MainPage
from rdiffweb.rdw_helpers import rdwTime
from rdiffweb.rdw_plugin import IPreferencesPanelProvider, ITemplateFilterPlugin, \
IDeamonPlugin
......
......@@ -20,17 +20,8 @@ from __future__ import division
from __future__ import unicode_literals
from builtins import bytes
from builtins import map
from builtins import object
from builtins import str
import calendar
from future.utils import iteritems
from future.utils import python_2_unicode_compatible
from past.builtins import cmp
from past.utils import old_div
import time
from datetime import timedelta, datetime
try:
from urllib.parse import quote, unquote
......@@ -78,166 +69,6 @@ def unquote_url(url):
return val
@python_2_unicode_compatible
class rdwTime(object):
"""Time information has two components: the local time, stored in GMT as
seconds since Epoch, and the timezone, stored as a seconds offset. Since
the server may not be in the same timezone as the user, we cannot rely on
the built-in localtime() functions, but look at the rdiff-backup string
for timezone information. As a general rule, we always display the
"local" time, but pass the timezone information on to rdiff-backup, so
it can restore to the correct state"""
def __init__(self, value=None, tz_offset=None):
assert value is None or isinstance(value, int) or isinstance(value, str)
if value is None:
# Get GMT time.
self.timeInSeconds = int(time.time())
self.tzOffset = tz_offset or 0
elif isinstance(value, int):
self.timeInSeconds = value
self.tzOffset = tz_offset or 0
else:
self._initFromString(value)
def initFromMidnightUTC(self, daysFromToday):
self.timeInSeconds = time.time()
self.timeInSeconds -= self.timeInSeconds % (24 * 60 * 60)
self.timeInSeconds += daysFromToday * 24 * 60 * 60
self.tzOffset = 0
def _initFromString(self, timeString):
try:
date, daytime = timeString[:19].split("T")
year, month, day = list(map(int, date.split("-")))
hour, minute, second = list(map(int, daytime.split(":")))
assert 1900 < year < 2100, year
assert 1 <= month <= 12
assert 1 <= day <= 31
assert 0 <= hour <= 23
assert 0 <= minute <= 59
assert 0 <= second <= 61 # leap seconds
timetuple = (year, month, day, hour, minute, second, -1, -1, 0)
self.timeInSeconds = calendar.timegm(timetuple)
self.tzOffset = self._tzdtoseconds(timeString[19:])
self.getTimeZoneString() # to get assertions there
except (TypeError, ValueError, AssertionError):
raise ValueError(timeString)
def getLocalDaysSinceEpoch(self):
return self.getLocalSeconds() // (24 * 60 * 60)
def getLocalSeconds(self):
return self.timeInSeconds
def getSeconds(self):
return self.timeInSeconds - self.tzOffset
def getDisplayString(self):
value = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(self.getLocalSeconds()))
if isinstance(value, bytes):
value = value.decode(encoding='latin1')
return value
def getTimeZoneString(self):
if self.tzOffset:
tzinfo = self._getTimeZoneDisplayInfo()
return "%s%s:%s" % (tzinfo["plusMinus"], tzinfo["hours"], tzinfo["minutes"])
else:
return "Z"
def setTime(self, hour, minute, second):
year = time.gmtime(self.timeInSeconds)[0]
month = time.gmtime(self.timeInSeconds)[1]
day = time.gmtime(self.timeInSeconds)[2]
self.timeInSeconds = calendar.timegm(
(year, month, day, hour, minute, second, -1, -1, 0))
def _getTimeZoneDisplayInfo(self):
hours, minutes = divmod(old_div(abs(self.tzOffset), 60), 60)
assert 0 <= hours <= 23
assert 0 <= minutes <= 59
if self.tzOffset > 0:
plusMinus = "+"
else:
plusMinus = "-"
return {"plusMinus": plusMinus,
"hours": "%02d" % hours,
"minutes": "%02d" % minutes}
def _tzdtoseconds(self, tzd):
"""Given w3 compliant TZD, converts it to number of seconds from UTC"""
if tzd == "Z":
return 0
assert len(tzd) == 6 # only accept forms like +08:00 for now
assert (tzd[0] == "-" or tzd[0] == "+") and tzd[3] == ":"
if tzd[0] == "+":
plusMinus = 1
else:
plusMinus = -1
return plusMinus * 60 * (60 * int(tzd[1:3]) + int(tzd[4:]))
def __add__(self, other):
"""Support plus (+) timedelta"""
assert isinstance(other, timedelta)
return rdwTime(self.timeInSeconds + int(other.total_seconds()), self.tzOffset)
def __sub__(self, other):
"""Support minus (-) timedelta"""
assert isinstance(other, timedelta) or isinstance(other, rdwTime)
# Sub with timedelta, return rdwTime
if isinstance(other, timedelta):
return rdwTime(self.timeInSeconds - int(other.total_seconds()), self.tzOffset)
# Sub with rdwTime, return timedelta
if isinstance(other, rdwTime):
return timedelta(seconds=self.timeInSeconds - other.timeInSeconds)
def __int__(self):
"""Return this date as seconds since epoch."""
return self.timeInSeconds
def __lt__(self, other):
assert isinstance(other, rdwTime)
return self.getSeconds() < other.getSeconds()
def __le__(self, other):
assert isinstance(other, rdwTime)
return self.getSeconds() <= other.getSeconds()
def __gt__(self, other):
assert isinstance(other, rdwTime)
return self.getSeconds() > other.getSeconds()
def __ge__(self, other):
assert isinstance(other, rdwTime)
return self.getSeconds() >= other.getSeconds()
def __cmp__(self, other):
assert isinstance(other, rdwTime)
return cmp(self.getSeconds(), other.getSeconds())
def __eq__(self, other):
return (isinstance(other, rdwTime) and
self.getSeconds() == other.getSeconds())
def __hash__(self):
return hash(self.getSeconds())
def __str__(self):
"""return utf-8 string"""
return self.getDisplayString()
def __repr__(self):
"""return second since epoch"""
return str(self.getSeconds())
# Taken from ASPN:
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/259173
......
......@@ -24,13 +24,14 @@ from builtins import object
from builtins import str
from io import StringIO
from jinja2 import Environment, PackageLoader
from jinja2.filters import do_mark_safe
from jinja2.loaders import ChoiceLoader, FileSystemLoader
import logging
import time
from rdiffweb import i18n
from rdiffweb import librdiff
from rdiffweb import rdw_helpers
from jinja2.filters import do_mark_safe
# Define the logger
......@@ -98,7 +99,7 @@ def do_format_datetime(value, dateformat='%Y-%m-%d %H:%M'):
if not value:
return ""
if isinstance(value, rdw_helpers.rdwTime):
if isinstance(value, librdiff.RdiffTime):
value = value.getSeconds()
# TODO Try to figure out the time zone name (it's a )
......@@ -173,7 +174,7 @@ def url_for_history(repo):
def url_for_restore(repo, path, date, kind=None):
assert isinstance(repo, bytes)
assert path is None or isinstance(path, bytes)
assert isinstance(date, rdw_helpers.rdwTime)
assert isinstance(date, librdiff.RdiffTime)
url = []
url.append("/restore/")
if repo:
......@@ -202,7 +203,7 @@ def url_for_settings(repo):
def url_for_status_entry(date, repo=None):
assert isinstance(date, rdw_helpers.rdwTime)
assert isinstance(date, librdiff.RdiffTime)
url = []
url.append("/status/entry/")
if repo:
......
......@@ -26,18 +26,20 @@ Module used to test the librdiff.
from __future__ import unicode_literals
from builtins import bytes
from builtins import str
import datetime
from future.utils import native_str
import os
import pkg_resources
import shutil
import tarfile
import tempfile
import time
import unittest
from rdiffweb.librdiff import FileStatisticsEntry, RdiffRepo, \
DirEntry, IncrementEntry, SessionStatisticsEntry, HistoryEntry, \
AccessDeniedError, DoesNotExistError, FileError, UnknownError
from rdiffweb.rdw_helpers import rdwTime
AccessDeniedError, DoesNotExistError, FileError, UnknownError, RdiffTime
class MockRdiffRepo(RdiffRepo):
......@@ -64,13 +66,13 @@ class IncrementEntryTest(unittest.TestCase):
1414873850, 1414879639, 1414887165, 1414887491, 1414889478, 1414937803,
1414939853, 1414967021, 1415047607, 1415059497, 1415221262, 1415221470,
1415221495, 1415221507]
self.repo._backup_dates = [rdwTime(x) for x in backup_dates]
self.repo._backup_dates = [RdiffTime(x) for x in backup_dates]
self.root_path = self.repo.root_path
def test_init(self):
increment = IncrementEntry(self.root_path, b'my_filename.txt.2014-11-02T17:23:41-05:00.diff.gz')
self.assertEqual(rdwTime(1414967021), increment.date)
self.assertEqual(RdiffTime(1414967021), increment.date)
self.assertEqual(b'my_filename.txt', increment.filename)
self.assertIsNotNone(increment.repo)
......@@ -84,7 +86,7 @@ class DirEntryTest(unittest.TestCase):
1414873850, 1414879639, 1414887165, 1414887491, 1414889478, 1414937803,
1414939853, 1414967021, 1415047607, 1415059497, 1415221262, 1415221470,
1415221495, 1415221507]
self.repo._backup_dates = [rdwTime(x) for x in backup_dates]
self.repo._backup_dates = [RdiffTime(x) for x in backup_dates]
self.root_path = self.repo.root_path
def test_init(self):
......@@ -103,9 +105,9 @@ class DirEntryTest(unittest.TestCase):
entry = DirEntry(self.root_path, b'my_filename.txt', False, increments)
self.assertEqual(
[rdwTime(1414939853),
rdwTime(1414967021),
rdwTime(1415059497)],
[RdiffTime(1414939853),
RdiffTime(1414967021),
RdiffTime(1415059497)],
entry.change_dates)
def test_change_dates_with_exists(self):
......@@ -117,10 +119,10 @@ class DirEntryTest(unittest.TestCase):
entry = DirEntry(self.root_path, b'my_filename.txt', True, increments)
self.assertEqual(
[rdwTime(1414939853),
rdwTime(1414967021),
rdwTime(1415059497),
rdwTime(1415221507)],
[RdiffTime(1414939853),
RdiffTime(1414967021),
RdiffTime(1415059497),
RdiffTime(1415221507)],
entry.change_dates)
def test_display_name(self):
......@@ -221,11 +223,11 @@ class RdiffRepoTest(unittest.TestCase):
def test_extract_date(self):
self.assertEqual(rdwTime(1414967021), self.repo._extract_date(b'my_filename.txt.2014-11-02T17:23:41-05:00.diff.gz'))
self.assertEqual(RdiffTime(1414967021), self.repo._extract_date(b'my_filename.txt.2014-11-02T17:23:41-05:00.diff.gz'))
# Check if date with quoted characther are proerply parsed.
# On NTFS, colon (:) are not supported.
self.assertEqual(rdwTime(1483443123), self.repo._extract_date(b'my_filename.txt.2017-01-03T06;05832;05803-05;05800.diff.gz'))
self.assertEqual(RdiffTime(1483443123), self.repo._extract_date(b'my_filename.txt.2017-01-03T06;05832;05803-05;05800.diff.gz'))
def test_init(self):
self.assertEqual('testcases', self.repo.display_name)
......@@ -347,6 +349,63 @@ class SessionStatisticsEntryTest(unittest.TestCase):
self.assertEqual(0, entry.errors)
class RdiffTimeTest(unittest.TestCase):
def test_add(self):
"""Check if addition with timedelta is working as expected."""
# Without timezone
self.assertEqual(RdiffTime('2014-11-08T21:04:30Z'),
RdiffTime('2014-11-05T21:04:30Z') + datetime.timedelta(days=3))
# With timezone
self.assertEqual(RdiffTime('2014-11-08T21:04:30-04:00'),
RdiffTime('2014-11-05T21:04:30-04:00') + datetime.timedelta(days=3))
def test_compare(self):
"""Check behaviour of comparison operator operator."""
self.assertTrue(RdiffTime('2014-11-07T21:04:30-04:00') < RdiffTime('2014-11-08T21:04:30Z'))
self.assertTrue(RdiffTime('2014-11-08T21:04:30Z') < RdiffTime('2014-11-08T21:50:30Z'))
self.assertFalse(RdiffTime('2014-11-08T22:04:30Z') < RdiffTime('2014-11-08T21:50:30Z'))
self.assertFalse(RdiffTime('2014-11-07T21:04:30-04:00') > RdiffTime('2014-11-08T21:04:30Z'))
self.assertFalse(RdiffTime('2014-11-08T21:04:30Z') > RdiffTime('2014-11-08T21:50:30Z'))
self.assertTrue(RdiffTime('2014-11-08T22:04:30Z') > RdiffTime('2014-11-08T21:50:30Z'))
def test_init(self):
"""
Check various constructor.
"""
t0 = RdiffTime()
self.assertAlmostEqual(int(time.time()), t0.timeInSeconds, delta=5000)
t1 = RdiffTime(1415221470)
self.assertEqual(1415221470, t1.timeInSeconds)
t2 = RdiffTime('2014-11-05T21:04:30Z')
self.assertEqual(1415221470, t2.timeInSeconds)
def test_int(self):
"""Check if int(RdiffTime) return expected value."""
self.assertEqual(1415221470, int(RdiffTime(1415221470)))
def test_str(self):
"""Check if __str__ is working."""
self.assertEqual('2014-11-05 21:04:30', str(RdiffTime(1415221470)))