def test_history_timestamp_abbreviations(): """Test timezone abbreviation support. """ abbrev = timestamp.support_abbreviations( 'CA', reset=True ) assert sorted( abbrev ) == ['ADT', 'AST', 'CDT', 'CST', 'EDT', 'EST', 'MDT', 'MST', 'NDT', 'NST', 'PDT', 'PST'] # Perform all the remaining timezone abbreviation tests relative to a known range of times, to # avoid differences in the future due to timezone changes. ts = timestamp( "2014-04-24 08:00:00 MDT" ) assert near( ts.value, 1398348000.0 ) # Try to add all of the Americas to the CA abbreviations already supported; can't be done (too # many inconsistencies) try: abbrev = timestamp.support_abbreviations( 'America' ) assert False, "Many zones should have been ambiguously abbreviated" except AmbiguousTimeZoneError as exc: assert "America/Mazatlan" in str( exc ) exclude = [ 'America/Mazatlan', 'America/Merida', 'America/Mexico_City', 'America/Monterrey', 'America/Bahia_Banderas', 'America/Cancun', 'America/Chihuahua', 'America/Havana', 'America/Santa_Isabel', 'America/Grand_Turk', 'America/Cayman', 'America/Port-au-Prince', 'America/Metlakatla', ] #print() #print( "America, w/o %r" % ( exclude )) abbrev = timestamp.support_abbreviations( 'America', exclude=exclude ) #print( sorted( abbrev )) #print( reprlib.repr( timestamp._tzabbrev )) pytz_version = tuple( map( int, pytz.__version__.split( '.' ))) if pytz_version < (2015,4): logging.warning( "pytz < 2015.4; HADT/HAST vs. HDT/HST" ) assert sorted( abbrev ) == ['ACT', 'AKDT', 'AKST', 'AMST', 'AMT', 'ART', 'BOT', 'BRST', 'BRT', 'CLST', 'CLT', 'COT', 'ECT', 'EGST', 'EGT', 'FNT', 'GFT', 'GMT', 'GYT', 'HADT', 'HAST', 'PET', 'PMDT', 'PMST', 'PYST', 'PYT', 'SRT', 'UYST', 'UYT', 'VET', 'WGST', 'WGT'] elif pytz_version < (2015,7): logging.warning( "pytz < 2015.7; had UYST" ) assert sorted( abbrev ) == ['ACT', 'AKDT', 'AKST', 'AMST', 'AMT', 'ART', 'BOT', 'BRST', 'BRT', 'CLST', 'CLT', 'COT', 'ECT', 'EGST', 'EGT', 'FNT', 'GFT', 'GMT', 'GYT', 'HDT', 'HST', 'PET', 'PMDT', 'PMST', 'PYST', 'PYT', 'SRT', 'UYST', 'UYT', 'VET', 'WGST', 'WGT'] elif pytz_version < (2017,2): assert sorted( abbrev ) == ['ACT', 'AKDT', 'AKST', 'AMST', 'AMT', 'ART', 'BOT', 'BRST', 'BRT', 'CLST', 'CLT', 'COT', 'ECT', 'EGST', 'EGT', 'FNT', 'GFT', 'GMT', 'GYT', 'HDT', 'HST', 'PET', 'PMDT', 'PMST', 'PYST', 'PYT', 'SRT', 'UYT', 'VET', 'WGST', 'WGT'] else: # As of pytz 2017.2, alot of these zones are now using time zones consistent with CA; only a few added. assert sorted( abbrev ) == ['AKDT', 'AKST', 'GMT', 'HDT', 'HST'] # We *can* add Europe/Berlin abbrev = timestamp.support_abbreviations( 'Europe/Berlin' ) assert sorted( abbrev ) == ['CEST', 'CET'] assert 'CEST' in timestamp._tzabbrev assert 'EEST' not in timestamp._tzabbrev # And all of Europe, w/o some troublesome time zones exclude = [ 'Europe/Simferopol', 'Europe/Istanbul', 'Europe/Minsk', 'Europe/Chisinau', 'Europe/Dublin' ] #print() #print( "Europe, w/o %r" % ( exclude )) abbrev = timestamp.support_abbreviations( 'Europe', exclude=exclude ) #print( sorted( abbrev )) if pytz_version < (2015,2): assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'MSK', 'SAMT', 'WEST', 'WET'] elif pytz_version < (2016,3): assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'IST', 'MSK', 'SAMT', 'WEST', 'WET'] elif pytz_version < (2016,7): assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'IST', 'MSK', 'SAMT', 'WEST', 'WET'] elif pytz_version < (2018,5): assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'IST', 'MSK', 'WEST', 'WET'] else: assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'MSK', 'WEST', 'WET'] assert 'EEST' in timestamp._tzabbrev try: timestamp.support_abbreviations( 'Asia' ) assert False, "Asia/Jerusalem IST should have mismatched Europe/Dublin IST" except AmbiguousTimeZoneError as exc: assert "Asia/Jerusalem" in str( exc ) assert near( parse_offset( '< 1:00:00.001' ), -3600.001 ) assert near( parse_offset( '<:1.001' ), -1.001 ) assert near( parse_offset( '>1:0.001' ), 60.001 ) assert near( parse_offset( '>1' ), 1 ) # While Asia is internally very inconsistent (eg. EEST), countries should be internally consisent abbrev = timestamp.support_abbreviations( 'JO', reset=True ) # Jordan #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'EEST', 'EET'] z,dst,off = timestamp._tzabbrev['EEST'] assert str(z) == 'Asia/Amman' and dst == True and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 3:00:00" abbrev = timestamp.support_abbreviations( 'IE', reset=True ) # Israel #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'GMT', 'IST' ] # Jordan, Israel and Lebanon only work if we pick a region to exclude, for one EEST definition abbrev = timestamp.support_abbreviations( ['JO', 'IE', 'LB'], exclude=[ 'Asia/Amman' ], reset=True ) #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'EEST', 'EET', 'GMT', 'IST' ] z,dst,off = timestamp._tzabbrev['EEST'] assert str(z) == 'Asia/Beirut' and dst == True and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 3:00:00" # Australia zones incompatible with a bunch of other timezone abbreviations, eg. CST; reset abbrev = timestamp.support_abbreviations( 'Australia', reset=True ) #print( sorted( abbrev )) #print( repr( timestamp._tzabbrev )) if pytz_version < (2017,2): assert sorted( abbrev ) == ['ACDT', 'ACST', 'ACWST', 'AEDT', 'AEST', 'AWST', 'LHDT', 'LHST'] z,dst,off = timestamp._tzabbrev['LHST'] assert str(z) == 'Australia/Lord_Howe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == ">10:30:00" else: assert sorted( abbrev ) == ['ACDT', 'ACST', 'AEDT', 'AEST', 'AWST'] # Ensure that non-ambiguous (DST-specific) zone abbreviations override ambiguous (no longer # relevant, as pytz >= 2014.7 no longer contains dst == None for some of the Australian zones # without DST) abbrev = timestamp.support_abbreviations( [ 'Australia/Adelaide' ], reset=True ) assert sorted( abbrev ) == [ 'ACDT', 'ACST' ] z,dst,off = timestamp._tzabbrev['ACST'] assert str(z) == 'Australia/Adelaide' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 9:30:00" abbrev = timestamp.support_abbreviations( [ 'Australia/Adelaide', 'Australia/Darwin' ], reset=True ) #print( sorted( abbrev )) #print( repr( timestamp._tzabbrev )) z,dst,off = timestamp._tzabbrev['ACST'] assert str(z) in ( 'Australia/Darwin', 'Australia/Adelaide' ) and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 9:30:00" # Check that zones with complete, permanent offset changes (not just DST) are handled. We know # that within a year of 2014-04-28, the America/Eirunepe (west Amazonas) zone had such a change # (pre pytz 2017.2, anyway...) if pytz_version < (2017,2): abbrev = timestamp.support_abbreviations( [ 'America/Eirunepe' ], at=datetime.datetime( 2014, 4, 28 ), reset=True) #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'ACT', 'AMT' ] z,dst,off = timestamp._tzabbrev['ACT'] assert str(z) == 'America/Eirunepe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "< 5:00:00" z,dst,off = timestamp._tzabbrev['AMT'] assert str(z) == 'America/Eirunepe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "< 4:00:00"
def test_history_timestamp(): """Test timestamp, ensuring comparison deals in UTC only. Supports testing in local timezones: Canada/Edmonton -- A generic, ambiguous DST/non-DST timezone MST -- A DST-specific non-DST timezone UTC -- UTC """ trtab = ( string if sys.version_info[0] < 3 else str ).maketrans( ":-.", " " ) def utc_strp( loctime ): if '.' in loctime: unaware = datetime.datetime.strptime( loctime, timestamp._fmt + ".%f" ) else: unaware = datetime.datetime.strptime( loctime, timestamp._fmt ) return pytz.utc.localize( unaware ) def utc_trns( loctime ): terms = loctime.translate( trtab ).split() if len( terms ) == 7: # convert .123 into 123000 microseconds terms[6] += '0' * ( 6 - len( terms[6] )) return datetime.datetime( *map( int, terms ), tzinfo=pytz.utc ) # Basic millisecond hygiene. Comparisons are by standard UTC format to 3 sub-second decimal # places of precision. Unfortunately, the Python 2/3 strftime microsecond formatters are # different, so we don't use them. If no precision, we do NOT round; we truncate, to avoid the # surprising effect of formatting a UNIX value manually using strftime produces a different # second than formatting it using render() with no sub-second precision. assert timestamp( 1399326141.999836 ) >= timestamp( 1399326141.374836 ) assert timestamp( 1399326141.999836 ).render( ms=False ) == '2014-05-05 21:42:21' assert timestamp( 1399326141.999836 ).render( ms=5 ) == '2014-05-05 21:42:21.99984' assert timestamp( 1399326141.999836 ).render() == '2014-05-05 21:42:22.000' # Type caste support assert abs( float( timestamp( 1399326141.999836 )) - 1399326141.999836 ) < 1e-6 assert int( timestamp( 1399326141.999836 )) == 1399326141 # Adjust timestamp default precision and comparison epsilon. save = timestamp._precision,timestamp._epsilon try: ts = timestamp( 1399326141.999836 ) for p in range( 0, 7 ): timestamp._precision= p timestamp._epsilon = 10**-p if p else 0 assert ts.render( ms=True ) == { 0: '2014-05-05 21:42:21', # Truncates at 0 digits of sub-second precision 1: '2014-05-05 21:42:22.0', 2: '2014-05-05 21:42:22.00', 3: '2014-05-05 21:42:22.000', 4: '2014-05-05 21:42:21.9998', 5: '2014-05-05 21:42:21.99984', 6: '2014-05-05 21:42:21.999836', }[timestamp._precision] # For p == 0, try exact precision. 1e-6 is the smallest delta that can be reliably # added to a typical UNIX timestamp (eg. 1399326141.999836) in a double and still # expect it to affect the value (can store 15-17 decimal digits of precision). s,l = (timestamp._epsilon*f for f in (0.9,1.1)) if p else (0,10**-6) assert ts == ts + s assert ts == ts - s assert not(ts == ts + l) assert not(ts == ts - l) assert ts != ts + l assert ts != ts - l assert not(ts < ts + s) assert not(ts < ts - s) assert ts < ts + l assert not(ts < ts - l) assert ts <= ts + s assert ts <= ts - s assert ts <= ts + l assert not(ts <= ts - l) assert not(ts > ts + s) assert not(ts > ts - s) assert not(ts > ts + l) assert ts > ts - l assert ts >= ts + s assert ts >= ts - s assert not(ts >= ts + l) assert ts >= ts - l finally: timestamp._precision,timestamp._epsilon = save # Maintain DST specificity when rendering in DST-specific timezones? Nope, only when using # specially constructed non-DST versions of timezones, when they are made available by pytz. timestamp.support_abbreviations( None, reset=True ) assert timestamp.timezone_info('MST') == (pytz.timezone( 'MST' ),None) assert timestamp( 1399326141.999836 ).render( tzinfo='MST', ms=False ) == '2014-05-05 14:42:21 MST' # Get MST/MDT etc., and CET/CEST abbreviations timestamp.support_abbreviations( ['CA','Europe/Berlin'], reset=True ) assert timestamp.timezone_info('MST') == (pytz.timezone( 'America/Edmonton' ),False) assert timestamp( 1399326141.999836 ).render( tzinfo='MST', ms=False ) == '2014-05-05 15:42:21 MDT' # $ TZ=UTC date --date=@1388559600 # Wed Jan 1 07:00:00 UTC 2014 # 1396531199 # Thu Apr 3 07:19:59 MDT 2014 assert '2014-01-02 03:04:55.123'.translate( trtab ) == '2014 01 02 03 04 55 123' cnt = 10000 beg = timer() for _ in range( cnt ): utc1 = utc_strp( '2014-01-02 03:04:55.123' ) dur1 = timer() - beg beg = timer() for _ in range( cnt ): utc2 = utc_trns( '2014-01-02 03:04:55.123' ) dur2 = timer() - beg beg = timer() for _ in range( cnt ): utc3 = timestamp.datetime_from_string( '2014-01-02 03:04:55.123' ) dur3 = timer() - beg assert utc1.strftime( timestamp._fmt ) \ == utc2.strftime( timestamp._fmt ) \ == utc3.strftime( timestamp._fmt ) == '2014-01-02 03:04:55' logging.detail( "strptime: %d/s, translate: %d/s, timestamp: %d/s", cnt/dur1, cnt/dur2, cnt/dur3 ) now = timer() assert timestamp( now ) < timestamp( now + 1 ) # From a numeric timestamp ts = timestamp( 1396531199 ) assert ts.utc == '2014-04-03 13:19:59.000' == str( ts ) assert ts.local in ( '2014-04-03 07:19:59 MDT', '2014-04-03 06:19:59 MST', '2014-04-03 13:19:59 UTC' ) # From a string UTC time dt = timestamp.datetime_from_string( '2014-01-01 07:00:00.0' ) assert str( dt ) == '2014-01-01 07:00:00+00:00' assert repr( dt ) == 'datetime.datetime(2014, 1, 1, 7, 0, tzinfo=<UTC>)' #assert dt.strftime( '%s' ) != '1388559600' # !? (will fail if machine is in UTC timezone ) #assert pytz.utc.normalize( dt ).strftime( '%s' ) != '1388559600' # !? assert 1388559559.999999 < timestamp.number_from_datetime( dt ) < 1388559600.000001 # ok ts = timestamp( '2014-01-01 07:00:00.0' ) assert 1388559559.999999 < ts.value < 1388559600.000001 assert ts.utc == '2014-01-01 07:00:00.000' == str( ts ) assert ts.local in ( '2014-01-01 00:00:00 MST', '2014-01-01 07:00:00 UTC' ) # OK, now try a UTC time where the local timezone is in MDT ts.utc = '2014-04-01 07:00:00.000' assert ts.local in ( '2014-04-01 01:00:00 MDT', '2014-04-01 00:00:00 MST', '2014-04-01 07:00:00 UTC' ) # Make sure that local times are unambiguous over daylight savings time # Mar 9 02:00 -> 03:00 1394355540 == Mar 9 2014 01:59 # Nov 2 02:00 -> 01:00 1414915140 == Nov 2 2014 01:59 ts = timestamp( 1394355540 ) assert ts.local in ( '2014-03-09 01:59:00 MST', '2014-03-09 08:59:00 UTC' ) ts += 61 assert ts.local in ( '2014-03-09 03:00:01 MDT', '2014-03-09 02:00:01 MST', '2014-03-09 09:00:01 UTC' ) ts = timestamp( 1414915140 ) assert ts.local in ( '2014-11-02 01:59:00 MDT', '2014-11-02 00:59:00 MST', '2014-11-02 07:59:00 UTC' ) ts += 61 assert ts.local in ( '2014-11-02 01:00:01 MST', '2014-03-09 02:00:01 MST', '2014-11-02 08:00:01 UTC' ) # Now try converting a few strings that have a specific timezone. We can use either .utc = # ... or .local = ...; they just default to the UTC or (local) timezone, respectively. Using a # DST-specific timezone such as MST/MDT, we can unambiguously specify whether a time is inside # or outside DST. try: ts.local = '2014-03-09 02:00:01 America/Edmonton' # Just inside MDT 2014 assert False, """Should have failed -- time doesn't exist during "spring ahead" """ except Exception as exc: assert "NonExistentTimeError" in str( exc ) ts.local = '2014-03-09 03:00:01 MDT' # Just inside MDT 2014 assert 1394355600.999999 < ts.value < 1394355601.000001 assert ts.utc == '2014-03-09 09:00:01.000' # MDT == UCT-6:00 assert ts.local in ( '2014-03-09 03:00:01 MDT', '2014-03-09 02:00:01 MST', '2014-03-09 09:00:01 UTC' ) # However, we CAN use a specifically non-DST timezone to specify times non-existent in DST ts.local = '2014-03-09 02:00:01 MST' # No such time in MDT!! assert 1394355600.999999 < ts.value < 1394355601.000001 assert ts.utc == '2014-03-09 09:00:01.000' assert ts.local in ( '2014-03-09 03:00:01 MDT', '2014-03-09 02:00:01 MST', '2014-03-09 09:00:01 UTC' ) ts.local = '2014-11-02 01:00:01 MST' # 1 second after the end of DST assert 1414915200.999999 < ts.value < 1414915201.000001 assert ts.utc == '2014-11-02 08:00:01.000' assert ts.local in ( '2014-11-02 01:00:01 MST', '2014-11-02 00:59:59 MST', '2014-11-02 08:00:01 UTC' ) ts -= 2 # Go back 2 seconds, into DST assert ts.utc == '2014-11-02 07:59:59.000' assert ts.local in ( '2014-11-02 01:59:59 MDT', '2014-11-02 00:59:59 MST', '2014-11-02 07:59:59 UTC' ) ts.local = '2014-11-02 01:59:58 MDT' # 2 seconds before end of DST assert 1414915197.999999 < ts.value < 1414915198.000001 assert ts.utc == '2014-11-02 07:59:58.000' assert ts.local in ( '2014-11-02 01:59:58 MDT', '2014-11-02 00:59:58 MST', '2014-11-02 07:59:58 UTC' ) # Using a canonical timezone such as 'America/Edmonton', an "ambiguous" time (eg. during the # overlap in the fall) cannot be specified. Using a DST-specific timezone, we can. try: ts.local = '2014-11-02 01:00:01 America/Edmonton' # Inside DST? except Exception as exc: assert "AmbiguousTimeError" in str( exc ) ts.local = '2014-11-02 00:59:59 America/Edmonton' # 2 seconds before end of DST assert 1414911598.999999 < ts.value < 1414911599.000001 assert ts.utc == '2014-11-02 06:59:59.000' assert ts.local in ( '2014-11-02 00:59:59 MDT', '2014-11-01 23:59:59 MST', '2014-11-02 06:59:59 UTC' ) after = timestamp( '2014-11-02 01:02:03.123 MST' ) # (Nov 2 2014 -- 1:02 *after* DST ended) before = timestamp( '2014-11-02 01:02:03.456 MDT' ) # (Nov 2 2014 -- :58 *before* DST ends) assert before < after assert before.utc == '2014-11-02 07:02:03.456' assert before.local in ( '2014-11-02 01:02:03 MDT', '2014-11-02 00:02:03 MST', '2014-11-02 07:02:03 UTC' ) assert after.utc == '2014-11-02 08:02:03.123' assert after.local in ( '2014-11-02 01:02:03 MST', '2014-11-02 08:02:03 UTC' ) after = timestamp( '2014-10-26 02:01:00.123 CET' ) # (Nov 26 2014 -- 1:02 *after* DST ended) before = timestamp( '2014-10-26 02:01:00.456 CEST' ) # (Nov 26 2014 -- :58 *before* DST ends) assert before < after assert before.utc == '2014-10-26 00:01:00.456' assert before.local in ( '2014-10-25 18:01:00 MDT', '2014-10-25 17:01:00 MST', '2014-10-26 00:01:00 UTC' ) assert after.utc == '2014-10-26 01:01:00.123' assert after.local in ( '2014-10-25 19:01:00 MDT', '2014-10-25 18:01:00 MST', '2014-10-26 01:01:00 UTC' )
def test_history_timestamp_abbreviations(): """Test timezone abbreviation support. """ abbrev = timestamp.support_abbreviations( 'CA', reset=True ) assert sorted( abbrev ) == ['ADT', 'AST', 'CDT', 'CST', 'EDT', 'EST', 'MDT', 'MST', 'NDT', 'NST', 'PDT', 'PST'] # Perform all the remaining timezone abbreviation tests relative to a known range of times, to # avoid differences in the future due to timezone changes. ts = timestamp( "2014-04-24 08:00:00 MDT" ) assert near( ts.value, 1398348000.0 ) try: abbrev = timestamp.support_abbreviations( 'America' ) assert False, "Many zones should have been ambiguously abbreviated" except AmbiguousTimeZoneError as exc: assert "America/Mazatlan" in str( exc ) abbrev = timestamp.support_abbreviations( 'America', exclude=['America/Mazatlan', 'America/Merida', 'America/Mexico_City', 'America/Monterrey', 'America/Bahia_Banderas', 'America/Cancun', 'America/Chihuahua', 'America/Havana', 'America/Santa_Isabel', 'America/Grand_Turk'] ) #print( sorted( abbrev )) #print( reprlib.repr( timestamp._tzabbrev )) assert sorted( abbrev ) == ['ACT', 'AKDT', 'AKST', 'AMST', 'AMT', 'ART', 'BOT', 'BRST', 'BRT', 'CLST', 'CLT', 'COT', 'ECT', 'EGST', 'EGT', 'FNT', 'GFT', 'GMT', 'GYT', 'HADT', 'HAST', 'PET', 'PMDT', 'PMST', 'PYST', 'PYT', 'SRT', 'UYST', 'UYT', 'VET', 'WGST', 'WGT'] abbrev = timestamp.support_abbreviations( 'Europe/Berlin' ) assert sorted( abbrev ) == ['CEST', 'CET'] assert 'CEST' in timestamp._tzabbrev assert 'EEST' not in timestamp._tzabbrev abbrev = timestamp.support_abbreviations( 'Europe', exclude=[ 'Europe/Simferopol', 'Europe/Istanbul', 'Europe/Minsk' ] ) #print( sorted( abbrev )) assert sorted( abbrev ) == ['BST', 'EEST', 'EET', 'FET', 'IST', 'MSK', 'SAMT', 'WEST', 'WET'] assert 'EEST' in timestamp._tzabbrev try: timestamp.support_abbreviations( 'Asia' ) assert False, "Asia/Jerusalem IST should have mismatched Europe/Dublin IST" except AmbiguousTimeZoneError as exc: assert "Asia/Jerusalem" in str( exc ) assert near( parse_offset( '< 1:00:00.001' ), -3600.001 ) assert near( parse_offset( '<:1.001' ), -1.001 ) assert near( parse_offset( '>1:0.001' ), 60.001 ) assert near( parse_offset( '>1' ), 1 ) # While Asia is internally very inconsistent (eg. EEST), countries should be internally consisent abbrev = timestamp.support_abbreviations( 'JO', reset=True ) # Jordan #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'EEST', 'EET'] z,dst,off = timestamp._tzabbrev['EEST'] assert str(z) == 'Asia/Amman' and dst == True and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 3:00:00" abbrev = timestamp.support_abbreviations( 'IE', reset=True ) # Israel #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'GMT', 'IST' ] # Jordan, Israel and Lebanon only work if we pick a region to exclude, for one EEST definition abbrev = timestamp.support_abbreviations( ['JO', 'IE', 'LB'], exclude=[ 'Asia/Amman' ], reset=True ) #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'EEST', 'EET', 'GMT', 'IST' ] z,dst,off = timestamp._tzabbrev['EEST'] assert str(z) == 'Asia/Beirut' and dst == True and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 3:00:00" # Australia zones incompatible with a bunch of other timezone abbreviations, eg. CST; reset abbrev = timestamp.support_abbreviations( 'Australia', reset=True ) #print( sorted( abbrev )) #print( repr( timestamp._tzabbrev )) assert sorted( abbrev ) == ['ACDT', 'ACST', 'ACWST', 'AEDT', 'AEST', 'AWST', 'LHDT', 'LHST'] z,dst,off = timestamp._tzabbrev['LHST'] assert str(z) == 'Australia/Lord_Howe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == ">10:30:00" # Ensure that non-ambiguous (DST-specific) zone abbreviations override ambiguous (no longer # relevant, as pytz >= 2014.7 no longer contains dst == None for some of the Australian zones # without DST) abbrev = timestamp.support_abbreviations( [ 'Australia/Adelaide' ], reset=True ) #print( sorted( abbrev )) # ['ACDT', 'ACST'] z,dst,off = timestamp._tzabbrev['ACST'] assert str(z) == 'Australia/Adelaide' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 9:30:00" abbrev = timestamp.support_abbreviations( [ 'Australia/Adelaide', 'Australia/Darwin' ], reset=True ) #print( sorted( abbrev )) #print( repr( timestamp._tzabbrev )) z,dst,off = timestamp._tzabbrev['ACST'] assert str(z) in ( 'Australia/Darwin', 'Australia/Adelaide' ) and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "> 9:30:00" # Check that zones with complete, permanent offset changes (not just DST) are handled. We know # that within a year of 2014-04-28, the America/Eirunepe (west Amazonas) zone had such a change. abbrev = timestamp.support_abbreviations( [ 'America/Eirunepe' ], at=datetime.datetime( 2014, 4, 28 )) #print( sorted( abbrev )) assert sorted( abbrev ) == [ 'ACT', 'AMT' ] z,dst,off = timestamp._tzabbrev['ACT'] assert str(z) == 'America/Eirunepe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "< 5:00:00" z,dst,off = timestamp._tzabbrev['AMT'] assert str(z) == 'America/Eirunepe' and dst == False and format_offset( timedelta_total_seconds( off ), ms=None ) == "< 4:00:00"
def test_history_timestamp_abbreviations(): """Test timezone abbreviation support. """ abbrev = timestamp.support_abbreviations("CA", reset=True) assert sorted(abbrev) == ["ADT", "AST", "CDT", "CST", "EDT", "EST", "MDT", "MST", "NDT", "NST", "PDT", "PST"] # Perform all the remaining timezone abbreviation tests relative to a known range of times, to # avoid differences in the future due to timezone changes. ts = timestamp("2014-04-24 08:00:00 MDT") assert near(ts.value, 1398348000.0) try: abbrev = timestamp.support_abbreviations("America") assert False, "Many zones should have been ambiguously abbreviated" except AmbiguousTimeZoneError as exc: assert "America/Mazatlan" in str(exc) abbrev = timestamp.support_abbreviations( "America", exclude=[ "America/Mazatlan", "America/Merida", "America/Mexico_City", "America/Monterrey", "America/Bahia_Banderas", "America/Cancun", "America/Chihuahua", "America/Havana", "America/Santa_Isabel", "America/Grand_Turk", "America/Cayman", ], ) # print( sorted( abbrev )) # print( reprlib.repr( timestamp._tzabbrev )) if tuple(map(int, pytz.__version__.split("."))) < (2015, 4): logging.warning("pytz < 2015.4; HADT/HAST vs. HDT/HST") assert sorted(abbrev) == [ "ACT", "AKDT", "AKST", "AMST", "AMT", "ART", "BOT", "BRST", "BRT", "CLST", "CLT", "COT", "ECT", "EGST", "EGT", "FNT", "GFT", "GMT", "GYT", "HADT", "HAST", "PET", "PMDT", "PMST", "PYST", "PYT", "SRT", "UYST", "UYT", "VET", "WGST", "WGT", ] else: assert sorted(abbrev) == [ "ACT", "AKDT", "AKST", "AMST", "AMT", "ART", "BOT", "BRST", "BRT", "CLST", "CLT", "COT", "ECT", "EGST", "EGT", "FNT", "GFT", "GMT", "GYT", "HDT", "HST", "PET", "PMDT", "PMST", "PYST", "PYT", "SRT", "UYST", "UYT", "VET", "WGST", "WGT", ] abbrev = timestamp.support_abbreviations("Europe/Berlin") assert sorted(abbrev) == ["CEST", "CET"] assert "CEST" in timestamp._tzabbrev assert "EEST" not in timestamp._tzabbrev abbrev = timestamp.support_abbreviations( "Europe", exclude=["Europe/Simferopol", "Europe/Istanbul", "Europe/Minsk", "Europe/Chisinau"] ) # print( sorted( abbrev )) assert sorted(abbrev) == ["BST", "EEST", "EET", "IST", "MSK", "SAMT", "WEST", "WET"] assert "EEST" in timestamp._tzabbrev try: timestamp.support_abbreviations("Asia") assert False, "Asia/Jerusalem IST should have mismatched Europe/Dublin IST" except AmbiguousTimeZoneError as exc: assert "Asia/Jerusalem" in str(exc) assert near(parse_offset("< 1:00:00.001"), -3600.001) assert near(parse_offset("<:1.001"), -1.001) assert near(parse_offset(">1:0.001"), 60.001) assert near(parse_offset(">1"), 1) # While Asia is internally very inconsistent (eg. EEST), countries should be internally consisent abbrev = timestamp.support_abbreviations("JO", reset=True) # Jordan # print( sorted( abbrev )) assert sorted(abbrev) == ["EEST", "EET"] z, dst, off = timestamp._tzabbrev["EEST"] assert ( str(z) == "Asia/Amman" and dst == True and format_offset(timedelta_total_seconds(off), ms=None) == "> 3:00:00" ) abbrev = timestamp.support_abbreviations("IE", reset=True) # Israel # print( sorted( abbrev )) assert sorted(abbrev) == ["GMT", "IST"] # Jordan, Israel and Lebanon only work if we pick a region to exclude, for one EEST definition abbrev = timestamp.support_abbreviations(["JO", "IE", "LB"], exclude=["Asia/Amman"], reset=True) # print( sorted( abbrev )) assert sorted(abbrev) == ["EEST", "EET", "GMT", "IST"] z, dst, off = timestamp._tzabbrev["EEST"] assert ( str(z) == "Asia/Beirut" and dst == True and format_offset(timedelta_total_seconds(off), ms=None) == "> 3:00:00" ) # Australia zones incompatible with a bunch of other timezone abbreviations, eg. CST; reset abbrev = timestamp.support_abbreviations("Australia", reset=True) # print( sorted( abbrev )) # print( repr( timestamp._tzabbrev )) assert sorted(abbrev) == ["ACDT", "ACST", "ACWST", "AEDT", "AEST", "AWST", "LHDT", "LHST"] z, dst, off = timestamp._tzabbrev["LHST"] assert ( str(z) == "Australia/Lord_Howe" and dst == False and format_offset(timedelta_total_seconds(off), ms=None) == ">10:30:00" ) # Ensure that non-ambiguous (DST-specific) zone abbreviations override ambiguous (no longer # relevant, as pytz >= 2014.7 no longer contains dst == None for some of the Australian zones # without DST) abbrev = timestamp.support_abbreviations(["Australia/Adelaide"], reset=True) # print( sorted( abbrev )) # ['ACDT', 'ACST'] z, dst, off = timestamp._tzabbrev["ACST"] assert ( str(z) == "Australia/Adelaide" and dst == False and format_offset(timedelta_total_seconds(off), ms=None) == "> 9:30:00" ) abbrev = timestamp.support_abbreviations(["Australia/Adelaide", "Australia/Darwin"], reset=True) # print( sorted( abbrev )) # print( repr( timestamp._tzabbrev )) z, dst, off = timestamp._tzabbrev["ACST"] assert ( str(z) in ("Australia/Darwin", "Australia/Adelaide") and dst == False and format_offset(timedelta_total_seconds(off), ms=None) == "> 9:30:00" ) # Check that zones with complete, permanent offset changes (not just DST) are handled. We know # that within a year of 2014-04-28, the America/Eirunepe (west Amazonas) zone had such a change. abbrev = timestamp.support_abbreviations(["America/Eirunepe"], at=datetime.datetime(2014, 4, 28)) # print( sorted( abbrev )) assert sorted(abbrev) == ["ACT", "AMT"] z, dst, off = timestamp._tzabbrev["ACT"] assert ( str(z) == "America/Eirunepe" and dst == False and format_offset(timedelta_total_seconds(off), ms=None) == "< 5:00:00" ) z, dst, off = timestamp._tzabbrev["AMT"] assert ( str(z) == "America/Eirunepe" and dst == False and format_offset(timedelta_total_seconds(off), ms=None) == "< 4:00:00" )