كيف تخزن تاريخ نطاقات ، والتي هي في الواقع الطوابع الزمنية

StackOverflow https://stackoverflow.com/questions/156032

سؤال

جافا & Oracle كل الطابع الزمني نوع يسمى التاريخ.المطورين يميلون إلى التعامل مع هؤلاء كما لو كانوا التقويم التمر الذي رأيت يسبب سيئة واحدة قبالة البق.

  1. الأساسية تاريخ كمية يمكنك ببساطة قطع جزء الوقت عند إدخال أي تقليل الدقة.ولكن إذا كنت تفعل ذلك مع نطاق التاريخ (على سبيل المثال: 9/29-9/30), الفرق بين هاتين القيمتين هو يوم 1 بدلا من 2.أيضا, مجموعة مقارنات تتطلب إما 1) اقتطاع العملية: start < trunc(now) <= end, أو 2) الحساب: start < now < (end + 24hrs).لا الرهيبة ، ولكن ليس الجافة.

  2. والبديل هو استخدام صحيح الطوابع الزمنية: 9/29 00:00:00 - 10/1 00:00:00.(منتصف الليل إلى منتصف الليل ، لذا لا يشمل أي جزء من أكتوبر).الآن المدد هي في جوهرها صحيحة ، و مجموعة من المقارنات أبسط: start <= now < end.بالتأكيد نظافة المعالجة الداخلية ، ومع ذلك تواريخ النهاية لا تحتاج إلى تحويلها على المدخلات الأولية (+1) من أجل إخراج (-1) ، على افتراض تقويم تاريخ الاستعارة على مستوى المستخدم.

كيف يمكنك التعامل مع نطاقات تاريخ على المشروع الخاص بك ؟ هل هناك بدائل أخرى ؟ أنا مهتم بشكل خاص في كيفية التعامل مع هذا على كل من جافا أوراكل الجانبين من المعادلة.

هل كانت مفيدة؟

المحلول

هنا هو كيف نفعل ذلك.

  1. استخدام الطوابع.

  2. استخدام نصف مفتوحة فترات المقارنة: start <= now < end.

تجاهل النائحين الذين يصرون على أن بين على نحو ما هو أساسي لنجاح SQL.

هذه سلسلة من النطاقات الزمنية هو حقا سهلة المراجعة.قاعدة البيانات القيمة 9/30 to 10/1 تشمل يوم واحد (9/30).إن الفترة المقبلة البدء يجب أن يساوي السابقة الفاصل نهاية.أن interval[n-1].end == interval[n].start القاعدة هو مفيد للمراجعة.

عند عرض, إذا كنت تريد, يمكنك عرض تنسيق start و end-1.اتضح ، يمكن تثقيف الناس أن نفهم أن "نهاية" هو في الواقع أول يوم حكم لم يعد صحيحا.حتى "9/30 إلى 10/1" يعني "ساري المفعول ابتداء من 9/30, لم يعد ساري المفعول ابتداء من 10/1".

نصائح أخرى

وقد أوراكل نوع بيانات الطابع الزمني.فإنه يخزن السنة الشهر اليوم التاريخ نوع البيانات ، بالإضافة إلى ساعة ، دقيقة ، ثانية كسرى الثاني القيم.

هنا موضوع على asktom.oracle.com عن تاريخ الحساب.

أنا ثاني ما S. لوت أوضح.لدينا منتج جناح مما يجعل الاستخدام المكثف من تاريخ الوقت يتراوح وكان أحد الدروس المستفادة من العمل مع نطاقات مثل ذلك.بالمناسبة ندعو تاريخ انتهاء حصري تاريخ النهاية إذا لم يكن جزءا من مجموعة بعد الآن (IOW نصف مفتوحة الفاصل الزمني).وعلى النقيض من ذلك ، هو شاملة تاريخ النهاية إذا كان ذلك ضروريا كجزء من النطاق الذي يكون له معنى فقط إذا كان هناك أي جزء الوقت.

المستخدمين عادة نتوقع الإدخال/الإخراج الشامل نطاقات التاريخ.على أي حال, تحويل مدخلات المستخدم في أقرب وقت ممكن الحصرية تاريخ نهاية نطاقات, وتحويل أي مدى التاريخ في وقت متأخر ممكن عندما يكون عرضها للمستخدم.

على قاعدة البيانات, تخزين دائما حصرية نهاية نطاقات التاريخ.إذا كان هناك تركة بيانات شاملة تاريخ نهاية نطاقات ، إما تهاجر منها على ديسيبل إذا كان ذلك ممكنا أو تحويل الحصرية تاريخ انتهاء النطاق في أقرب وقت ممكن عندما يتم قراءة البيانات.

يمكنني استخدام أوراكل نوع البيانات تاريخ وتثقيف المطورين على هذه المكونات التي تؤثر في شروط الحدود.

قاعدة بيانات القيد أيضا منع عرضي مواصفات وقت عنصر في العمود الذي يجب أن يكون لا شيء كما يقول محسن أن أيا من القيم يكون عنصر الوقت.

على سبيل المثال, القيد الاختيار (MY_DATE=TRUNC(MY_DATE)) ويمنع قيمة مع الوقت بخلاف 00:00:00 وضعها في my_date عمود و أيضا يسمح أوراكل أن نستنتج أن المسند مثل MY_DATE = TO_DATE('2008-09-12 15:00:00') لن يكون صحيحا, وبالتالي لا الصفوف سوف تعاد من الجدول لأنه يمكن توسيعها إلى:

MY_DATE = TO_DATE('2008-09-12 15:00:00') AND
TO_DATE('2008-09-12 15:00:00') = TRUNC(TO_DATE('2008-09-12 15:00:00'))

هذا هو تلقائيا كاذبة بالطبع.

على الرغم من أنه في بعض الأحيان المغري تخزين التواريخ كأرقام مثل 20080915 يمكن أن يسبب هذا الاستعلام الأمثل المشاكل.على سبيل المثال, كيف العديد من القيم القانونية هناك بين 20,071,231 و 20,070,101?ماذا عن بين التواريخ 31-Dec-2007 abnd 01-Jan-2008?فإنه يسمح أيضا غير القيم التي يتم إدخالها مثل 20070100.

لذا, إذا كان لديك مواعيد دون وقت المكونات ثم تحديد مجموعة يصبح من السهل:

select ...
from   ...
where  my_date Between date '2008-01-01' and date '2008-01-05'

عندما يكون هناك عنصر الوقت يمكنك القيام بأحد الإجراءات التالية:

select ...
from   ...
where  my_date >= date '2008-01-01' and
       my_date  < date '2008-01-06'

أو

select ...
from   ...
where  my_date Between date '2008-01-01'
                   and date '2008-01-05'-(1/24/60/60)

ملاحظة استخدام (1/24/60/60) بدلا من الرقم السحري.فإنه من الشائع جدا في أوراكل لأداء تاريخ الحساب عن طريق إضافة تعريف الكسور من يوم ...3/24 لمدة ثلاث ساعات ، 27/24/60 لمدة 27 دقيقة.أوراكل الرياضيات من هذا النوع بالضبط و لا تعاني من أخطاء التقريب ، لذلك:

select 27/24/60 from dual;

...يعطي 0.01875 لا 0.01874999999999 أو أيا كان.

أنا لا أرى الفاصل أنواع البيانات المنشورة حتى الآن.

أوراكل أيضا أنواع البيانات الخاصة بك بالضبط السيناريو.هناك فاصل العام إلى الشهر الفاصل اليوم الثاني أنواع البيانات في أوراكل أيضا.

من 10gR2 مستندات.

الفاصل الزمني العام إلى شهر مخازن فترة من الوقت باستخدام السنة و الشهر التاريخ والوقت المجالات.هذا هو نوع البيانات مفيدة يمثل الفرق بين اثنين من قيم التاريخ والوقت عندما فقط السنة و الشهر القيم كبيرة.

الفاصل الزمني العام [(year_precision)] إلى الشهر

حيث year_precision هو عدد أرقام في السنة حقل التاريخ والوقت.على القيمة الافتراضية year_precision هو 2.

فاصل اليوم الثاني نوع البيانات

فاصل اليوم الثاني متجر فترة من أيام وساعات ، دقائق و ثوان.هذا هو نوع البيانات من المفيد تمثيل دقيق الفرق بين اثنين من التاريخ والوقت القيم.

تحديد هذا نوع البيانات كما يلي:

فاصل اليوم [(day_precision)] إلى الثاني [(fractional_seconds_precision)]

حيث

day_precision هو عدد الأرقام في يوم حقل التاريخ والوقت.قبلت القيم من 0 إلى 9.الافتراضي هو 2.

fractional_seconds_precision هو عدد الأرقام في كسور جزء من الثانية حقل التاريخ والوقت.القيم المقبولة هي من 0 إلى 9.على الافتراضي هو 6.

لديك قدرا كبيرا من المرونة عند تحديد الفاصل الزمني القيم حرفية.يرجى الرجوع إلى "الفاصل حرفية" للحصول على معلومات مفصلة عن تحديد الفاصل الزمني قيم حرفية.انظر أيضا "والوقت الفاصل أمثلة" على سبيل المثال باستخدام فترات.

استنادا إلى تجربتي ، وهناك أربع طرق رئيسية للقيام بذلك:

1) تحويل التاريخ إلى حقبة صحيح (ثانية منذ 1 يناير 1970) وتخزينها في قاعدة بيانات عدد صحيح.

2) تحويل التاريخ إلى YYYYMMDDHHMMSS صحيح وتخزينها في قاعدة بيانات عدد صحيح.

3) مخزن على أنها تاريخ

4) مخزن بأنها سلسلة

كنت دائما عالقة مع 1 و 2 ، لأنه يتيح لك أداء سريع و بعملية حسابية بسيطة مع التاريخ و لا تعتمد على قاعدة البيانات الأساسية وظيفة.

استنادا إلى الجملة الأولى ، أنت عثرة على أحد المخفية "ملامح" (أيالبق) جافا: java.util.Date ينبغي أن يكون ثابتا لكنه لا.(Java 7 وعود إصلاح هذا مع التاريخ/الوقت API.) تقريبا كل المشاريع التطبيق بحساب مختلف الزمنية أنماط, و في بعض نقطة سوف تحتاج إلى القيام بعملية حسابية على التاريخ والوقت.

من الناحية المثالية, هل يمكن استخدام Joda الوقت, الذي يستخدم من قبل جوجل التقويم.إذا كنت لا تستطيع أن تفعل هذا ، أعتقد API التي تتكون من التفاف حول java.util.Date مع الطرق الحسابية مماثلة الكؤوس/القضبان ، ومجموعة من المجمع الخاص بك (أي ، أمر الزوج مما يدل على بداية و نهاية الفترة) سوف تكون كافية.

على المشروع الحالي (HR الساعات التطبيق) ونحن نحاول أن تطبيع جميع التواريخ نفس التوقيت لكل من أوراكل وجافا.لحسن الحظ, لدينا متطلبات توطين هي خفيفة الوزن (= 1 التوقيت بما فيه الكفاية).عندما الثابتة وجوه لا تحتاج بدقة أفضل من اليوم ، ونحن استخدام الطابع الزمني اعتبارا من منتصف الليل.وأود أن تذهب أبعد من ذلك و يصر على رمي إضافية ملي ثانية خشن تحبب أن استمرار كائن يمكن أن يتسامح مع (سيجعل الخاص بك معالجة أبسط).

جميع التواريخ يمكن أن يكون بشكل لا لبس فيه تخزين GMT الطوابع الزمنية (أيلا التوقيت أو التوقيت الصيفي الصداع) عن طريق تخزين نتيجة getTime() كما عدد صحيح طويل.

في الحالات التي يكون فيها يوم ، أسبوع ، شهر ، إلخ.التلاعب اللازمة في استعلامات قاعدة البيانات و عند الاستعلام الأداء هو الهدف الأسمى ، الطوابع الزمنية (تطبيع أعلى تحبب من ميلي ثانية) يمكن أن تكون مرتبطة إلى تاريخ انهيار جدول يحتوي على الأعمدة يوم ، أسبوع ، شهر ، إلخ.القيم بحيث مكلفة التاريخ/الوقت من المهام لا تستخدم في الاستعلامات.

آلان هو الحق - Joda الوقت كبيرة.java.util.تاريخ التقويم هي مجرد عار.

إذا كنت بحاجة إلى استخدام الطوابع أوراكل نوع التاريخ مع الوقت ، اسم العمود مع بعض نوع من لاحقة مثل _tmst.عند قراءة البيانات في جافا الحصول عليها في joda الوقت DateTime الكائن.للتأكد من التوقيت هو حق النظر أن هناك أنواع البيانات في أوراكل التي سوف مخزن الطوابع الزمنية مع التوقيت.أو يمكنك إنشاء عمود آخر في الجدول لتخزين التوقيت الهوية.قيم التوقيت ID يجب أن يكون معيار الاسم الكامل معرف الزمنية ترى http://java.sun.com/j2se/1.4.2/docs/api/java/util/TimeZone.html#getTimeZone%28java.lang.String%29 .إذا كنت تستخدم آخر العمود TZ dta ثم عند قراءة البيانات في جافا استخدام التاريخ والوقت كائن ولكن ضبط التوقيت على التاريخ والوقت الكائن باستخدام .withZoneRetainFields لضبط التوقيت.

إذا كنت بحاجة فقط تاريخ البيانات (لا زمني) ثم استخدام نوع التاريخ في قاعدة البيانات مع أي وقت من الأوقات.مرة أخرى اسم ذلك جيدا.في هذه الحالة استخدام DateMidnight كائن من jodatime.

خلاصة القول:الاستفادة من نظام نوع من قاعدة البيانات واللغة التي تستخدمها.نتعلم منها و جني الفوائد من وجود معبرة api و تركيب اللغة للتعامل مع المشكلة الخاصة بك.

تحديث:على Joda الوقت المشروع هو الآن في "وضع الصيانة".فريق تنصح الهجرة إلى java.الوقت دروس بنيت في جاوة.

Joda الوقت

Joda الوقت تقدم 3 فئات تمثل فترة من الوقت:الفاصل الزمني ومدة الفترة.

8601 ISO القياسية تحدد كيفية تنسيق السلاسل يمثل مدة و الفاصل.Joda مرة كل يوزع ويولد مثل هذه السلاسل.

منطقة زمنية اعتبار حاسم.قاعدة البيانات الخاصة بك يجب أن يتم تخزين التاريخ والوقت القيم في UTC.ولكن منطق تسلسل العمل الخاص بك قد تحتاج إلى النظر في المناطق الزمنية.بداية من "يوم" يعتمد على المنطقة الزمنية.بالمناسبة, استخدام الوقت المناسب المنطقة الأسماء بدلا من 3 أو 4 رموز الرسالة.

على الإجابة الصحيحة بواسطة S. لوت بحكمة ينصح استخدام نصف مفتوحة المنطق ، كما أنه عادة ما يعمل بشكل أفضل بالنسبة تاريخ-وقت العمل.بداية من فترة من الوقت شاملة بينما النهاية حصري.Joda الوقت يستخدم نصف مفتوحة المنطق في أساليبها.

diagram defining a week as greater than or equal to Day 1 and less than Day 8

DateTimeZone timeZone_NewYork = DateTimeZone.forID( "America/New_York" );
DateTime start = new DateTime( 2014, 9, 29, 15, 16, 17, timeZone_NewYork );
DateTime stop = new DateTime( 2014, 9, 30, 1, 2, 3, timeZone_NewYork );

int daysBetween = Days.daysBetween( start, stop ).getDays();

Period period = new Period( start, stop );

Interval interval = new Interval( start, stop );
Interval intervalWholeDays = new Interval( start.withTimeAtStartOfDay(), stop.plusDays( 1 ).withTimeAtStartOfDay() );

DateTime lateNight29th = new DateTime( 2014, 9, 29, 23, 0, 0, timeZone_NewYork );
boolean containsLateNight29th = interval.contains( lateNight29th );

تفريغ وحدة...

System.out.println( "start: " + start );
System.out.println( "stop: " + stop );
System.out.println( "daysBetween: " + daysBetween );
System.out.println( "period: " + period ); // Uses format: PnYnMnDTnHnMnS
System.out.println( "interval: " + interval );
System.out.println( "intervalWholeDays: " + intervalWholeDays );
System.out.println( "lateNight29th: " + lateNight29th );
System.out.println( "containsLateNight29th: " + containsLateNight29th );

عند تشغيل...

start: 2014-09-29T15:16:17.000-04:00
stop: 2014-09-30T01:02:03.000-04:00
daysBetween: 0
period: PT9H45M46S
interval: 2014-09-29T15:16:17.000-04:00/2014-09-30T01:02:03.000-04:00
intervalWholeDays: 2014-09-29T00:00:00.000-04:00/2014-10-01T00:00:00.000-04:00
lateNight29th: 2014-09-29T23:00:00.000-04:00
containsLateNight29th: true

Im تخزين كافة التواريخ في ميلي ثانية.أنا لا استخدام الطوابع/التاريخ والوقت في جميع المجالات.

لذا يجب أن التلاعب به كما يتوق.يعني أنا لا تستخدم 'قبل', 'بعد', 'الآن' الكلمات الرئيسية في استعلامات sql.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top