পান্ডাস টাইমজোন-সচেতন তারিখটাইমআইডেক্সকে নিরীহ টাইমস্ট্যাম্পে রূপান্তর করুন, তবে নির্দিষ্ট সময় অঞ্চলে


99

আপনি tz_localizeটাইমস্ট্যাম্প বা ডেটটাইম ইন্ডেক্সের সময় অঞ্চলকে সচেতন করতে ফাংশনটি ব্যবহার করতে পারেন তবে আপনি বিপরীতে কীভাবে করতে পারেন: আপনি কীভাবে টাইমজোন সচেতন টাইমস্ট্যাম্পকে একটি নির্দোষে রূপান্তর করতে পারবেন, তার সময়সীমা সংরক্ষণের মাধ্যমে?

একটি উদাহরণ:

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

আমি টাইমজোনটিকে কোনওটিতে সেট করে সরিয়ে ফেলতে পারতাম, তবে তারপরে ফলাফলটি ইউটিসিতে রূপান্তরিত হয় (12 টা বাজে 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

আমি কি ডেটটাইম ইন্ডেক্সকে টাইমজোন भोঁদে রূপান্তর করতে পারি, তবে টাইমজোনটি সংরক্ষণ করার সময় এটি সেট করা আছে কি অন্য উপায় আছে?


আমি এটি জিজ্ঞাসা করার কারণ সম্পর্কে কিছু প্রসঙ্গ : আমি টাইমজোন নিখুঁত টাইমসারিগুলির সাথে কাজ করতে চাই (টাইমজোনগুলির সাথে অতিরিক্ত ঝামেলা এড়াতে এবং আমি যে মামলায় কাজ করছি তার জন্য তাদের দরকার নেই)।
তবে কিছু কারণে, আমাকে আমার স্থানীয় সময় অঞ্চল (ইউরোপ / ব্রাসেলস) এর একটি সময় অঞ্চল-সচেতন টাইমসিরিজগুলি মোকাবেলা করতে হবে। যেহেতু আমার সমস্ত অন্যান্য ডেটা টাইমজোন নিখুঁত (তবে এটি আমার স্থানীয় টাইমজোনটিতে উপস্থাপিত), তাই আমি এই টাইমসারিগুলিকে এটিকে আরও কাজ করতে নিখরচায় রূপান্তর করতে চাই, তবে এটি আমার স্থানীয় টাইমজোনতেও উপস্থাপন করতে হবে (তাই কেবল টাইমজোন তথ্য সরিয়ে ফেলুন, ব্যবহারকারী-দৃশ্যমান সময়টিকে ইউটিসি তে রূপান্তর না করে )।

আমি জানি সময়টি আসলে ইউটিসি হিসাবে অভ্যন্তরীণভাবে সঞ্চিত থাকে এবং আপনি যখন এটি উপস্থাপন করেন কেবল তখনই অন্য টাইমজোনতে রূপান্তরিত হয়, সুতরাং যখন আমি এটি "নতুন করে" তৈরি করতে চাই তখন এক ধরণের রূপান্তর থাকতে হবে। উদাহরণস্বরূপ, পাইথনের ডেটটাইম মডিউল দিয়ে আপনি টাইমজোনকে এইভাবে "অপসারণ" করতে পারেন:

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> 

সুতরাং, এর ভিত্তিতে, আমি নিম্নলিখিতগুলি করতে পারতাম, তবে আমি মনে করি বৃহত্তর টাইমসারিগুলির সাথে কাজ করার সময় এটি খুব কার্যকর হবে না:

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

টাইমজোন = কোনওটিই ইউটিসি মানে না ... আমি নিশ্চিত না আপনি এখানে কী জিজ্ঞাসা করছেন তা আমি বুঝতে পেরেছি।
অ্যান্ডি হেডেন

আমি কিছু ব্যাখ্যা যোগ। একজন ব্যবহারকারী হিসাবে আপনি যে সময়টি দেখছেন তা আমি রাখতে চাই। আমি আশা করি এটি কিছুটা স্পষ্ট করে দেয়।
জোরিস

আহ হা, এটা করে, আমি বুঝতে পারিনি যে আপনি এটি দিয়ে করতে পারেন replace
অ্যান্ডি হেডেন

@ অ্যান্ডি হেডেন তাই আসলে আমি যা চাই তা হ'ল বিপরীত tz_localizeযা ডেটটাইমগুলির জন্য যা replace(tzinfo=None)করে তা আসলে এটি খুব স্পষ্ট উপায় নয়।
জরিস

উত্তর:


123

আমার নিজের প্রশ্নের উত্তর দিতে, ইতিমধ্যে এই কার্যকারিতাটি পান্ডায় যুক্ত হয়েছে। পান্ডাস 0.15.0 থেকে শুরু করে , আপনি tz_localize(None)স্থানীয় সময়গুলির ফলে সময় অঞ্চলটি অপসারণ করতে ব্যবহার করতে পারেন।
নতুন এন্ট্রি দেখুন: http://pandas.pydata.org/pandas-docs/stable/whatsnew.html# টাইমজোন- হ্যান্ডলিং- উন্নয়ন

সুতরাং উপর থেকে আমার উদাহরণ সহ:

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')

নিরীহ স্থানীয় সময়tz_localize(None) ফলে সময় অঞ্চল তথ্য ব্যবহার করে :

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')

এছাড়াও, আপনি tz_convert(None)সময় অঞ্চল তথ্য অপসারণ করতে কিন্তু ইউটিসিতে রূপান্তর করতেও ব্যবহার করতে পারেন, তাই নির্দোষ ইউটিসি সময় উপার্জন করতে পারেন :

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')

এটি সমাধানের চেয়ে অনেক বেশি পারফরম্যান্টdatetime.replace :

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

4
যদি আপনি কিছু ইতিমধ্যে ইউটিসি যে এবং এটি স্থানীয় সময় রূপান্তর এবং দরকার, তাদের সাথে কাজ করছি তারপর : সময় অঞ্চল ড্রপ from tzlocal import get_localzone, tz_here = get_localzone(),<datetime object>.tz_convert(tz_here).tz_localize(None)
নাথন লয়েড

4
আপনার যদি দরকারী সূচক না থাকে তবে আপনার প্রয়োজন হতে পারে t.dt.tz_localize(None)বা t.dt.tz_convert(None)। নোট করুন .dt
আকিউম্যানাস

4
এই সমাধানটি কেবল তখনই কাজ করে যখন সিরিজে একটি অনন্য tz থাকে। আপনি একই ধারাবাহিকে একাধিক বিভিন্ন TZ থাকে, তাহলে কি তবুও ভেবে দেখবে (এবং ভোট দিন) সমাধান এখানে :-): stackoverflow.com/a/59204751/1054154
tozCSS

14

আমি মনে করি আপনি যা চেয়েছিলেন তার চেয়ে কার্যকর দক্ষতার সাথে আপনি যা অর্জন করতে পারবেন তা নয়।

অন্তর্নিহিত সমস্যাটি হ'ল টাইমস্ট্যাম্পগুলি (যেমন আপনি সচেতন বলে মনে করেন) দুটি অংশ নিয়ে গঠিত। ডেটা যা ইউটিসি সময়, এবং সময় অঞ্চল, tz_info উপস্থাপন করে। টাইমজোন তথ্যটি কেবল প্রদর্শনের উদ্দেশ্যে ব্যবহৃত হয় যখন স্ক্রিনে সময় অঞ্চলটি মুদ্রণ করা হয়। প্রদর্শনের সময়, ডেটা যথাযথভাবে অফসেট হয় এবং স্ট্রিংয়ে +01: 00 (বা অনুরূপ) যুক্ত করা হয়। Tz_info মানটি ছড়িয়ে দেওয়া (tz_convers (tz = কিছুই নয়) ব্যবহার করে) আসলে টাইমস্ট্যাম্পের নিষ্পাপ অংশকে উপস্থাপন করে এমন ডেটা পরিবর্তন করে না।

সুতরাং, আপনি যা চান তা করার একমাত্র উপায় হ'ল অন্তর্নিহিত ডেটা সংশোধন করা (প্যান্ডাস এটিকে অনুমতি দেয় না ... ডেটটাইম ইন্ডেক্সটি পরিবর্তনযোগ্য নয় - ডেটটাইম ইন্ডেক্সে সহায়তা দেখুন), বা টাইমস্ট্যাম্প অবজেক্টের একটি নতুন সেট তৈরি এবং এগুলি মোড়ানোর জন্য way একটি নতুন ডেটটাইম ইন্ডেক্সে। আপনার সমাধানটি পরে দেয়:

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

রেফারেন্সের জন্য, এখানে (tslib.pyx দেখুন) replaceপদ্ধতি Timestamp:

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

এটি একটি নতুন অবজেক্ট তৈরি করে datetime.datetimeতা দেখতে আপনি দস্তাবেজগুলিকে উল্লেখ করতে পারেন datetime.datetime.replace

যদি আপনি পারেন তবে দক্ষতার জন্য আপনার সেরা বাজিটি হ'ল ডেটার উত্সটি সংশোধন করা যাতে এটি (ভুলভাবে) তাদের টাইমজোন ছাড়াই টাইমস্ট্যাম্পগুলি রিপোর্ট করে। তুমি উল্লেখ করেছিলে:

আমি টাইমজোন নিরীহ টাইমসারিগুলির সাথে কাজ করতে চাই (টাইমজোনগুলির সাথে অতিরিক্ত ঝামেলা এড়াতে এবং আমি যে ক্ষেত্রে কাজ করছি তার জন্য তাদের দরকার নেই)

আপনি কোন অতিরিক্ত ঝামেলাটির কথা উল্লেখ করছেন তা জানতে আগ্রহী হব। সমস্ত সফ্টওয়্যার বিকাশের জন্য আমি একটি সাধারণ নিয়ম হিসাবে প্রস্তাব দিচ্ছি, আপনার টাইমস্ট্যাম্পটিকে 'নির্ভুল মান' ইউটিসি-তে রাখুন। দুটি আলাদা ইন্টার 64৪ টি মান দেখার চেয়ে কিছু খারাপ যা তারা ভাবছে যে তারা কোন টাইমজোন সম্পর্কিত। আপনি যদি সর্বদা, সর্বদা, সর্বদা অভ্যন্তরীণ স্টোরেজের জন্য ইউটিসি ব্যবহার করেন তবে আপনি অসংখ্য মাথাব্যথা এড়াতে পারবেন। আমার মন্ত্রটি হ'ল টাইমজোনগুলি কেবলমাত্র I / O এর জন্য


4
উত্তরের জন্য ধন্যবাদ, এবং দেরিতে জবাব: আমার কেসটি কোনও অ্যাপ্লিকেশন নয়, কেবল নিজের কাজের জন্য একটি বৈজ্ঞানিক বিশ্লেষণ (যাতে উদাহরণস্বরূপ বিশ্বজুড়ে সহযোগীদের সাথে ভাগ করে নেওয়া হয় না)। এবং সেক্ষেত্রে কেবল নিষ্পাপ টাইমস্ট্যাম্পগুলির সাথে কাজ করা সহজ হতে পারে তবে আপনার স্থানীয় সময়ে। সুতরাং আমাকে সময় অঞ্চল সম্পর্কে চিন্তা করার দরকার নেই এবং টাইমস্ট্যাম্পটিকে স্থানীয় সময় হিসাবে ব্যাখ্যা করতে পারি (অতিরিক্ত 'ঝামেলা' হতে পারে উদাহরণস্বরূপ যে সমস্ত কিছু তখন সময় অঞ্চলে থাকতে হবে, অন্যথায় আপনি "অফসেটের তুলনা করতে পারবেন না" এমন জিনিস পান নিষ্পাপ এবং অফসেট-সচেতন তারিখের সময় ")। তবে আরও জটিল অ্যাপ্লিকেশনগুলির সাথে ডিল করার সময় আমি আপনার সাথে পুরোপুরি একমত।
জোরিস

13

কারণ আমি সর্বদা মনে রাখতে লড়াই করি, এর প্রত্যেকটি কী করে তার একটি দ্রুত সংক্ষিপ্তসার:

>>> pd.Timestamp.now()  # naive local time
Timestamp('2019-10-07 10:30:19.428748')

>>> pd.Timestamp.utcnow()  # tz aware UTC
Timestamp('2019-10-07 08:30:19.428748+0000', tz='UTC')

>>> pd.Timestamp.now(tz='Europe/Brussels')  # tz aware local time
Timestamp('2019-10-07 10:30:19.428748+0200', tz='Europe/Brussels')

>>> pd.Timestamp.now(tz='Europe/Brussels').tz_localize(None)  # naive local time
Timestamp('2019-10-07 10:30:19.428748')

>>> pd.Timestamp.now(tz='Europe/Brussels').tz_convert(None)  # naive UTC
Timestamp('2019-10-07 08:30:19.428748')

>>> pd.Timestamp.utcnow().tz_localize(None)  # naive UTC
Timestamp('2019-10-07 08:30:19.428748')

>>> pd.Timestamp.utcnow().tz_convert(None)  # naive UTC
Timestamp('2019-10-07 08:30:19.428748')

7

tzসূচকের বৈশিষ্ট্যটি নির্ধারণ করা সুস্পষ্টভাবে কাজ করে বলে মনে হচ্ছে:

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

4
দেরিতে মন্তব্য করা, তবে আমি ফলাফলটি ইউটিসিতে নয়, স্থানীয় সময় অঞ্চলে উপস্থাপিত সময় হতে চাই। এবং আমি যেমন প্রশ্নের মধ্যে দেখছি, তেমন tzকোনওটি সেট করাও এটি ইউটিসিতে রূপান্তর করে।
joris

আরও, টাইমসারিগুলি ইতিমধ্যে টাইমজোন সচেতন, সুতরাং tz_convertএটিতে কল করা একটি ত্রুটি বাড়িয়ে তুলবে।
জুরিস

4

কোনও সিরিজে একাধিক বিভিন্ন সময় অঞ্চল থাকলে গৃহীত সমাধানটি কাজ করে না। এটা ছুড়ে ফেলেValueError: Tz-aware datetime.datetime cannot be converted to datetime64 unless utc=True

সমাধানটি হ'ল applyপদ্ধতিটি ব্যবহার করা ।

নীচের উদাহরণগুলি দেখুন:

# Let's have a series `a` with different multiple timezones. 
> a
0    2019-10-04 16:30:00+02:00
1    2019-10-07 16:00:00-04:00
2    2019-09-24 08:30:00-07:00
Name: localized, dtype: object

> a.iloc[0]
Timestamp('2019-10-04 16:30:00+0200', tz='Europe/Amsterdam')

# trying the accepted solution
> a.dt.tz_localize(None)
ValueError: Tz-aware datetime.datetime cannot be converted to datetime64 unless utc=True

# Make it tz-naive. This is the solution:
> a.apply(lambda x:x.tz_localize(None))
0   2019-10-04 16:30:00
1   2019-10-07 16:00:00
2   2019-09-24 08:30:00
Name: localized, dtype: datetime64[ns]

# a.tz_convert() also does not work with multiple timezones, but this works:
> a.apply(lambda x:x.tz_convert('America/Los_Angeles'))
0   2019-10-04 07:30:00-07:00
1   2019-10-07 13:00:00-07:00
2   2019-09-24 08:30:00-07:00
Name: localized, dtype: datetime64[ns, America/Los_Angeles]

3

ডিএর এই পরামর্শকে কেন্দ্র করে যে "" আপনি যা চান তা করার একমাত্র উপায় হ'ল অন্তর্নিহিত ডেটা সংশোধন করা "এবং অন্তর্নিহিত ডেটা সংশোধন করার জন্য অসাধ্য ব্যবহার করা ...

এটি আমার পক্ষে কাজ করে এবং বেশ দ্রুত:

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)

আপনার উত্তরের জন্য ধন্যবাদ! তবে আমি মনে করি ডেটাসেটের সময়কালে গ্রীষ্মকালীন / শীতের সময় স্থানান্তর না থাকলে এটি কেবলমাত্র কাজ করবে।
জোরিস

@ জোরিস আহ, ভাল ধরা! আমি তা বিবেচনা করিনি! এই পরিস্থিতিটি ASAP পরিচালনা করার জন্য আমি আমার সমাধানটি পরিবর্তন করব।
জ্যাক কেলি

আমি বিশ্বাস করি এটি এখনও ভুল কারণ আপনি কেবল প্রথম বারের অফসেটটি গণনা করছেন এবং এটি সময়কালে অগ্রগতি হিসাবে নয়। এটি আপনাকে দিবালোকের সময় সাশ্রয় করার সময় মিস করতে এবং সেই নির্দিষ্ট তারিখ এবং পরবর্তী তারিখ অনুসারে সামঞ্জস্য করবে না।
পিয়েরে-লুক বার্ট্র্যান্ড

2

দেরীতে অবদান কিন্তু ঠিক পাইথনের ডেটটাইমের মতোই কিছু পাওয়া গেছে এবং পান্ডারা একই তারিখের জন্য বিভিন্ন টাইমস্ট্যাম্প দেয়

আপনার যদি টাইমজোন-সচেতন তারিখের সময় থাকে pandas, প্রযুক্তিগতভাবে, tz_localize(None)পসিক্স টাইমস্ট্যাম্প পরিবর্তন করে (এটি অভ্যন্তরীণভাবে ব্যবহৃত হয়) যেন টাইমস্ট্যাম্পের স্থানীয় সময়টি ইউটিসি ছিল। স্থানীয় এই প্রেক্ষাপটে মানে নির্দিষ্ট সময় অঞ্চল স্থানীয় । প্রাক্তন:

import pandas as pd

t = pd.date_range(start="2013-05-18 12:00:00", periods=2, freq='H', tz="US/Central")
# DatetimeIndex(['2013-05-18 12:00:00-05:00', '2013-05-18 13:00:00-05:00'], dtype='datetime64[ns, US/Central]', freq='H')

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

# offset in seconds according to timezone:
(t_loc.values-t.values)//1e9
# array([-18000, -18000], dtype='timedelta64[ns]')

নোট করুন যে এটি আপনাকে ডিএসটি রূপান্তরকালে অদ্ভুত জিনিসগুলি দিয়ে যাবে eg

t = pd.date_range(start="2020-03-08 01:00:00", periods=2, freq='H', tz="US/Central")
(t.values[1]-t.values[0])//1e9
# numpy.timedelta64(3600,'ns')

t_loc = t.tz_localize(None)
(t_loc.values[1]-t_loc.values[0])//1e9
# numpy.timedelta64(7200,'ns')

বিপরীতে, tz_convert(None)অভ্যন্তরীণ টাইমস্ট্যাম্পটি সংশোধন করে না, এটি কেবল সরিয়ে দেয় tzinfo

t_utc = t.tz_convert(None)
(t_utc.values-t.values)//1e9
# array([0, 0], dtype='timedelta64[ns]')

আমার নীচের লাইনটি হবে: টাইমজোন-সচেতন তারিখের সাথে লেগে থাকুন আপনি যদি কেবলমাত্র এমন ব্যবহার করতে পারেন t.tz_convert(None)যা অন্তর্নিহিত POSIX টাইমস্ট্যাম্পটি সংশোধন করে না। কেবল মনে রাখবেন যে আপনি তখন ইউটিসির সাথে ব্যবহারিকভাবে কাজ করছেন।

(উইন্ডোজ 10 এ পাইথন 3.8.2 এক্স 64, pandasv1.0.5।)


0

tzinfoআপনি একটি ডেটটাইম অবজেক্টটি সংজ্ঞায়িত করার সময় সর্বাধিক গুরুত্বপূর্ণ বিষয়টি যুক্ত করা হয় ।

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())
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.