كيفية التعامل مع التقويم الزمنية باستخدام جافا ؟

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

  •  04-07-2019
  •  | 
  •  

سؤال

لدي الزمني القيمة التي تأتي من بلدي التطبيق.يمكن للمستخدم في أي وقت التوقيت المحلي.

منذ هذا التاريخ هو استخدام خدمة ويب التي يفترض وقت معين هو دائما في GMT, أنا بحاجة إلى تحويل المستخدم المعلمة من يقول (EST) إلى (بتوقيت جرينتش).هنا كيكر:المستخدم هو مدرك له TZ.يدخل إنشاء التاريخ أنه يريد أن يرسل إلى WS, لذا ما أريده هو:

يدخل المستخدم: 5/1/2008 الساعة 6:12 مساء (EST)
المعلمة إلى WS يحتاج إلى:5/1/2008 الساعة 6:12 مساء (جرينيتش)

أعلم أن الطوابع هي دائما من المفترض أن يكون في GMT افتراضيا ، ولكن عند إرسال المعلمة, على الرغم من أنني خلقت التقويم من TS (والتي من المفترض أن تكون في توقيت غرينيتش) ، ساعات هي دائما إلا إذا كان المستخدم هو بتوقيت جرينتش.ما أنا في عداد المفقودين ؟

Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
  java.util.Calendar cal = java.util.Calendar.getInstance(
      GMT_TIMEZONE, EN_US_LOCALE);
  cal.setTimeInMillis(ts_.getTime());
  return cal;
}

مع القانون السابق ، وهذا هو ما يحصل نتيجة (قصيرة صيغة سهلة القراءة):

[1 مايو, 2008 11:12 PM]

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

المحلول 2

شكرا لكم جميعا على الاستجابة.بعد مزيد من التحقيق حصلت على الجواب الصحيح.كما ذكر تخطي الرأس ، قتية كنت الحصول من طلبي كان يجري تعديل على المستخدم التوقيت.حتى إذا قام المستخدم بإدخالها 6:12 مساء (بتوقيت شرق الولايات المتحدة) أود الحصول على 2:12 مساء (بتوقيت جرينتش).ما كان في حاجة إلى وسيلة إلى التراجع عن التحويل حتى وقت إدخالها من قبل المستخدم هو الوقت أرسلت إلى خادم الويب الطلب.هنا كيف يتحقق هذا:

// Get TimeZone of user
TimeZone currentTimeZone = sc_.getTimeZone();
Calendar currentDt = new GregorianCalendar(currentTimeZone, EN_US_LOCALE);
// Get the Offset from GMT taking DST into account
int gmtOffset = currentTimeZone.getOffset(
    currentDt.get(Calendar.ERA), 
    currentDt.get(Calendar.YEAR), 
    currentDt.get(Calendar.MONTH), 
    currentDt.get(Calendar.DAY_OF_MONTH), 
    currentDt.get(Calendar.DAY_OF_WEEK), 
    currentDt.get(Calendar.MILLISECOND));
// convert to hours
gmtOffset = gmtOffset / (60*60*1000);
System.out.println("Current User's TimeZone: " + currentTimeZone.getID());
System.out.println("Current Offset from GMT (in hrs):" + gmtOffset);
// Get TS from User Input
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
System.out.println("TS from ACP: " + issuedDate);
// Set TS into Calendar
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
// Adjust for GMT (note the offset negation)
issueDate.add(Calendar.HOUR_OF_DAY, -gmtOffset);
System.out.println("Calendar Date converted from TS using GMT and US_EN Locale: "
    + DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
    .format(issueDate.getTime()));

الرمز الناتج هو:(المستخدم دخل 5/1/2008 الساعة 6:12 مساء (EST)

المستخدم الحالي هو التوقيت:EST
الحالي تعويض عن توقيت غرينتش (في ساعة):-4 (عادة -5 إلا هو تعديل التوقيت الصيفي)
TS من ACP:2008-05-01 14:12:00.0
تاريخ التقويم تحويلها من TS باستخدام بتوقيت غرينتش US_EN الإعدادات المحلية:5/1/08 6:12 مساء (جرينيتش)

نصائح أخرى

public static Calendar convertToGmt(Calendar cal) {

    Date date = cal.getTime();
    TimeZone tz = cal.getTimeZone();

    log.debug("input calendar has date [" + date + "]");

    //Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT 
    long msFromEpochGmt = date.getTime();

    //gives you the current offset in ms from GMT at the current date
    int offsetFromUTC = tz.getOffset(msFromEpochGmt);
    log.debug("offset is " + offsetFromUTC);

    //create a new calendar in GMT timezone, set to this date and add the offset
    Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    gmtCal.setTime(date);
    gmtCal.add(Calendar.MILLISECOND, offsetFromUTC);

    log.debug("Created GMT cal with date [" + gmtCal.getTime() + "]");

    return gmtCal;
}

هنا هو الإخراج إذا كنت تمر في الوقت الحالي ("12:09:05 بتوقيت شرق الولايات المتحدة" من Calendar.getInstance()) في:

تصحيح المدخلات تقويم تاريخ [الخميس أكتوبر 23 12:09:05 بتوقيت شرق الولايات المتحدة 2008]
تصحيح إزاحة -14400000
التصحيح إنشاء GMT كال مع التاريخ [الخميس أكتوبر 23 08:09:05 بتوقيت شرق الولايات المتحدة 2008]

12:09:05 GMT 8:09:05 بتوقيت شرق الولايات المتحدة.

الجزء مربكة هنا هو أن Calendar.getTime() يعود لك Date في التوقيت الحالي ، كما أن هناك لا توجد طريقة لتعديل التوقيت تقويم ولها تاريخ الأساسية توالت أيضا.اعتمادا على ما نوع من المعلمة الويب الخاص بك يأخذ الخدمة الخاص بك قد ترغب فقط أن يكون WS صفقة من حيث ميلي ثانية من العصر.

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

إذا كانت هذه هي الحالة ، يجب أن نلقي نظرة على setTimeZone طريقة من DateFormat الدرجة.هذا يفرض فيها المنطقة الزمنية التي سيتم استخدامها عند الطباعة ختم الوقت.

مثال بسيط:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));

Calendar cal = Calendar.getInstance();
String timestamp = formatter.format(cal.getTime());

يمكن حل مع Joda الوقت:

Date utcDate = new Date(timezoneFrom.convertLocalToUTC(date.getTime(), false));
Date localDate = new Date(timezoneTo.convertUTCToLocal(utcDate.getTime()));

جافا 8:

LocalDateTime localDateTime = LocalDateTime.parse("2007-12-03T10:15:30");
ZonedDateTime fromDateTime = localDateTime.atZone(
    ZoneId.of("America/Toronto"));
ZonedDateTime toDateTime = fromDateTime.withZoneSameInstant(
    ZoneId.of("Canada/Newfoundland"));

يبدو الطابع الزمني الخاص بك يتم تعيين المنطقة الزمنية من مصدرها النظام.

هذا هو مستنكر ، ولكن يجب العمل:

cal.setTimeInMillis(ts_.getTime() - ts_.getTimezoneOffset());

غير مستنكر طريقة هي استخدام

Calendar.get(Calendar.ZONE_OFFSET) + Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)

ولكن سوف تحتاج إلى القيام به على جانب العميل ، حيث أن هذا النظام يعرف ما التوقيت في.

طريقة تحويل من أحد التوقيت أخرى(ربما يعمل :) ).

/**
 * Adapt calendar to client time zone.
 * @param calendar - adapting calendar
 * @param timeZone - client time zone
 * @return adapt calendar to client time zone
 */
public static Calendar convertCalendar(final Calendar calendar, final TimeZone timeZone) {
    Calendar ret = new GregorianCalendar(timeZone);
    ret.setTimeInMillis(calendar.getTimeInMillis() +
            timeZone.getOffset(calendar.getTimeInMillis()) -
            TimeZone.getDefault().getOffset(calendar.getTimeInMillis()));
    ret.getTime();
    return ret;
}

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

OP مشكلة في بداية المعالجة:مدخلات المستخدم ساعات ، والتي هي غامضة ، وهي تفسر في غير توقيت غرينيتش التوقيت ؛ عند هذه النقطة القيمة "6:12 EST", والتي يمكن طباعتها بسهولة "11.12 GMT" أو أي التوقيت ولكن لن تغيير إلى "6.12 GMT".

لا توجد وسيلة لجعل SimpleDateFormat أن يوزع "06:12" كما "HH:MM" (المتعثرة المنطقة الزمنية المحلية) الافتراضي إلى التوقيت العالمي بدلا من ذلك ؛ SimpleDateFormat قليلا جدا الذكية لمصلحتها.

ومع ذلك ، يمكنك إقناع أي SimpleDateFormat سبيل المثال إلى استخدام حق المنطقة الزمنية إذا وضعت عليها صراحة في الإدخال:فقط إلحاق سلسلة ثابتة إلى تلقت (كاف التحقق من صحة) "06:12" تحليل "06:12 GMT" كما "HH:MM z".

ليست هناك حاجة صريح من GregorianCalendar الحقول أو استرجاع واستخدام التوقيت الصيفي إزاحة الوقت.

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

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

int offset = TimeZone.getTimeZone(timezoneId).getRawOffset();

timezoneId هو معرف المستخدم الزمنية (مثل EST).

java.الوقت

النهج الحديث يستخدم java.الوقت الفئات التي حلت محل مزعجة إرث التاريخ-الوقت الطبقات المجمعة مع الإصدارات الأقدم من جافا.

على java.sql.Timestamp الدرجة هي واحدة من تلك التركة الطبقات.لم تعد هناك حاجة.بدلا من استخدام Instant أو غيرها من جافا.الوقت الطبقات مباشرة مع قاعدة البيانات الخاصة بك باستخدام JDBC 4.2 والإصدارات الأحدث.

على Instant فئة تمثل لحظة على الجدول الزمني في UTC مع قرار من نانو ثانية (ما يصل إلى تسعة (9) أرقام من الكسر العشري).

Instant instant = myResultSet.getObject( … , Instant.class ) ; 

إذا كان يجب التعامل مع القائمة Timestamp, تحويل على الفور في جافا.الوقت عن طريق التحويل الجديدة أساليب إضافة إلى الطبقات القديمة.

Instant instant = myTimestamp.toInstant() ;

لضبط إلى منطقة زمنية أخرى ، حدد المنطقة الزمنية كما ZoneId الكائن.تحديد الوقت المناسب اسم المنطقة في شكل continent/region, مثل America/Montreal, Africa/Casablanca, أو Pacific/Auckland.أبدا استخدام 3-4 الرسالة الزائفة مناطق مثل EST أو IST كما هي لا صحيح الوقت مناطق غير موحدة ، و لا حتى فريدة من نوعها(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;

تنطبق على Instant لإنتاج ZonedDateTime الكائن.

ZonedDateTime zdt = instant.atZone( z ) ;

لتوليد سلسلة العرض للمستخدم البحث من أجل تجاوز سعة مكدس DateTimeFormatter أن تجد العديد من المناقشات و الأمثلة.

سؤالك هو حقا تسير في الاتجاه الآخر من المستخدم إدخال البيانات إلى التاريخ-الوقت الكائنات.عموما الأفضل لكسر الخاص بك إدخال البيانات إلى قسمين ، تاريخ و وقت من اليوم.

LocalDate ld = LocalDate.parse( dateInput , DateTimeFormatter.ofPattern( "M/d/uuuu" , Locale.US ) ) ;
LocalTime lt = LocalTime.parse( timeInput , DateTimeFormatter.ofPattern( "H:m a" , Locale.US ) ) ;

سؤالك غير واضح.هل ترغب في تفسير التاريخ والوقت التي تم إدخالها من قبل المستخدم في UTC ؟ أو في وقت آخر ؟

إذا كنت تقصد UTC, إنشاء OffsetDateTime مع إزاحة باستخدام ثابت بالتوقيت العالمي ، ZoneOffset.UTC.

OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;

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

ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

للحصول على أبسط كائن دائما في UTC بحكم التعريف, استخراج Instant.

Instant instant = odt.toInstant() ;

...أو...

Instant instant = zdt.toInstant() ; 

إرسال إلى قاعدة البيانات الخاصة بك.

myPreparedStatement.setObject( … , instant ) ;

حول جافا.الوقت

على java.الوقت إطار بنيت في جاوة 8 وما بعدها.هذه الفئات محل مزعجة القديمة تراث التاريخ الوقت الطبقات مثل java.util.Date, Calendar, & SimpleDateFormat.

على Joda الوقت المشروع الآن في وضع الصيانة, تنصح الهجرة إلى java.الوقت فصول.

لمعرفة المزيد ، راجع أوراكل التعليمي.والبحث تجاوز سعة مكدس على العديد من الأمثلة و الشروح.مواصفات JSR 310.

أين يمكن الحصول على جافا.الوقت الطبقات ؟

  • جافا SE 8, جافا SE 9, و في وقت لاحق
    • المدمج في.
    • جزء من معيار API جافا مع المجمعة التنفيذ.
    • جافا 9 يضيف بعض الميزات طفيفة وإصلاحات.
  • Java SE 6 و Java SE 7
    • الكثير من جافا.الوظائف في الوقت عاد استدار إلى جافا 6 & 7 في ThreeTen-Backport.
  • الروبوت
    • الإصدارات الأحدث من الروبوت حزمة تطبيقات جافا.الوقت الطبقات.
    • السابقة الروبوت ، ThreeTenABP المشروع يتكيف ThreeTen-Backport (المذكورة أعلاه).انظر كيفية استخدام ThreeTenABP....

على ThreeTen إضافية المشروع يمتد جافا.الوقت مع فصول إضافية.هذا المشروع هو إثبات أن من الممكن في المستقبل الإضافات جافا.الوقت.قد تجد بعض المعلومات المفيدة في هذه الطبقات هنا مثل Interval, YearWeek, YearQuarter, ، المزيد.

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