test_tzhelper.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. # # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Tests for L{twisted.python._tzhelper}.
  5. """
  6. from os import environ
  7. try:
  8. from time import tzset
  9. except ImportError:
  10. tzset = None
  11. from twisted.python._tzhelper import FixedOffsetTimeZone
  12. from twisted.trial.unittest import TestCase, SkipTest
  13. from datetime import timedelta
  14. from time import mktime as mktime_real
  15. # On some rare platforms (FreeBSD 8? I was not able to reproduce
  16. # on FreeBSD 9) 'mktime' seems to always fail once tzset() has been
  17. # called more than once in a process lifetime. I think this is
  18. # just a platform bug, so let's work around it. -glyph
  19. def mktime(t9):
  20. """
  21. Call L{mktime_real}, and if it raises L{OverflowError}, catch it and raise
  22. SkipTest instead.
  23. @param t9: A time as a 9-item tuple.
  24. @type t9: L{tuple}
  25. @return: A timestamp.
  26. @rtype: L{float}
  27. """
  28. try:
  29. return mktime_real(t9)
  30. except OverflowError:
  31. raise SkipTest(
  32. "Platform cannot construct time zone for {0!r}"
  33. .format(t9)
  34. )
  35. def setTZ(name):
  36. """
  37. Set time zone.
  38. @param name: a time zone name
  39. @type name: L{str}
  40. """
  41. if tzset is None:
  42. return
  43. if name is None:
  44. try:
  45. del environ["TZ"]
  46. except KeyError:
  47. pass
  48. else:
  49. environ["TZ"] = name
  50. tzset()
  51. def addTZCleanup(testCase):
  52. """
  53. Add cleanup hooks to a test case to reset timezone to original value.
  54. @param testCase: the test case to add the cleanup to.
  55. @type testCase: L{unittest.TestCase}
  56. """
  57. tzIn = environ.get("TZ", None)
  58. @testCase.addCleanup
  59. def resetTZ():
  60. setTZ(tzIn)
  61. class FixedOffsetTimeZoneTests(TestCase):
  62. """
  63. Tests for L{FixedOffsetTimeZone}.
  64. """
  65. def test_tzinfo(self):
  66. """
  67. Test that timezone attributes respect the timezone as set by the
  68. standard C{TZ} environment variable and L{tzset} API.
  69. """
  70. if tzset is None:
  71. raise SkipTest(
  72. "Platform cannot change timezone; unable to verify offsets."
  73. )
  74. def testForTimeZone(name, expectedOffsetDST, expectedOffsetSTD):
  75. setTZ(name)
  76. localDST = mktime((2006, 6, 30, 0, 0, 0, 4, 181, 1))
  77. localSTD = mktime((2007, 1, 31, 0, 0, 0, 2, 31, 0))
  78. tzDST = FixedOffsetTimeZone.fromLocalTimeStamp(localDST)
  79. tzSTD = FixedOffsetTimeZone.fromLocalTimeStamp(localSTD)
  80. self.assertEqual(
  81. tzDST.tzname(localDST),
  82. "UTC{0}".format(expectedOffsetDST)
  83. )
  84. self.assertEqual(
  85. tzSTD.tzname(localSTD),
  86. "UTC{0}".format(expectedOffsetSTD)
  87. )
  88. self.assertEqual(tzDST.dst(localDST), timedelta(0))
  89. self.assertEqual(tzSTD.dst(localSTD), timedelta(0))
  90. def timeDeltaFromOffset(offset):
  91. assert len(offset) == 5
  92. sign = offset[0]
  93. hours = int(offset[1:3])
  94. minutes = int(offset[3:5])
  95. if sign == "-":
  96. hours = -hours
  97. minutes = -minutes
  98. else:
  99. assert sign == "+"
  100. return timedelta(hours=hours, minutes=minutes)
  101. self.assertEqual(
  102. tzDST.utcoffset(localDST),
  103. timeDeltaFromOffset(expectedOffsetDST)
  104. )
  105. self.assertEqual(
  106. tzSTD.utcoffset(localSTD),
  107. timeDeltaFromOffset(expectedOffsetSTD)
  108. )
  109. addTZCleanup(self)
  110. # UTC
  111. testForTimeZone("UTC+00", "+0000", "+0000")
  112. # West of UTC
  113. testForTimeZone("EST+05EDT,M4.1.0,M10.5.0", "-0400", "-0500")
  114. # East of UTC
  115. testForTimeZone("CEST-01CEDT,M4.1.0,M10.5.0", "+0200", "+0100")
  116. # No DST
  117. testForTimeZone("CST+06", "-0600", "-0600")