1
1
""" define extension dtypes """
2
-
3
2
import re
3
+ import warnings
4
4
5
5
import numpy as np
6
+ import pytz
6
7
7
8
from pandas ._libs .interval import Interval
8
9
from pandas ._libs .tslibs import NaT , Period , Timestamp , timezones
@@ -491,64 +492,69 @@ class DatetimeTZDtype(PandasExtensionDtype):
491
492
_match = re .compile (r"(datetime64|M8)\[(?P<unit>.+), (?P<tz>.+)\]" )
492
493
_cache = {}
493
494
494
- def __new__ ( cls , unit = None , tz = None ):
495
+ def __init__ ( self , unit = "ns" , tz = None ):
495
496
"""
496
- Create a new unit if needed, otherwise return from the cache
497
+ An ExtensionDtype for timezone-aware datetime data.
497
498
498
499
Parameters
499
500
----------
500
- unit : string unit that this represents, currently must be 'ns'
501
- tz : string tz that this represents
502
- """
503
-
504
- if isinstance (unit , DatetimeTZDtype ):
505
- unit , tz = unit .unit , unit .tz
506
-
507
- elif unit is None :
508
- # we are called as an empty constructor
509
- # generally for pickle compat
510
- return object .__new__ (cls )
501
+ unit : str, default "ns"
502
+ The precision of the datetime data. Currently limited
503
+ to ``"ns"``.
504
+ tz : str, int, or datetime.tzinfo
505
+ The timezone.
511
506
512
- elif tz is None :
507
+ Raises
508
+ ------
509
+ pytz.UnknownTimeZoneError
510
+ When the requested timezone cannot be found.
513
511
514
- # we were passed a string that we can construct
515
- try :
516
- m = cls ._match .search (unit )
517
- if m is not None :
518
- unit = m .groupdict ()['unit' ]
519
- tz = timezones .maybe_get_tz (m .groupdict ()['tz' ])
520
- except TypeError :
521
- raise ValueError ("could not construct DatetimeTZDtype" )
512
+ Examples
513
+ --------
514
+ >>> pd.core.dtypes.dtypes.DatetimeTZDtype(tz='UTC')
515
+ datetime64[ns, UTC]
522
516
523
- elif isinstance (unit , compat .string_types ):
517
+ >>> pd.core.dtypes.dtypes.DatetimeTZDtype(tz='dateutil/US/Central')
518
+ datetime64[ns, tzfile('/usr/share/zoneinfo/US/Central')]
519
+ """
520
+ if isinstance (unit , DatetimeTZDtype ):
521
+ unit , tz = unit .unit , unit .tz
524
522
525
- if unit != 'ns' :
523
+ if unit != 'ns' :
524
+ if isinstance (unit , compat .string_types ) and tz is None :
525
+ # maybe a string like datetime64[ns, tz], which we support for
526
+ # now.
527
+ result = type (self ).construct_from_string (unit )
528
+ unit = result .unit
529
+ tz = result .tz
530
+ msg = (
531
+ "Passing a dtype alias like 'datetime64[ns, {tz}]' "
532
+ "to DatetimeTZDtype is deprecated. Use "
533
+ "'DatetimeTZDtype.construct_from_string()' instead."
534
+ )
535
+ warnings .warn (msg .format (tz = tz ), FutureWarning , stacklevel = 2 )
536
+ else :
526
537
raise ValueError ("DatetimeTZDtype only supports ns units" )
527
538
528
- unit = unit
529
- tz = tz
539
+ if tz :
540
+ tz = timezones .maybe_get_tz (tz )
541
+ elif tz is not None :
542
+ raise pytz .UnknownTimeZoneError (tz )
543
+ elif tz is None :
544
+ raise TypeError ("A 'tz' is required." )
530
545
531
- if tz is None :
532
- raise ValueError ("DatetimeTZDtype constructor must have a tz "
533
- "supplied" )
546
+ self ._unit = unit
547
+ self ._tz = tz
534
548
535
- # hash with the actual tz if we can
536
- # some cannot be hashed, so stringfy
537
- try :
538
- key = (unit , tz )
539
- hash (key )
540
- except TypeError :
541
- key = (unit , str (tz ))
549
+ @property
550
+ def unit (self ):
551
+ """The precision of the datetime data."""
552
+ return self ._unit
542
553
543
- # set/retrieve from cache
544
- try :
545
- return cls ._cache [key ]
546
- except KeyError :
547
- u = object .__new__ (cls )
548
- u .unit = unit
549
- u .tz = tz
550
- cls ._cache [key ] = u
551
- return u
554
+ @property
555
+ def tz (self ):
556
+ """The timezone."""
557
+ return self ._tz
552
558
553
559
@classmethod
554
560
def construct_array_type (cls ):
@@ -565,24 +571,42 @@ def construct_array_type(cls):
565
571
@classmethod
566
572
def construct_from_string (cls , string ):
567
573
"""
568
- attempt to construct this type from a string, raise a TypeError if
569
- it's not possible
574
+ Construct a DatetimeTZDtype from a string.
575
+
576
+ Parameters
577
+ ----------
578
+ string : str
579
+ The string alias for this DatetimeTZDtype.
580
+ Should be formatted like ``datetime64[ns, <tz>]``,
581
+ where ``<tz>`` is the timezone name.
582
+
583
+ Examples
584
+ --------
585
+ >>> DatetimeTZDtype.construct_from_string('datetime64[ns, UTC]')
586
+ datetime64[ns, UTC]
570
587
"""
588
+ msg = "Could not construct DatetimeTZDtype from '{}'"
571
589
try :
572
- return cls (unit = string )
573
- except ValueError :
574
- raise TypeError ("could not construct DatetimeTZDtype" )
590
+ match = cls ._match .match (string )
591
+ if match :
592
+ d = match .groupdict ()
593
+ return cls (unit = d ['unit' ], tz = d ['tz' ])
594
+ except Exception :
595
+ # TODO(py3): Change this pass to `raise TypeError(msg) from e`
596
+ pass
597
+ raise TypeError (msg .format (string ))
575
598
576
599
def __unicode__ (self ):
577
- # format the tz
578
600
return "datetime64[{unit}, {tz}]" .format (unit = self .unit , tz = self .tz )
579
601
580
602
@property
581
603
def name (self ):
604
+ """A string representation of the dtype."""
582
605
return str (self )
583
606
584
607
def __hash__ (self ):
585
608
# make myself hashable
609
+ # TODO: update this.
586
610
return hash (str (self ))
587
611
588
612
def __eq__ (self , other ):
@@ -593,6 +617,11 @@ def __eq__(self, other):
593
617
self .unit == other .unit and
594
618
str (self .tz ) == str (other .tz ))
595
619
620
+ def __setstate__ (self , state ):
621
+ # for pickle compat.
622
+ self ._tz = state ['tz' ]
623
+ self ._unit = state ['unit' ]
624
+
596
625
597
626
class PeriodDtype (ExtensionDtype , PandasExtensionDtype ):
598
627
"""
0 commit comments