@@ -765,79 +765,84 @@ except:
765
765
trans_cache = {}
766
766
utc_offset_cache = {}
767
767
768
- cdef ndarray[int64_t] _get_transitions(object tz):
768
+ def tz_convert (ndarray[int64_t] vals , object tz1 , object tz2 ):
769
+ cdef:
770
+ ndarray[int64_t] utc_dates, result, trans, deltas
771
+ Py_ssize_t i, pos, n = len (vals)
772
+ int64_t v, offset
773
+
774
+ if not have_pytz:
775
+ import pytz
776
+
777
+ # Convert to UTC
778
+
779
+ if tz1.zone != ' UTC' :
780
+ utc_dates = np.empty(n, dtype = np.int64)
781
+ deltas = _get_deltas(tz1)
782
+ trans = _get_transitions(tz1)
783
+ pos = trans.searchsorted(vals[0 ])
784
+ offset = deltas[pos]
785
+ for i in range (n):
786
+ v = vals[i]
787
+ if v >= trans[pos + 1 ]:
788
+ pos += 1
789
+ offset = deltas[pos]
790
+ utc_dates[i] = v - offset
791
+ else :
792
+ utc_dates = vals
793
+
794
+ if tz2.zone == ' UTC' :
795
+ return utc_dates
796
+
797
+ # Convert UTC to other timezone
798
+
799
+ result = np.empty(n, dtype = np.int64)
800
+ trans = _get_transitions(tz2)
801
+ deltas = _get_deltas(tz2)
802
+ pos = trans.searchsorted(utc_dates[0 ])
803
+ offset = deltas[pos]
804
+ for i in range (n):
805
+ v = utc_dates[i]
806
+ if v >= trans[pos + 1 ]:
807
+ pos += 1
808
+ offset = deltas[pos]
809
+ result[i] = v + offset
810
+
811
+ return result
812
+
813
+ trans_cache = {}
814
+ utc_offset_cache = {}
815
+
816
+ def _get_transitions (object tz ):
769
817
"""
770
818
Get UTC times of DST transitions
771
819
"""
772
820
if tz not in trans_cache:
773
821
arr = np.array(tz._utc_transition_times, dtype = ' M8[us]' )
774
- trans_cache[tz] = np.array( arr.view(' i8' ) )
822
+ trans_cache[tz] = arr.view(' i8' )
775
823
return trans_cache[tz]
776
824
777
- cdef ndarray[int64_t] _unbox_utcoffsets(object transinfo):
778
- cdef:
779
- Py_ssize_t i, sz
780
- ndarray[int64_t] arr
781
-
782
- sz = len (transinfo)
783
- arr = np.empty(sz, dtype = ' i8' )
784
-
785
- for i in range (sz):
786
- arr[i] = int (transinfo[i][0 ].total_seconds()) * 1000000
787
-
788
- return arr
789
-
790
- cdef int64_t get_utcoffset(object tz, Py_ssize_t idx):
825
+ def _get_deltas (object tz ):
791
826
"""
792
827
Get UTC offsets in microseconds corresponding to DST transitions
793
828
"""
794
- cdef:
795
- ndarray[int64_t] arr
796
829
if tz not in utc_offset_cache:
797
830
utc_offset_cache[tz] = _unbox_utcoffsets(tz._transition_info)
798
- arr = utc_offset_cache[tz]
799
- return arr[idx]
800
-
801
- def tz_normalize_array (ndarray[int64_t] vals , object tz1 , object tz2 ):
802
- """
803
- Convert DateRange from one time zone to another (using pytz)
831
+ return utc_offset_cache[tz]
804
832
805
- Returns
806
- -------
807
- normalized : DateRange
808
- """
833
+ cdef ndarray _unbox_utcoffsets(object transinfo):
809
834
cdef:
810
- ndarray[int64_t] result
811
- ndarray[int64_t] trans
812
- Py_ssize_t i, sz, tzidx
813
- int64_t v, tz1offset, tz2offset
814
-
815
- if not have_pytz:
816
- raise Exception (" Could not find pytz module" )
817
-
818
- sz = len (vals)
819
-
820
- if sz == 0 :
821
- return np.empty(0 , dtype = np.int64)
822
-
823
- result = np.empty(sz, dtype = np.int64)
824
- trans = _get_transitions(tz1)
825
-
826
- tzidx = np.searchsorted(trans, vals[0 ])
835
+ Py_ssize_t i, sz
836
+ ndarray[int64_t] arr
827
837
828
- tz1offset = get_utcoffset(tz1, tzidx )
829
- tz2offset = get_utcoffset(tz2, tzidx )
838
+ sz = len (transinfo )
839
+ arr = np.empty(sz, dtype = ' i8 ' )
830
840
831
841
for i in range (sz):
832
- v = vals[i]
833
- if v >= trans[tzidx + 1 ]:
834
- tzidx += 1
835
- tz1offset = get_utcoffset(tz1, tzidx)
836
- tz2offset = get_utcoffset(tz2, tzidx)
842
+ arr[i] = int (transinfo[i][0 ].total_seconds()) * 1000000
837
843
838
- result[i] = (v - tz1offset) + tz2offset
844
+ return arr
839
845
840
- return result
841
846
842
847
def tz_localize_array (ndarray[int64_t] vals , object tz ):
843
848
"""
@@ -849,43 +854,34 @@ def tz_localize_array(ndarray[int64_t] vals, object tz):
849
854
localized : DatetimeIndex
850
855
"""
851
856
cdef:
852
- ndarray[int64_t] trans
853
- Py_ssize_t i, sz, tzidx
854
- int64_t v, t1, t2, currtrans, tmp
857
+ ndarray[int64_t] trans, deltas
858
+ Py_ssize_t i, pos, n = len (vals)
859
+ int64_t v, t1, t2, tmp
855
860
856
861
if not have_pytz:
857
862
raise Exception (" Could not find pytz module" )
858
863
859
864
if tz == pytz.utc or tz is None :
860
865
return vals
861
866
862
- sz = len (vals)
863
-
864
- if sz == 0 :
865
- return np.empty(0 , dtype = np.int64)
866
-
867
- result = np.empty(sz, dtype = np.int64)
868
867
trans = _get_transitions(tz)
869
- tzidx = np.searchsorted(trans, vals[ 0 ] )
868
+ deltas = _get_deltas(tz )
870
869
871
- currtrans = trans[tzidx]
872
- t1 = currtrans + get_utcoffset(tz, tzidx - 1 )
873
- t2 = currtrans + get_utcoffset(tz, tzidx)
870
+ pos = np.searchsorted( trans, vals[ 0 ])
871
+ dst_start = trans[pos] + deltas[pos - 1 ]
872
+ dst_end = trans[pos] + deltas[pos]
874
873
875
- for i in range (sz ):
874
+ for i in range (n ):
876
875
v = vals[i]
877
- if v >= trans[tzidx + 1 ]:
878
- tzidx += 1
879
- currtrans = trans[tzidx]
880
- t1 = currtrans + get_utcoffset(tz, tzidx- 1 )
881
- t2 = currtrans + get_utcoffset(tz, tzidx)
882
-
883
- if t1 > t2:
884
- tmp = t1
885
- t1 = t2
886
- t2 = tmp
887
-
888
- if t1 <= v and v <= t2:
876
+ if v >= trans[pos + 1 ]:
877
+ pos += 1
878
+ dst_start = trans[pos] + deltas[pos - 1 ]
879
+ dst_end = trans[pos] + deltas[pos]
880
+
881
+ if dst_start > dst_end:
882
+ dst_end, dst_start = dst_start, dst_end
883
+
884
+ if dst_start <= v and v <= dst_end:
889
885
msg = " Cannot localize, ambiguous time %s found" % Timestamp(v)
890
886
raise pytz.AmbiguousTimeError(msg)
891
887
0 commit comments