अजगर में एक अनजान डाइमटाइम टाइमजोन को कैसे जागरूक किया जाए


506

मुझे क्या करना है

मेरे पास एक टाइमज़ोन-अनजान डेटाटाइम ऑब्जेक्ट है, जिसके लिए मुझे अन्य टाइमज़ोन-जागरूक डेटाटाइम ऑब्जेक्ट्स के साथ तुलना करने में सक्षम होने के लिए टाइम ज़ोन जोड़ने की आवश्यकता है। मैं अपने पूरे आवेदन को इस एक विरासत मामले के लिए अनजान समयरेखा में परिवर्तित नहीं करना चाहता।

मैंने क्या कोशिश की है

सबसे पहले, समस्या को प्रदर्शित करने के लिए:

Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes

सबसे पहले, मैंने astimezone की कोशिश की:

>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>

यह वास्तव में आश्चर्यजनक नहीं है, क्योंकि यह वास्तव में रूपांतरण करने की कोशिश कर रहा है। एक बेहतर विकल्प तरह लग रहा था बदलें (अनुसार अजगर: कैसे datetime.today () है कि "समय क्षेत्र के बारे में पता" का मान प्राप्त करने के लिए ):

>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>> 

लेकिन जैसा कि आप देख सकते हैं, प्रतिस्थापित करने से लगता है कि tzinfo सेट है, लेकिन ऑब्जेक्ट को अवगत नहीं कराएं। मैं इनपुट स्ट्रिंग को डॉक्टर करने के लिए वापस आने के लिए तैयार हूं, ताकि इसे पार्स करने से पहले एक टाइमज़ोन हो (मैं पार्सिंग के लिए डेटूटिल का उपयोग कर रहा हूं, अगर यह मायने रखता है), लेकिन यह अविश्वसनीय रूप से कुल्डी लगता है।

इसके अलावा, मैंने पायथन 2.6 और अजगर 2.7 दोनों में यह कोशिश की है, एक ही परिणाम के साथ।

प्रसंग

मैं कुछ डेटा फ़ाइलों के लिए एक पार्सर लिख रहा हूं। एक पुराना प्रारूप है जिसका मुझे समर्थन करने की आवश्यकता है जहां दिनांक स्ट्रिंग में टाइमज़ोन संकेतक नहीं है। मैंने डेटा स्रोत पहले ही तय कर लिया है, लेकिन मुझे अभी भी विरासत डेटा प्रारूप का समर्थन करने की आवश्यकता है। विरासत डेटा का एक बार रूपांतरण विभिन्न व्यावसायिक बीएस कारणों के लिए एक विकल्प नहीं है। सामान्य तौर पर, मुझे डिफ़ॉल्ट टाइमज़ोन को हार्ड-कोडिंग करने का विचार पसंद नहीं है, इस मामले में यह सबसे अच्छा विकल्प लगता है। मैं उचित विश्वास के साथ जानता हूं कि प्रश्न में सभी विरासत डेटा UTC में है, इसलिए मैं इस मामले में उस पर डिफ़ॉल्ट करने के जोखिम को स्वीकार करने के लिए तैयार हूं।


1
unaware.replace()Noneयदि यह unawareवस्तु की गति को संशोधित कर रहा होता है तो वापस आ जाता है । आरईपीएल दिखाता है कि यहां .replace()एक नई datetimeवस्तु लौटती है।
JFS

3
जब मैं यहाँ आया तो मुझे क्या चाहिए:import datetime; datetime.datetime.now(datetime.timezone.utc)
मार्टिन थोमा

1
@MartinThoma मैं नामित tzarg का उपयोग अधिक पठनीय होगा:datetime.datetime.now(tz=datetime.timezone.utc)
Acumenus

जवाबों:


593

सामान्य तौर पर, भोले-भाले लोगों को समय-समय पर जागरूक करने के लिए, स्थानीयकरण विधि का उपयोग करें :

import datetime
import pytz

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)

now_aware = pytz.utc.localize(unaware)
assert aware == now_aware

यूटीसी टाइमज़ोन के लिए, उपयोग करने के लिए वास्तव में आवश्यक नहीं है localizeक्योंकि संभाल करने के लिए कोई दिन की बचत समय गणना नहीं है:

now_aware = unaware.replace(tzinfo=pytz.UTC)

काम करता है। ( .replaceनया डेटाटाइम लौटाता है; यह संशोधित नहीं होता है unaware।)


10
खैर, मुझे मूर्खतापूर्ण लगता है। बदले एक नया डेटाटाइम। यह कहता है कि डॉक्स में भी वहीं है, और मैं पूरी तरह से चूक गया। धन्यवाद, ठीक यही मैं देख रहा था।
मार्क तोजि

2
"बदले में एक नया डेटाटाइम मिलता है।" हां। संकेत जो REPL आपको देता है वह यह है कि यह आपको लौटाया हुआ मान दिखा रहा है। :)
कार्ल Knechtel - घर से दूर

धन्यवाद, मेरे पास dt_aware से unware dt_unware = datetime.datetime (* (dt_aware.timetuple () [: 6])) का उपयोग था,
Sérgio

4
अगर टाइमजोन UTC नहीं है, तो सीधे कंस्ट्रक्टर का उपयोग न करें: इसके बजाय aware = datetime(..., tz)उपयोग करें .localize()
JFS

1
यह उल्लेखनीय है कि स्थानीय समय अस्पष्ट हो सकता है। tz.localize(..., is_dst=None)जोर देकर कहते हैं कि यह नहीं है।
JFS

166

ये सभी उदाहरण एक बाहरी मॉड्यूल का उपयोग करते हैं, लेकिन आप केवल डेटाइम मॉड्यूल का उपयोग करके एक ही परिणाम प्राप्त कर सकते हैं, जैसा कि इस SO उत्तर में प्रस्तुत किया गया है :

from datetime import datetime
from datetime import timezone

dt = datetime.now()
dt.replace(tzinfo=timezone.utc)

print(dt.replace(tzinfo=timezone.utc).isoformat())
'2017-01-12T22:11:31+00:00'

कम निर्भरता और कोई pytz मुद्दों।

नोट: यदि आप इसे python3 और python2 के साथ उपयोग करना चाहते हैं, तो आप इसे समय-समय पर आयात (UTC के लिए हार्डकोड) के लिए उपयोग कर सकते हैं:

try:
    from datetime import timezone
    utc = timezone.utc
except ImportError:
    #Hi there python2 user
    class UTC(tzinfo):
        def utcoffset(self, dt):
            return timedelta(0)
        def tzname(self, dt):
            return "UTC"
        def dst(self, dt):
            return timedelta(0)
    utc = UTC()

10
pytzमुद्दों को रोकने के लिए बहुत अच्छा जवाब , मुझे खुशी है कि मैं थोड़ा नीचे स्क्रॉल किया! pytzमेरे रिमोट सर्वर पर वास्तव में निपटने की इच्छा नहीं थी :)
Tregoreg

7
ध्यान दें कि from datetime import timezonepy3 में काम करता है लेकिन py2.7 नहीं।
7yl4r

11
आपको ध्यान देना चाहिए कि dt.replace(tzinfo=timezone.utc)नया डेटाटाइम लौटाता है, यह dtजगह में संशोधित नहीं होता है। (मैं यह दिखाने के लिए संपादित करूंगा)।
ब्लेयरग

2
आप समय-सारणी का उपयोग करने के बजाय, स्ट्रिंग के रूप में एक अलग टाइमज़ोन कैसे प्रदान कर सकते हैं (जैसे "अमेरिका / शिकागो")?
बम्पकिन

2
@ बम्पकिन कभी देर से बेहतर, मुझे लगता है:tz = pytz.timezone('America/Chicago')
फ्लोरियन

82

मैंने dt_aware से dt_unaware तक का उपयोग किया था

dt_unaware = dt_aware.replace(tzinfo=None)

और dt_unware को dt_aware

from pytz import timezone
localtz = timezone('Europe/Lisbon')
dt_aware = localtz.localize(dt_unware)

लेकिन पहले जवाब भी एक अच्छा समाधान है।


2
आप इस्तेमाल कर सकते हैं localtz.localize(dt_unware, is_dst=None)अगर एक अपवाद को बढ़ाने के लिए dt_unwareगैर मौजूदा या अस्पष्ट स्थानीय समय (नोट प्रतिनिधित्व करता है: वहां अपना उत्तर के पिछले संशोधन जहां में ऐसी कोई मुद्दा थे localtzयूटीसी था, क्योंकि यूटीसी कोई डीएसटी संक्रमण है
JFS

@JF सेबस्टियन, पहली टिप्पणी लागू किया
सर्जियो

1
मैं आपको रूपांतरण के दोनों दिशाओं को दिखाने की सराहना करता हूं।
क्रिश्चियन लॉन्ग

41

मैं अनजान समय को जागरूक में बदलने के लिए Django में इस कथन का उपयोग करता हूं:

from django.utils import timezone

dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())

2
मुझे यह समाधान (+1) पसंद है, लेकिन यह Django पर निर्भर है, जो कि वे (-1) की तलाश में नहीं थे। =)
मोकोइस्टिन

3
आप वास्तव में दूसरा तर्क नहीं है। डिफ़ॉल्ट तर्क (कोई नहीं) का मतलब होगा स्थानीय समय क्षेत्र परोक्ष प्रयोग किया जाता है। DST के साथ भी (जो तीसरा तर्क है
Oli

14

मैं पिछले जवाबों से सहमत हूं, और यदि आप यूटीसी में शुरू करना चाहते हैं तो ठीक है। लेकिन मुझे लगता है कि लोगों के लिए यह एक सामान्य परिदृश्य भी है कि एक tz जागरूक मूल्य के साथ काम करने के लिए एक डेटाटाइम है, जिसमें एक गैर UTC लोकल सीज़ोन है।

यदि आप केवल नाम से जाने वाले थे, तो शायद कोई भी प्रतिस्थापित हो जाएगा () लागू होगा और सही डेटाइम जानकारी का उत्पादन करेगा। यह मामला नहीं है।

प्रतिस्थापन (tzinfo = ...) अपने व्यवहार में यादृच्छिक लगता है । इसलिए यह बेकार है। इस का उपयोग न करें!

स्थानीयकरण उपयोग करने के लिए सही कार्य है। उदाहरण:

localdatetime_aware = tz.localize(datetime_nonaware)

या अधिक पूर्ण उदाहरण:

import pytz
from datetime import datetime
pytz.timezone('Australia/Melbourne').localize(datetime.now())

मुझे वर्तमान स्थानीय समय का एक समय क्षेत्र जागरूक डेटाइम मान देता है:

datetime.datetime(2017, 11, 3, 7, 44, 51, 908574, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)

3
यह अधिक upvotes की जरूरत है, replace(tzinfo=...)UTC के अलावा किसी अन्य समयक्षेत्र पर करने की कोशिश करने से आपका डेटाटाइम खराब हो जाएगा। मैं उदाहरण -07:53के -08:00लिए मिल गया । देखें stackoverflow.com/a/13994611/1224827
Blairg23

क्या आप replace(tzinfo=...)अप्रत्याशित व्यवहार करने का एक प्रतिलिपि प्रस्तुत करने योग्य उदाहरण दे सकते हैं ?
xjcl

11

dateutil.tz.tzlocal()अपने उपयोग में समय क्षेत्र प्राप्त करने के लिए उपयोग करें datetime.datetime.now()और datetime.datetime.astimezone():

from datetime import datetime
from dateutil import tz

unlocalisedDatetime = datetime.now()

localisedDatetime1 = datetime.now(tz = tz.tzlocal())
localisedDatetime2 = datetime(2017, 6, 24, 12, 24, 36, tz.tzlocal())
localisedDatetime3 = unlocalisedDatetime.astimezone(tz = tz.tzlocal())
localisedDatetime4 = unlocalisedDatetime.replace(tzinfo = tz.tzlocal())

ध्यान दें कि datetime.astimezoneपहले अपनी datetimeवस्तु को यूटीसी में तब समयावधि में परिवर्तित किया जाएगा , जो datetime.replaceकि मूल समय क्षेत्र की जानकारी के साथ कॉल करने के समान है None


1
अगर आप इसे UTC बनाना चाहते हैं:.replace(tzinfo=dateutil.tz.UTC)
मार्टिन थोमा

2
एक आयात कम और बस:.replace(tzinfo=datetime.timezone.utc)
kubanczyk

9

यह @ Sérgio और @ unutbu के उत्तरों को संहिताबद्ध करता है । यह या तो एक pytz.timezoneऑब्जेक्ट या IANA टाइम ज़ोन स्ट्रिंग के साथ "बस काम करेगा" ।

def make_tz_aware(dt, tz='UTC', is_dst=None):
    """Add timezone information to a datetime object, only if it is naive."""
    tz = dt.tzinfo or tz
    try:
        tz = pytz.timezone(tz)
    except AttributeError:
        pass
    return tz.localize(dt, is_dst=is_dst) 

यह वही है की तरह लगता है datetime.localize()(या .inform()या .awarify()) करते हैं, दोनों तार और TZ तर्क और यूटीसी करने के लिए डिफ़ॉल्ट के लिए समय क्षेत्र वस्तुओं अगर कोई समय क्षेत्र निर्दिष्ट किया जाता है को स्वीकार करना चाहिए।


1
धन्यवाद, इससे मुझे "UTC" के रूप में एक कच्चे डेटाटाइम ऑब्जेक्ट "ब्रांड" में मदद मिली, बिना सिस्टम ने पहले इसे स्थानीय समय मान लिया और फिर मूल्यों की पुनर्गणना की!
निखिल वीजे

2

अजगर 3.9 zoneinfoमॉड्यूल जोड़ता है इसलिए अब केवल मानक पुस्तकालय की आवश्यकता है!

from zoneinfo import ZoneInfo
from datetime import datetime
unaware = datetime(2020, 10, 31, 12)

एक समयक्षेत्र संलग्न करें:

>>> unaware.replace(tzinfo=ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 12:00:00+09:00'

सिस्टम का स्थानीय समय क्षेत्र संलग्न करें:

>>> unaware.replace(tzinfo=ZoneInfo('localtime'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='localtime'))
>>> str(_)
'2020-10-31 12:00:00+01:00'

बाद में इसे अन्य टाइमज़ोन में ठीक से परिवर्तित किया जाता है:

>>> unaware.replace(tzinfo=ZoneInfo('localtime')).astimezone(ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 20, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 20:00:00+09:00'

उपलब्ध समय क्षेत्रों की विकिपीडिया सूची


पायथन 3.6 से 3.8 में उपयोग की अनुमति देने के लिए एक बैकपोर्ट है :

sudo pip install backports.zoneinfo

फिर:

from backports.zoneinfo import ZoneInfo

0

अनटुब के उत्तर के प्रारूप में; मैंने एक उपयोगिता मॉड्यूल बनाया जो इस तरह की चीजों को संभालता है, अधिक सहज वाक्यविन्यास के साथ। पाइप के साथ स्थापित किया जा सकता है।

import datetime
import saturn

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
now_aware = saturn.fix_naive(unaware)

now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid')

0

उन लोगों के लिए जो सिर्फ एक टाइमजोन जागरूक डेटाइम बनाना चाहते हैं

import datetime
import pytz

datetime.datetime(2019, 12, 7, tzinfo=pytz.UTC)

0

पायथन के लिए काफी नया है और मुझे उसी मुद्दे का सामना करना पड़ा। मुझे यह समाधान काफी सरल लगता है और मेरे लिए यह ठीक काम करता है (अजगर 3.6):

unaware=parser.parse("2020-05-01 0:00:00")
aware=unaware.replace(tzinfo=tz.tzlocal()).astimezone(tz.tzlocal())

0

टाइमज़ोन के बीच परिवर्तन

import pytz
from datetime import datetime

other_tz = pytz.timezone('Europe/Madrid')

# From random aware datetime...
aware_datetime = datetime.utcnow().astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# 1. Change aware datetime to UTC and remove tzinfo to obtain an unaware datetime
unaware_datetime = aware_datetime.astimezone(pytz.UTC).replace(tzinfo=None)
>> 2020-05-21 06:28:26.984948

# 2. Set tzinfo to UTC directly on an unaware datetime to obtain an utc aware datetime
aware_datetime_utc = unaware_datetime.replace(tzinfo=pytz.UTC)
>> 2020-05-21 06:28:26.984948+00:00

# 3. Convert the aware utc datetime into another timezone
reconverted_aware_datetime = aware_datetime_utc.astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# Initial Aware Datetime and Reconverted Aware Datetime are equal
print(aware_datetime1 == aware_datetime2)
>> True
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.