রেল এবং পোস্টগ্রিএসকিউএল এ পুরো সময় অঞ্চলকে উপেক্ষা করা


164

আমি রেল এবং পোস্টগ্রিসে তারিখ এবং সময় নিয়ে কাজ করছি এবং এই সমস্যাটিতে চলেছি:

ডাটাবেসটি ইউটিসি-তে রয়েছে।

ব্যবহারকারী রেল অ্যাপ্লিকেশনটিতে পছন্দের সময়-অঞ্চল নির্ধারণ করে, তবে এটি কেবল সময়ের সাথে তুলনা করার জন্য স্থানীয় সময় পাওয়ার সময় ব্যবহার করা হয়।

ব্যবহারকারীরা একটি সময় সঞ্চয় করে, 17 মার্চ, 2012, সন্ধ্যা 7 মিনিট বলে। আমি চাই না টাইমজোন রূপান্তর বা টাইমজোনটি সঞ্চয় করা হোক। আমি কেবল সেই তারিখ এবং সময় বাঁচাতে চাই। যদি ব্যবহারকারী তাদের সময় অঞ্চল পরিবর্তন করে, এটি এখনও মার্চ 17, 2012, সন্ধ্যা 7 টা প্রদর্শিত হবে।

আমি কেবলমাত্র স্থানীয় সময় অঞ্চলে ব্যবহারকারীদের বর্তমান সময়ের 'আগে' বা 'পরে' রেকর্ড পেতে ব্যবহারকারীদের নির্দিষ্ট সময় অঞ্চলটি ব্যবহার করি।

আমি বর্তমানে 'টাইমস্ট্যাম্প ছাড়াই টাইমস্ট্যাম্প' ব্যবহার করছি তবে আমি যখন রেকর্ডগুলি পুনরুদ্ধার করি তখন রেলগুলি (?) সেগুলি অ্যাপে টাইম জোনে রূপান্তর করে, যা আমি চাই না।

Appointment.first.time
 => Fri, 02 Mar 2012 19:00:00 UTC +00:00 

যেহেতু ডাটাবেসে রেকর্ডগুলি ইউটিসি হিসাবে প্রকাশিত হয়েছে বলে মনে হচ্ছে, আমার হ্যাকটি এখনকার সময় নেবে, 'ডেট.স্ট্রিপটাইম (স্ট্রিং, "% এম /% ডি /% ওয়াই") দিয়ে টাইম অঞ্চলটি সরিয়ে ফেলবে এবং তারপরে আমার এর সাথে ক্যোয়ারী:

.where("time >= ?", date_start)

দেখে মনে হচ্ছে চারপাশের সময় অঞ্চলগুলি উপেক্ষা করার একটি সহজ উপায় থাকতে হবে। কোন ধারনা?

উত্তর:


347

ডেটা টাইপ timestampহ'ল সংক্ষিপ্ত নাম timestamp without time zone
অন্য বিকল্পের timestamptzজন্য সংক্ষিপ্ত timestamp with time zone

timestamptzহয় পছন্দের তারিখ / সময় পরিবারে ধরন, আক্ষরিক। এটি typispreferredসেট করেছে pg_type, যা প্রাসঙ্গিক হতে পারে:

অভ্যন্তরীণ স্টোরেজ এবং পর্ব

অভ্যন্তরীণভাবে, টাইমস্ট্যাম্পগুলি ডিস্কে এবং র‌্যামে 8 বাইট স্টোরেজ দখল করে। এটি পোস্টগ্রিসের যুগ থেকে 2000-01-01 00:00:00 ইউটিসি থেকে মাইক্রোসেকেন্ডগুলির গণনা উপস্থাপন করে একটি পূর্ণসংখ্যা মান।

পোস্টগ্রিসের ইউএনআইএক্স-এর মহাকাব্য , 1970-01-01 00:00:00 ইউটিসি থেকে সাধারণভাবে ব্যবহৃত ইউনিক্স সময় গণনা সেকেন্ডের অন্তর্নির্মিত জ্ঞান রয়েছে এবং এটি ফাংশনে to_timestamp(double precision)বা ব্যবহার করে EXTRACT(EPOCH FROM timestamptz)

উত্স কোড:

* টাইমস্ট্যাম্পগুলি, পাশাপাশি hv / m / s অন্তরগুলির ক্ষেত্রগুলি হিসাবে সংরক্ষণ করা হয়
মাইক্রোসেকেন্ডগুলির ইউনিট সহ int64 মানগুলি। (একসময় তারা ছিল  
* সেকেন্ডের ইউনিট সহ ডাবল মান)

এবং:

/ * জুলিয়ান-তারিখ সমতুল্য 0 ইউনিক্স এবং পোস্টগ্রিস গণনায় * /  
# নির্ধারিত ইউনিক্স_ইপোক_জেড 2440588 / * == তারিখ 2 জ (1970, 1, 1) * /  
# নির্ধারিত পোষ্টগ্রিএস_ইপোক_জেড 2451545 / * == তারিখ 2 জ (2000, 1, 1) * /  

মাইক্রোসেকেন্ড রেজোলিউশন সেকেন্ডের জন্য সর্বাধিক 6 ভগ্নাংশের সংখ্যায় অনুবাদ করে।

timestamp

টাইপ করা একটি মান পোস্টগ্রিসকে বলে যে কোনও সময় অঞ্চল স্পষ্টভাবে সরবরাহ করা হয় না। বর্তমান সময় অঞ্চল অনুমান করা হয়। পোস্টগ্র্যাগগুলি ভুলভাবে যুক্ত হওয়া কোনও সময় অঞ্চল সংশোধককে উপেক্ষা করে !timestamp [without time zone]

প্রদর্শনের জন্য কোনও ঘন্টা স্থানান্তরিত হয় না। একই সময় অঞ্চল নির্ধারণের সাথে সমস্ত ঠিক আছে। ভিন্ন সময় অঞ্চল নির্ধারণের জন্য অর্থ পরিবর্তিত হয় তবে মান এবং প্রদর্শন একই থাকে।

timestamptz

হ্যান্ডলিং timestamp with time zoneসুক্ষভাবে পৃথক। আমি এখানে ম্যানুয়াল উদ্ধৃত :

এর জন্য timestamp with time zone, অভ্যন্তরীণভাবে সঞ্চিত মান সর্বদা ইউটিসিতে থাকে (সার্বজনীন সমন্বিত সময় ...)

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

পিএসকিএল বা পিজিএডমিনের মতো ক্লায়েন্ট বা লাইবপিকিউ এর মাধ্যমে যোগাযোগের যে কোনও অ্যাপ্লিকেশন ( পিজি রত্নের সাথে রুবির মতো) বর্তমান টাইম জোনের জন্য বা একটি অনুরোধকৃত সময় অঞ্চল অনুযায়ী (নীচে দেখুন) টাইমস্ট্যাম্প প্লাস অফসেট সহ উপস্থাপিত হবে । এটি সময়ে সর্বদা একই পয়েন্ট থাকে কেবলমাত্র প্রদর্শন বিন্যাসটি পরিবর্তিত হয়। অথবা, ম্যানুয়ালটি যেমন রাখে :

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

এই সহজ উদাহরণ বিবেচনা করুন (পিএসকিএল এ):

ডিবি = # নির্বাচন টাইমস্ট্যাম্পটজ '2012-03-05 20:00 +03 ';
      timestamptz
------------------------
 2012-03-05 18:00:00 +01

বোল্ড জোর আমার। সেখানে কি ঘটেছিল?
আমি +3ইনপুট আক্ষরিক জন্য অফসেট একটি স্বেচ্ছাসেবী সময় অঞ্চল বেছে নিয়েছি । পোস্টগ্রিসের কাছে এটি ইউটিসি টাইমস্ট্যাম্প ইনপুট করার অনেকগুলি উপায়ের মধ্যে একটি 2012-03-05 17:00:00। আমার পরীক্ষায় ভিয়েনা / অস্ট্রিয়া নির্ধারণের জন্য বর্তমান সময়ের অঞ্চল নির্ধারণের জন্য ক্যোয়ারির ফলাফল প্রদর্শিত হবে যা শীতকালে এবং গ্রীষ্মের সময় একটি অফসেট থাকে : কারণ এটি শীতের সময়ে পড়ে।+1+22012-03-05 18:00:00+01

পোস্টগ্রিজ ইতিমধ্যে ভুলে গেছে যে কীভাবে এই মানটি প্রবেশ করানো হয়েছে। এটিকে মনে রাখার মতো সমস্ত মূল্য এবং ডেটা টাইপ। দশমিক সংখ্যার মতোই। numeric '003.4', numeric '3.40'বা numeric '+3.4'- সমস্ত ফলাফল একই একই অভ্যন্তরীণ মান হিসাবে।

AT TIME ZONE

আপনি এই যুক্তিটি উপলব্ধি করার সাথে সাথে আপনি নিজের ইচ্ছামত কিছু করতে পারেন। এখন যা অনুপস্থিত তা হ'ল নির্দিষ্ট সময় অঞ্চল অনুসারে টাইমস্ট্যাম্পের আক্ষরিক অর্থ ব্যাখ্যা বা উপস্থাপন করার একটি সরঞ্জাম। সেখানে AT TIME ZONEকনস্ট্রাক্টটি আসে use দুটি ব্যবহারের ক্ষেত্রে পৃথক পৃথক ঘটনা রয়েছে। timestamptzরূপান্তরিত হয় timestampএবং বিপরীতে।

ইউটিসিতে প্রবেশ করতে timestamptz 2012-03-05 17:00:00+0:

SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'

... যা এর সমান:

SELECT timestamptz '2012-03-05 17:00:00 UTC'

EST timestamp(পূর্ব স্ট্যান্ডার্ড সময়) হিসাবে একই সময়ে একই পয়েন্ট প্রদর্শন করতে :

SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'

ঠিক, AT TIME ZONE 'UTC' দু'বার । প্রথমটি timestampমানটি প্রদত্ত (প্রদত্ত) হিসাবে ইউটিসি টাইমস্ট্যাম্পটি টাইপটি ফেরত দেয় timestamptz। দ্বিতীয়টি প্রদত্ত সময় অঞ্চল 'ইএসটি' timestamptzতে রূপান্তর করে timestamp- সময় অঞ্চল ইএসটির একটি ঘড়ি সময়টিতে এই অনন্য পয়েন্টে প্রদর্শিত হয়।

উদাহরণ

SELECT ts AT TIME ZONE 'UTC'
FROM  (
   VALUES
      (1, timestamptz '2012-03-05 17:00:00+0')
    , (2, timestamptz '2012-03-05 18:00:00+1')
    , (3, timestamptz '2012-03-05 17:00:00 UTC')
    , (4, timestamp   '2012-03-05 11:00:00'  AT TIME ZONE '+6') 
    , (5, timestamp   '2012-03-05 17:00:00'  AT TIME ZONE 'UTC') 
    , (6, timestamp   '2012-03-05 07:00:00'  AT TIME ZONE 'US/Hawaii')  -- 
    , (7, timestamptz '2012-03-05 07:00:00 US/Hawaii')                  -- 
    , (8, timestamp   '2012-03-05 07:00:00'  AT TIME ZONE 'HST')        -- 
    , (9, timestamp   '2012-03-05 18:00:00+1')  --  loaded footgun!
      ) t(id, ts);

একই ইউটিসি টাইমস্ট্যাম্প ধারণ করে টাইমস্ট্যাম্প্টজ কলামগুলির সাথে 8 (বা 9) অভিন্ন সারি দেয় 2012-03-05 17:00:00। 9 ম সারির ধরণের কাজটি আমার টাইম জোনে কাজ করার জন্য ঘটে তবে এটি একটি খারাপ শত্রু। নিচে দেখ.

Zone হাওয়াই সময়ের জন্য সময় জোনের নাম এবং সময় জোনের সংক্ষিপ্তসার সহ 6 - 8 সারিগুলি ডিএসটি (দিবালোক সংরক্ষণের সময়) এর অধীন এবং বর্তমানে না হলেও এটি ভিন্ন হতে পারে। একটি টাইম জোনের নাম 'US/Hawaii'ডিএসটি নিয়ম এবং সমস্ত historicতিহাসিক শিফট স্বয়ংক্রিয়ভাবে সচেতন হয়, যখন একটি সংক্ষিপ্তকরণটি HSTএকটি নির্দিষ্ট অফসেটের জন্য কেবল একটি বোবা কোড। গ্রীষ্ম / মানক সময়ের জন্য আপনাকে আলাদা আলাদা সংক্ষেপণ যুক্ত করতে হতে পারে। নাম সঠিকভাবে ব্যাখ্যা করে কোন নির্দিষ্ট সময় জোন এ টাইমস্ট্যাম্প। একটি সংক্ষেপণ সস্তা, তবে প্রদত্ত টাইমস্ট্যাম্পের জন্য সঠিক হওয়া দরকার:

দিবালোক সংরক্ষণ সময় মানবতা যে উজ্জ্বল ধারণাগুলি নিয়ে আসে তার মধ্যে নয়।

② সারি 9, বোঝা ফুটগান হিসাবে চিহ্নিত হিসাবে আমার জন্য কাজ করে , কিন্তু শুধুমাত্র কাকতালীয় দ্বারা। আপনি স্পষ্টভাবে করার জন্য একটি আক্ষরিক নিক্ষেপ তাহলে timestamp [without time zone], কোন সময় জোন অফসেট উপেক্ষা করা হয় ! কেবল খালি টাইমস্ট্যাম্প ব্যবহার করা হয়। মানটির পরে timestamptzকলামের ধরণটি মেলে উদাহরণটিতে স্বয়ংক্রিয়ভাবে জোর করা হয়। এই পদক্ষেপের জন্য, timezoneবর্তমান অধিবেশনটির সেটিংটি ধরে নেওয়া হয়েছে, যা +1আমার ক্ষেত্রে একই সময় (ইউরোপ / ভিয়েনা) হিসাবে ঘটে । তবে সম্ভবত আপনার ক্ষেত্রে নয় - যার ফলশ্রুতিতে আলাদা মান আসবে। সংক্ষেপে: timestamptzআক্ষরিক কাস্ট করবেন না timestampবা আপনি টাইম অঞ্চল অফসেট হারাবেন।

তোমার প্রশ্নগুলো

ব্যবহারকারীরা একটি সময় সঞ্চয় করে, 17 মার্চ, 2012, সন্ধ্যা 7 মিনিট বলে। আমি চাই না টাইমজোন রূপান্তর বা টাইমজোনটি সঞ্চয় করা হোক।

সময় অঞ্চল নিজেই কখনও সংরক্ষণ করা হয় না। ইউটিসি টাইমস্ট্যাম্প প্রবেশের জন্য উপরের একটি পদ্ধতি ব্যবহার করুন।

আমি কেবলমাত্র স্থানীয় সময় অঞ্চলে ব্যবহারকারীদের বর্তমান সময়ের 'আগে' বা 'পরে' রেকর্ড পেতে ব্যবহারকারীদের নির্দিষ্ট সময় অঞ্চলটি ব্যবহার করি।

আপনি বিভিন্ন সময় জোনে সমস্ত ক্লায়েন্টের জন্য একটি ক্যোয়ারী ব্যবহার করতে পারেন।
পরম বৈশ্বিক সময়ের জন্য:

SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time

স্থানীয় ঘড়ি অনুযায়ী সময়ের জন্য:

SELECT * FROM tbl WHERE time_col > now()::time

পটভূমি তথ্য ক্লান্ত না, এখনও? ম্যানুয়ালটিতে আরও রয়েছে।


2
গৌণ বিশদ, তবে আমি মনে করি টাইমস্ট্যাম্পগুলি 2000-01-01 থেকে মাইক্রোসেকেন্ডের সংখ্যা হিসাবে অভ্যন্তরীণভাবে সঞ্চিত আছে - ম্যানুয়ালটির তারিখ / সময় ডেটাটাইপ বিভাগ দেখুন see উত্সটি সম্পর্কে আমার নিজস্ব পরিদর্শনগুলি এটির সত্যতা নিশ্চিত করেছে। যুগের জন্য আলাদা উত্স ব্যবহার করার অদ্ভুত!
ক্ষতিকারক

2
@harmic বিভিন্ন যুগের জন্য ... আসলে এত অদ্ভুত নয়। এই উইকিপিডিয়া পৃষ্ঠায় বিভিন্ন কম্পিউটার সিস্টেম দ্বারা ব্যবহৃত দুই ডজন যুগের তালিকা রয়েছে। যদিও ইউনিক্সের যুগটি সাধারণ তবে এটি একমাত্র নয়।
বাসিল বাউর্ক

4
@ এরউইন ব্র্যান্ডসটেটার একটি গুরুতর ত্রুটি বাদে এটি একটি দুর্দান্ত উত্তর। ক্ষতিকারক মন্তব্য হিসাবে, পোস্টগ্রিস ইউনিক্স সময় ব্যবহার করে নাদস্তাবেজের মতে : (ক) ইউনিক্সের '1970-01-01 এর পরিবর্তে মহাকাশটি 2001-01-01, এবং (খ) ইউনিক্সের সময়টিতে পুরো সেকেন্ডের রেজোলিউশন থাকলেও পোস্টগ্রিস কয়েক সেকেন্ডের ভগ্নাংশ রাখে। ভগ্নাংশের সংখ্যার সংকলন সময় বিকল্পের উপর নির্ভর করে: 0 থেকে 6 যখন আট-বাইট পূর্ণসংখ্যা স্টোরেজ (ডিফল্ট) ব্যবহৃত হয়, বা 0 থেকে 10 অবধি যখন ভাসমান-পয়েন্ট স্টোরেজ (অবমূল্যায়ন) ব্যবহৃত হয়।
বাসিল বাউরক

2
@ বাসিলবার্ক: আমি এই দুর্ভাগ্যজনক ভুল সম্পর্কে অবহিত। যদি আপনি কিছু মনে করেন না, আপনি এটি সম্পাদনা করতে খুব স্বাগত জানাই। আমি আপনার উত্তরগুলি অতীতে দেখেছি এবং আপনি এতে ভাল আছেন। আমার কাছ থেকে আরও একটি সম্পাদনা এটিকে সম্প্রদায় উইকিতে বাধ্য করবে - সময়ের সাথে সাথে আমি এটিকে স্পষ্ট এবং বিস্তৃত করার জন্য প্রচুর প্রচেষ্টা (এবং সম্পাদনা) করেছি।
এরউইন ব্র্যান্ডস্টেটার

2
সংশোধন: আমার আগে মন্তব্য, আমি ভুল উদাহৃত Postgres পর্ব হিসাবে 2001 বাস্তবিক এটা 2000
বাসিল বাউর্ক

1

আপনি যদি ইউটিসিতে ডিফল্টরূপে লেনদেন করতে চান:

ইন config/application.rb, যোগ করুন:

config.time_zone = 'UTC'

তারপরে, আপনি যদি বর্তমান ব্যবহারকারীর টাইমজোন নাম সংরক্ষণ করেন তবে current_user.timezoneআপনি বলতে পারেন।

post.created_at.in_time_zone(current_user.timezone)

current_user.timezoneএকটি বৈধ সময় অঞ্চল নাম হওয়া উচিত, অন্যথায় আপনি পাবেন ArgumentError: Invalid Timezone, সম্পূর্ণ তালিকা দেখুন

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