অজগর থেকে কীভাবে অজানা ডেটটাইম টাইমজোনটি সচেতন করা যায়


503

আমাকে কী করতে হবে

আমার একটি টাইমজোন-অজানা ডেটটাইম অবজেক্ট রয়েছে, যাতে এটির সাথে অন্যান্য টাইমজোন-সচেতন ডেটটাইম অবজেক্টের সাথে তুলনা করতে সক্ষম হওয়ার জন্য আমাকে একটি টাইম অঞ্চল যুক্ত করতে হবে। এই এক উত্তরাধিকারের মামলার জন্য আমি অজানা আমার পুরো অ্যাপ্লিকেশনটিকে সময় অঞ্চলকে রূপান্তর করতে চাই না।

আমি কি চেষ্টা করেছি

প্রথমে সমস্যাটি দেখানোর জন্য:

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

প্রথমত, আমি অ্যাসটাইমজোন চেষ্টা করেছি:

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

এটি ব্যর্থ হয়ে অবাক হওয়ার কিছু নেই, কারণ এটি আসলে রূপান্তর করার চেষ্টা করে do প্রতিস্থাপনটি আরও ভাল পছন্দের মতো মনে হয়েছিল ( পাইথন অনুসারে: ডেটটাইম.টোডে () যা "টাইমজোন সচেতন"? ) এর একটি মূল্য কীভাবে পাওয়া যায়? ):

>>> 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 সেট করে বলে মনে হচ্ছে, তবে অবজেক্টটিকে সচেতন করবে না। আমি ইনপুট স্ট্রিংটি বিশ্লেষণের আগে টাইমজোন তৈরি করার জন্য ফিরে আসতে প্রস্তুত হয়েছি (যদি বিষয়টি গুরুত্বপূর্ণ হয় তবে আমি পার্সিংয়ের জন্য ডেটুটিল ব্যবহার করছি) তবে এটি অবিশ্বাস্যরূপে ক্লডজি বলে মনে হয়।

এছাড়াও, আমি একই ফলাফল সহ অজগর ২.6 এবং অজগর ২.7 উভয় ক্ষেত্রে চেষ্টা করেছি।

প্রসঙ্গ

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


1
unaware.replace()Noneএটি যদি স্থানে থাকা unawareবস্তুটি সংশোধন করে তবে ফিরে আসত । আরপিএল দেখায় যে এখানে .replace()একটি নতুন datetimeঅবজেক্ট প্রদান করে।
jfs

3
এখানে আসার সময় আমার কী দরকার ছিল:import datetime; datetime.datetime.now(datetime.timezone.utc)
মার্টিন থোমা

1
@ মার্টিন থোমা আমি নামটিযুক্ত আরগটি tzআরও পড়ার জন্য ব্যবহার করব :datetime.datetime.now(tz=datetime.timezone.utc)
একিউম্যানাস

উত্তর:


590

সাধারণভাবে, একটি নিষ্পাপ ডেটটাইম টাইমজোন সচেতন করতে স্থানীয়করণ পদ্ধতিটি ব্যবহার করুন :

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
"প্রতিস্থাপন করুন একটি নতুন তারিখের সময় দেয়।" হাঁ। আরপিএল আপনাকে যে ইঙ্গিত দেয় তা হ'ল এটি আপনাকে ফেরত মান দেখাচ্ছে। :)
কার্ল নচেটেল - বাড়ি থেকে

ধন্যবাদ, আমি unware dt_unware করার dt_aware থেকে ব্যবহার ছিল = datetime.datetime (* (dt_aware.timetuple () [: 6])),
সের্গিও

4
যদি সময় অঞ্চলটি ইউটিসি না হয় তবে সরাসরি নির্মাতা ব্যবহার করবেন না: পরিবর্তে aware = datetime(..., tz)ব্যবহার করুন .localize()instead
jfs

1
এটি উল্লেখযোগ্য যে স্থানীয় সময় অস্পষ্ট হতে পারে। tz.localize(..., is_dst=None)দৃ as়রূপে যে এটি না।
jfs

166

এই উদাহরণগুলির সমস্ত একটি বাহ্যিক মডিউল ব্যবহার করে তবে আপনি কেবল ডেটটাইম মডিউলটি ব্যবহার করে একই ফলাফল অর্জন করতে পারেন, যেমনটি এই এসও উত্তরে উপস্থাপন করা হয়েছে :

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'

কম নির্ভরতা এবং পাইটজ সমস্যা নেই।

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

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আমার দূরবর্তী সার্ভারগুলিতে আসলেই মোকাবেলা করতে চায় নি :)
ট্রেগোরেগ

7
নোট করুন যে from datetime import timezoneপাই 3 তে কাজ করে তবে পাই 2.7 নয়।
7yl4r

11
আপনার লক্ষ্য করা উচিত যে dt.replace(tzinfo=timezone.utc)একটি নতুন তারিখের সময় দেয়, এটি dtজায়গায় পরিবর্তিত হয় না । (এটি দেখানোর জন্য আমি সম্পাদনা করব)।
ব্লেয়ারজ 23

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

@ জেএফ সেবাস্তিয়ান, প্রথম মন্তব্য প্রয়োগ করা হয়েছে
সেরজিও

1
আমি আপনাকে রূপান্তর উভয় দিক দেখিয়ে প্রশংসা করি।
খ্রিস্টান লং

41

আমি জাজানোতে এই বিবৃতিটি অজানা সময়কে সচেতন করে তুলতে ব্যবহার করি:

from django.utils import timezone

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

2
আমি এই সমাধানটি পছন্দ করি (+1) তবে এটি জ্যাঙ্গোর উপর নির্ভরশীল, যা তারা খুঁজছিল তা নয় (-1)। =)
মকোইস্টেইনেন

3
আপনি আসলে দ্বিতীয় যুক্তি না। ডিফল্ট যুক্তি (কিছুই নয়) অর্থ স্থানীয় সময় অঞ্চল পরোক্ষভাবে ব্যবহার করা হয়। ডিএসটি এর সাথে একই (এটি তৃতীয়
অলি

14

আমি পূর্ববর্তী উত্তরগুলির সাথে একমত, এবং আপনি যদি ইউটিসিতে শুরু করা ঠিক করেন তবে ঠিক আছে। তবে আমি মনে করি যে লোকেরা একটি টিজেড সচেতন মানের সাথে কাজ করার জন্য একটি সাধারণ পরিস্থিতি যার একটি ডেটটাইম রয়েছে যার একটি ইউটিসি-র স্থানীয় সময় অঞ্চল নেই।

আপনি যদি কেবল নামেই যান, সম্ভবত একটি স্থান নির্ধারণ করবে () প্রযোজ্য হবে এবং সঠিক ডেটটাইম সচেতন অবজেক্ট তৈরি করবে। এই ক্ষেত্রে না হয়.

প্রতিস্থাপন (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
এটির আরও বেশি পরিমাণের প্রয়োজন, replace(tzinfo=...)ইউটিসি ব্যতীত অন্য কোনও টাইমজোনটি করার চেষ্টা করা আপনার তারিখের সময়টিকে পুরোপুরি অস্বীকার করবে। আমি উদাহরণস্বরূপ -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
আপনি যদি এটি ইউটিসি .replace(tzinfo=dateutil.tz.UTC)
বানাতে

2
একটি আমদানি কম এবং ঠিক:.replace(tzinfo=datetime.timezone.utc)
কুবানজাইক

9

এটি @ সেরজিও এবং @ আনটবু এর উত্তরগুলি কোড করে । এটি কোনও pytz.timezoneবস্তু বা আইএএনএ টাইম জোন স্ট্রিংয়ের সাথে "কেবলমাত্র কাজ করবে" ।

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
ধন্যবাদ, এটি সিস্টেমটিকে প্রথমে স্থানীয় সময় হিসাবে ধরে নিয়ে তারপরে মানগুলি পুনরায় গণনা না করে একটি কাঁচা ডেটটাইম অবজেক্টটিকে "ইউটিসি" হিসাবে "ব্র্যান্ড" করতে সহায়তা করেছে!
নিখিল ভিজে

2

পাইথন ৩.৯ 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'

উপলব্ধ সময় অঞ্চলগুলির উইকিপিডিয়া তালিকা list


পাইথন 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

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