it-swarm.com.de

Konvertieren Sie den zeitzonenabhängigen DateTimeIndex von Pandas in einen naiven Zeitstempel, jedoch in bestimmten Zeitzonen

Sie können die Funktion tz_localize verwenden, um eine Timestamp- oder DateTimeIndex-Timezone anzuzeigen, aber wie können Sie das Gegenteil tun: Wie können Sie einen timezamp-fähigen Timestamp in einen naiven konvertieren und dabei seine Timezone beibehalten?

Ein Beispiel:

In [82]: t = pd.date_range(start="2013-05-18 12:00:00", periods=10, freq='s', tz="Europe/Brussels")

In [83]: t
Out[83]: 
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-05-18 12:00:00, ..., 2013-05-18 12:00:09]
Length: 10, Freq: S, Timezone: Europe/Brussels

Ich könnte die Zeitzone entfernen, indem Sie "Keine" setzen, aber dann wird das Ergebnis in UTC konvertiert (12 Uhr wurde 10):

In [86]: t.tz = None

In [87]: t
Out[87]: 
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-05-18 10:00:00, ..., 2013-05-18 10:00:09]
Length: 10, Freq: S, Timezone: None

Gibt es eine andere Möglichkeit, einen DateTimeIndex in eine naive Zeitzone umzuwandeln, aber während die Zeitzone beibehalten wurde, in der sie gespeichert wurde?


Einige context aus dem Grund, warum ich das frage: Ich möchte mit naiven Zeitzonen der Zeitzone arbeiten (um den zusätzlichen Ärger mit Zeitzonen zu vermeiden, und ich brauche sie nicht für den Fall, an dem ich gerade arbeite).
Aber aus irgendeinem Grund muss ich mich mit einer Zeitzone in meiner lokalen Zeitzone (Europa/Brüssel) beschäftigen. Da alle meine anderen Daten in der Zeitzone naiv sind (aber in meiner lokalen Zeitzone dargestellt werden), möchte ich diese Zeitreihe in naiv umwandeln, um weiter damit arbeiten zu können. Sie muss jedoch auch in meiner lokalen Zeitzone dargestellt werden (entfernen Sie einfach die Zeitzonen-Informationen.) ohne die user-visible Zeit in UTC umzuwandeln). 

Ich weiß, dass die Zeit tatsächlich als UTC intern gespeichert ist und erst dann in eine andere Zeitzone konvertiert wird, wenn Sie sie repräsentieren. Es muss also eine Art Konvertierung erfolgen, wenn ich sie "delokalisieren" möchte. Mit dem Python-Modul datetime können Sie beispielsweise die Zeitzone folgendermaßen "entfernen":

In [119]: d = pd.Timestamp("2013-05-18 12:00:00", tz="Europe/Brussels")

In [120]: d
Out[120]: <Timestamp: 2013-05-18 12:00:00+0200 CEST, tz=Europe/Brussels>

In [121]: d.replace(tzinfo=None)
Out[121]: <Timestamp: 2013-05-18 12:00:00> 

Auf dieser Grundlage könnte ich Folgendes tun, aber ich nehme an, dass dies bei einer größeren Zeitreihe nicht sehr effizient ist:

In [124]: t
Out[124]: 
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-05-18 12:00:00, ..., 2013-05-18 12:00:09]
Length: 10, Freq: S, Timezone: Europe/Brussels

In [125]: pd.DatetimeIndex([i.replace(tzinfo=None) for i in t])
Out[125]: 
<class 'pandas.tseries.index.DatetimeIndex'>
[2013-05-18 12:00:00, ..., 2013-05-18 12:00:09]
Length: 10, Freq: None, Timezone: None
49
joris

Um meine eigene Frage zu beantworten, wurde diese Funktionalität inzwischen zu Pandas hinzugefügt. Ab von Pandas 0.15.0 können Sie tz_localize(None) verwenden, um die Zeitzone zu entfernen, die zur Ortszeit führt.
Siehe den neuesten Eintrag: http://pandas.pydata.org/pandas-docs/stable/whatsnew.html#timezone-handling-improvements

Also bei meinem Beispiel von oben:

In [4]: t = pd.date_range(start="2013-05-18 12:00:00", periods=2, freq='H',
                          tz= "Europe/Brussels")

In [5]: t
Out[5]: DatetimeIndex(['2013-05-18 12:00:00+02:00', '2013-05-18 13:00:00+02:00'],
                       dtype='datetime64[ns, Europe/Brussels]', freq='H')

mit tz_localize(None) werden die Zeitzoneninformationen entfernt, die zu naiver Ortszeit führen:

In [6]: t.tz_localize(None)
Out[6]: DatetimeIndex(['2013-05-18 12:00:00', '2013-05-18 13:00:00'], 
                      dtype='datetime64[ns]', freq='H')

Darüber hinaus können Sie auch tz_convert(None) verwenden, um die Zeitzoneninformationen zu entfernen, jedoch in UTC zu konvertieren, sodass naive UTC-Zeit:

In [7]: t.tz_convert(None)
Out[7]: DatetimeIndex(['2013-05-18 10:00:00', '2013-05-18 11:00:00'], 
                      dtype='datetime64[ns]', freq='H')

Dies ist performanter als die datetime.replace-Lösung:

In [31]: t = pd.date_range(start="2013-05-18 12:00:00", periods=10000, freq='H',
                           tz="Europe/Brussels")

In [32]: %timeit t.tz_localize(None)
1000 loops, best of 3: 233 µs per loop

In [33]: %timeit pd.DatetimeIndex([i.replace(tzinfo=None) for i in t])
10 loops, best of 3: 99.7 ms per loop
53
joris

Ich denke, Sie können das, was Sie wollen, nicht effizienter erreichen, als Sie vorgeschlagen haben.

Das zugrunde liegende Problem ist, dass die Zeitstempel (wie Sie wissen) aus zwei Teilen bestehen. Die Daten, die die UTC-Zeit darstellen, und die Zeitzone tz_info. Die Zeitzoneninformationen werden nur zu Anzeigezwecken verwendet, wenn die Zeitzone auf dem Bildschirm gedruckt wird. Zum Anzeigezeitpunkt werden die Daten entsprechend versetzt und der Zeichenfolge wird +01: 00 (oder ähnliches) hinzugefügt. Durch das Entfernen des Wertes tz_info (mit tz_convert (tz = None)) werden die Daten, die den naiven Teil des Zeitstempels darstellen, nicht geändert. 

Die einzige Möglichkeit, das zu tun, was Sie möchten, besteht darin, die zugrunde liegenden Daten zu ändern (Pandas erlauben dies nicht ... DatetimeIndex sind unveränderlich - siehe die Hilfe zu DatetimeIndex) oder erstellen Sie einen neuen Satz von Zeitstempelobjekten und wickeln Sie sie ein in einem neuen DatetimeIndex. Ihre Lösung macht das Letztere:

pd.DatetimeIndex([i.replace(tzinfo=None) for i in t])

Als Referenz dient hier die replace-Methode von Timestamp (siehe tslib.pyx):

def replace(self, **kwds):
    return Timestamp(datetime.replace(self, **kwds),
                     offset=self.offset)

Sie können auf die Dokumente in datetime.datetime verweisen, um zu sehen, dass datetime.datetime.replace auch ein neues Objekt erstellt. 

Wenn Sie können, sollten Sie die Datenquelle so ändern, dass die Zeitstempel (falsch) ohne Zeitzone (falsch) gemeldet werden. Du erwähntest:

Ich möchte mit naiven Zeitreihen von timezone arbeiten (um den zusätzlichen Ärger mit Zeitzonen zu vermeiden, und ich brauche sie nicht für den Fall, an dem ich gerade arbeite).

Ich wäre gespannt, auf welche zusätzlichen Schwierigkeiten Sie sich beziehen. Ich empfehle als generelle Regel für alle Softwareentwicklungen, den Zeitstempel "naive Werte" in UTC aufzubewahren. Es ist kaum schlimmer, als zwei verschiedene int64-Werte zu betrachten, die sich fragen, zu welcher Zeitzone sie gehören. Wenn Sie immer UTC für den internen Speicher verwenden, werden Sie unzählige Kopfschmerzen vermeiden. Mein Mantra ist Zeitzonen sind nur für menschliche E/A .

13
D. A.

Das Einstellen des tz-Attributs des Index scheint explizit zu funktionieren:

ts_utc = ts.tz_convert("UTC")
ts_utc.index.tz = None
5
filmor

Das Wichtigste ist, dass Sie tzinfo hinzufügen, wenn Sie ein datetime-Objekt definieren.

from datetime import datetime, timezone
from tzinfo_examples import HOUR, Eastern
u0 = datetime(2016, 3, 13, 5, tzinfo=timezone.utc)
for i in range(4):
     u = u0 + i*HOUR
     t = u.astimezone(Eastern)
     print(u.time(), 'UTC =', t.time(), t.tzname())
0
Yuchao Jiang

Auf den Vorschlag von D.A. aufbauen, dass " die einzige Möglichkeit, das zu tun, was Sie wollen, ist, die zugrunde liegenden Daten zu ändern " und die Verwendung von Numpy, um die zugrunde liegenden Daten zu ändern ...

Das funktioniert für mich und ist ziemlich schnell:

def tz_to_naive(datetime_index):
    """Converts a tz-aware DatetimeIndex into a tz-naive DatetimeIndex,
    effectively baking the timezone into the internal representation.

    Parameters
    ----------
    datetime_index : pandas.DatetimeIndex, tz-aware

    Returns
    -------
    pandas.DatetimeIndex, tz-naive
    """
    # Calculate timezone offset relative to UTC
    timestamp = datetime_index[0]
    tz_offset = (timestamp.replace(tzinfo=None) - 
                 timestamp.tz_convert('UTC').replace(tzinfo=None))
    tz_offset_td64 = np.timedelta64(tz_offset)

    # Now convert to naive DatetimeIndex
    return pd.DatetimeIndex(datetime_index.values + tz_offset_td64)
0
Jack Kelly