জাভা ব্যবহার করে ক্যালেন্ডার টাইমজোনগুলি কীভাবে পরিচালনা করবেন?


92

আমার একটি টাইমস্ট্যাম্প মান রয়েছে যা আমার অ্যাপ্লিকেশন থেকে আসে। ব্যবহারকারী যে কোনও স্থানীয় সময় অঞ্চলতে থাকতে পারে Z

যেহেতু এই তারিখটি কোনও ওয়েব সার্ভিসের জন্য ব্যবহার করা হয়েছে যা ধরে নেওয়া সময় সর্বদা GMT তে থাকে তাই আমার ব্যবহারকারীর প্যারামিটারটিকে বলার (EST) থেকে (GMT) রূপান্তর করতে হবে। এখানে লাথি: ব্যবহারকারী তার টিজেড সম্পর্কে অজ্ঞান obl তিনি তৈরির তারিখে প্রবেশ করেন যা তিনি ডাব্লুএসে প্রেরণ করতে চান, তাই আমার যা দরকার তা হল:

ব্যবহারকারী প্রবেশ করায় : 5/1/2008 6:12 অপরাহ্ন (EST)
ডাব্লুএস এর প্যারামিটারটি হতে হবে : 5/1/2008 6:12 অপরাহ্ন (GMT)

আমি জানি টাইমস্ট্যাম্পগুলি সর্বদা জিএমটি-তে ডিফল্টরূপে থাকার কথা, তবে প্যারামিটারটি প্রেরণ করার সময়, যদিও আমি টিএস থেকে আমার ক্যালেন্ডার তৈরি করেছি (যা জিএমটি-তে থাকার কথা।) ব্যবহারকারী জিএমটি না থাকলে ঘন্টা সর্বদা বন্ধ থাকে। আমি কী মিস করছি?

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 অপরাহ্ন]


4
আপনি কেন কেবল সময় অঞ্চল পরিবর্তন করছেন এবং তার সাথে তারিখ / সময়কে রূপান্তর করছেন না?
স্পেনসার কামোমস

4
এক সময় অঞ্চলের জাভা তারিখ গ্রহণ করা এবং অন্য সময় অঞ্চলে সেই তারিখটি পাওয়ার জন্য এটি আসল ব্যথা । IE, 5PM EDT নিন এবং 5PM PDT পান।
এমটাইসন

উত্তর:


62
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()) পাস করি তবে এখানে আউটপুট দেওয়া হবে :

DEBUG - ইনপুট ক্যালেন্ডারের তারিখ রয়েছে [থু অক্টোবর 23 12:09:05 EDT ২০০৮]
DEBUG - অফসেট -14400000
DEBUG - তারিখ সহ GMT ক্যাল তৈরি করা হয়েছে [থু অক্টোবর 23 08:09:05 EDT 2008]

12:09:05 GMT 8:09:05 EDT।

এখানে বিভ্রান্তিকর অংশটি হ'ল এটি আপনার বর্তমান টাইমজোনটিতে Calendar.getTime()আপনাকে একটি ফিরিয়ে Dateদেয় এবং কোনও ক্যালেন্ডারের সময় অঞ্চল পরিবর্তন করার এবং অন্তর্নিহিত তারিখটিও ঘূর্ণিত করার কোনও পদ্ধতি নেই। আপনার ওয়েব পরিষেবা কী ধরণের প্যারামিটার নেয় তার উপর নির্ভর করে আপনি কেবল যুগ থেকে মিলিসেকেন্ডগুলির ক্ষেত্রে ডাব্লুএস চুক্তি করতে চাইতে পারেন।


11
আপনি offsetFromUTCএটি যোগ করার পরিবর্তে বিয়োগ করা উচিত নয় ? আপনার উদাহরণ ব্যবহার করে, যদি 12:09 GMT হয় 8:09 EDT (যা সত্য), এবং ব্যবহারকারী "12:09 EDT" তে প্রবেশ করে, আলগোরিদিমটি আমার মতে "16:09 GMT" আউটপুট দেয়।
ডিজনেক্স

29

সাড়া জন্য আপনি সমস্ত ধন্যবাদ। আরও তদন্তের পরে আমি সঠিক উত্তর পেয়েছি। স্কিপ হেড দ্বারা উল্লিখিত হিসাবে, আমার অ্যাপ্লিকেশনটি থেকে যে টাইমস্ট্যাম্পড আমি পেয়েছিলাম তা ব্যবহারকারীর টাইম জোনে সামঞ্জস্য করা হচ্ছে। সুতরাং যদি ব্যবহারকারী 6:12 অপরাহ্নে (EST) প্রবেশ করায় আমি 2:12 PM (GMT) পেতাম। আমার যা প্রয়োজন ছিল তা রূপান্তরটি পূর্বাবস্থায় ফেলার একটি উপায় ছিল যাতে ব্যবহারকারীর দ্বারা প্রবেশ করা সময়টিই আমি ওয়েব সার্ভারের অনুরোধে প্রেরণ করি। আমি এখানে এটি কীভাবে সম্পাদন করেছি:

// 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 অপরাহ্নে (ইএসটি) ব্যবহারকারী প্রবেশ করেছে

বর্তমান ব্যবহারকারীর টাইমজোন: জিএসটি
থেকে ইএসটি বর্তমান অফসেট (ঘন্টা সালে): - 4 (সাধারণত -5, ডিএসটি সামঞ্জস্য করা ছাড়া)
এসিপি থেকে টিএস: 2008-05-01 14: 12: 00.0
ক্যালেন্ডার তারিখ জিএমটি এবং ইউএস_এন লোকেল ব্যবহার করে টিএস থেকে রূপান্তরিত : 5/1/08 6:12 অপরাহ্ণ (GMT)


20

আপনি বলছেন যে তারিখটি ওয়েব পরিষেবাদির সাথে সংযোগে ব্যবহৃত হয়, তাই আমি ধরে নিই যে এটি কোনও সময়ে স্ট্রিংয়ে সিরিয়ালযুক্ত হয়েছে।

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

একটি সাধারণ উদাহরণ:

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());

4
এসডিএফকে রিলিজ দেয়নি কেন নিজস্ব সময় অঞ্চল থাকলে ক্যালেন্ডার টাইমজোন পরিবর্তনের কোনও প্রভাব নেই বলে ভাবছেন!
ক্রিস। জেনকিন্স

টাইমজোন.জেটটাইমজোন ("ইউটিসি") বৈধ নয় যেহেতু ইউটিসি উপলব্ধ
আইডিগুলিতে নেই

টাইমজোন.জেটটাইমজোন ("ইউটিসি") আমার মেশিনে উপলব্ধ। এটি কি জেভিএম নির্ভর?
CodeClimber

4
সেটটাইমজোন () পদ্ধতি সহ দুর্দান্ত ধারণা esome আপনি আমাকে অনেক মাথাব্যথা বাঁচিয়েছেন, অনেক ধন্যবাদ!
বোগদান জুড়াক

4
ঠিক যেটা আমার দরকার ছিল! আপনি ফর্ম্যাটারে সার্ভার টাইম জোন সেট করতে পারেন এবং তারপরে আপনি এটিকে ক্যালেন্ডার ফর্ম্যাটে রূপান্তর করবেন তখন আপনার উদ্বিগ্ন হওয়ার কিছু নেই। এখন পর্যন্ত সেরা পদ্ধতি! গেটটাইমজোনটির জন্য আপনার প্রয়োজন হতে পারে প্রাক্তন: ETD- এর জন্য "GMT-4: 00" ফর্ম্যাটটি ব্যবহার করুন
মাইকেল কার্ন

12

আপনি জোদা সময় দিয়ে এটি সমাধান করতে পারেন :

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"));

তবে আপনি যদি হাইবারনেট 4 ব্যবহার করেন তবে এটির জন্য যত্ন নিন, যা পার্শ্ব নির্ভরতা এবং অতিরিক্ত কনফিগারেশন ব্যতীত সরাসরি উপযুক্ত নয়। তবে এটি তৃতীয় সংস্করণের জন্য ব্যবহার করা সবচেয়ে দ্রুত এবং সহজতম ছিল।
আউবারজিন

8

দেখে মনে হচ্ছে আপনার টাইমস্ট্যাম্পটি উত্পন্ন সিস্টেমের টাইমজোনটিতে সেট করা আছে।

এটি অবচয় করা হয়েছে তবে এটি কাজ করা উচিত:

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

অ-অবমানিত উপায়টি হ'ল ব্যবহার করা

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

তবে এটি ক্লায়েন্টের পক্ষেই করা দরকার, যেহেতু সিস্টেমটি জানে যে এটি টাইমজোনটি কী।


7

এক সময় অঞ্চল থেকে অন্যকে রূপান্তর করার পদ্ধতি (সম্ভবত এটি কার্যকর হয় :))।

/**
 * 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;
}

6

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

ওপি'র সমস্যাটি তার প্রক্রিয়াজাতকরণের শুরুতে ঠিক ঠিক: ব্যবহারকারীরা সময়গুলিকে দ্ব্যর্থহীন, এবং এগুলি স্থানীয়, জিএমটি-বিহীন টাইমজোন দ্বারা ব্যাখ্যা করা হয়; এই মুহুর্তে মানটি "6:12 EST" , যা সহজেই "11.12 GMT" বা অন্য কোনও টাইমজোন হিসাবে মুদ্রণ করা যেতে পারে তবে কখনও "6.12 GMT" তে পরিবর্তন হতে পারে না ।

সিম্পলডিট ফরমেট তৈরির কোনও উপায় নেই যা "06:12" কে "এইচএইচ: এমএম" (স্থানীয় সময় অঞ্চলে ডিফল্ট করা) হিসাবে ইউটিসি-র পরিবর্তে ডিফল্ট করে; সিম্পলডেট ফরমেট তার নিজের ভালোর জন্য কিছুটা স্মার্ট।

যাইহোক, যদি আপনি কোন বোঝাতে পারবে SimpleDateFormat সঠিক সময় Zone ব্যবহার করার উদাহরণ হিসেবে বলা যায় যদি আপনি এটি স্পষ্টভাবে ইনপুট রাখা: এইমাত্র পেলাম (এবং পর্যাপ্তরূপে যাচাই) এর একটি নির্দিষ্ট স্ট্রিং সংযুক্ত "06:12" বিশ্লেষণ করতে "06:12 জিএমটি" যেমন "এইচএইচ: এমএম জেড"

গ্রেগরিয়ানক্যালেন্ডার ক্ষেত্রগুলির সুস্পষ্ট সেটিং বা টাইমজোন এবং দিবালোক সংরক্ষণের সময় অফসেটগুলি পুনরুদ্ধার এবং ব্যবহারের দরকার নেই।

আসল সমস্যাটি হ'ল ইনপুটগুলিকে স্থানীয় টাইমজোন থেকে আলাদা করে, ইউটিসি-তে ডিফল্ট ইনপুট দেয় এবং যে ইনপুটগুলিতে সত্যই একটি স্পষ্ট টাইমজোন ইঙ্গিত লাগে require


4

অতীতে আমার জন্য যে কাজ করেছে তা হ'ল ব্যবহারকারীর টাইমজোন এবং জিএমটির মধ্যে অফসেট (মিলিসেকেন্ডে) নির্ধারণ করা। একবার আপনার অফসেট হয়ে গেলে, উভয় টাইমজোনেই উপযুক্ত সময় পেতে আপনি কেবল যোগ / বিয়োগ করতে পারেন (কোন ধরণের রূপান্তর চলছে তার উপর নির্ভর করে)। আমি সাধারণত একটি ক্যালেন্ডার অবজেক্টের মিলিসেকেন্ড ক্ষেত্র সেট করে এটি সম্পাদন করব, তবে আমি নিশ্চিত যে আপনি এটি সহজেই টাইমস্ট্যাম্প অবজেক্টে প্রয়োগ করতে পারেন। অফসেট পেতে আমি যে কোডটি ব্যবহার করি তা এখানে

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

টাইমজোনআইড হ'ল ব্যবহারকারীর টাইমজোন (যেমন ইএসটি) এর আইডি।


9
কাঁচা অফসেট ব্যবহার করে আপনি ডিএসটি উপেক্ষা করছেন।
ওয়ার্নার লেহম্যান

4
ঠিক এই পদ্ধতিটি বছরের অর্ধ বছরের জন্য ভুল ফলাফল দেয়। ত্রুটির সবচেয়ে খারাপ রূপ।
ডানুবিয়ান নাবিক

1

java.time

আধুনিক পদ্ধতির জাভা.টাইম ক্লাসগুলি ব্যবহার করে যা জাভা-র প্রথম সংস্করণগুলির সাথে বান্ডিলযুক্ত ঝামেলাযুক্ত উত্তরাধিকারের তারিখ-সময় ক্লাসগুলি সরবরাহ করে।

java.sql.Timestampবর্গ ঐ উত্তরাধিকার শ্রেণীর অন্যতম। আর লাগবেনা. পরিবর্তে Instantজেডিবিসি ৪.২ এবং তারপরে আপনার ডাটাবেসের সাথে অন্য জাভা.টাইম ক্লাসগুলি ব্যবহার করুন।

Instantক্লাসে টাইমলাইনে একটি মুহূর্ত প্রতিনিধিত্ব করে ইউটিসি একটি রেজোলিউশনে ন্যানোসেকেন্ড (একসঙ্গে নয় জন (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অনেক আলোচনা এবং উদাহরণ খুঁজে পেতে স্ট্যাক ওভারফ্লো অনুসন্ধান করুন search

আপনার প্রশ্নটি ডেট-টাইম অবজেক্টগুলিতে ব্যবহারকারীর ডেটা-এন্ট্রি থেকে শুরু করে অন্য দিকে যাওয়ার বিষয়ে। আপনার ডেটা-এন্ট্রি দুটি অংশে ভাঙার জন্য সাধারণত সেরা, একটি তারিখ এবং দিনের একটি সময়।

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

আপনার প্রশ্ন পরিষ্কার নয়। আপনি কি ইউটিসিতে থাকার জন্য ব্যবহারকারী দ্বারা প্রবেশের তারিখ এবং সময়টিকে ব্যাখ্যা করতে চান? নাকি অন্য টাইম জোনে?

আপনি যদি ইউটিসি বলতে চান, ইউটিসির OffsetDateTimeজন্য ধ্রুবক ব্যবহার করে অফসেট সহ একটি তৈরি করুন ZoneOffset.UTC

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

যদি আপনি অন্য সময় অঞ্চল বলতে চান, একটি সময় অঞ্চল অবজেক্টের সাথে একত্রিত হন, ক ZoneId। তবে কোন সময় অঞ্চল? আপনি একটি ডিফল্ট সময় অঞ্চল সনাক্ত করতে পারেন। বা, যদি সমালোচনা হয় তবে তাদের অবশ্যই তাদের উদ্দেশ্য সম্পর্কে নিশ্চিত হওয়ার জন্য আপনাকে অবশ্যই নিশ্চিত করতে হবে।

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

সংজ্ঞা অনুসারে সর্বদা ইউটিসিতে থাকা একটি সহজ অবজেক্ট পেতে, একটিটি বের করুন Instant

Instant instant = odt.toInstant() ;

… বা…

Instant instant = zdt.toInstant() ; 

আপনার ডাটাবেসে প্রেরণ করুন।

myPreparedStatement.setObject( … , instant ) ;

জাভা.টাইম সম্পর্কে

Java.time ফ্রেমওয়ার্ক জাভা 8 এবং পরে পাতাটা করা হয়। এই ক্লাসগুলি , & , এর মতো সমস্যাযুক্ত পুরানো উত্তরাধিকারের তারিখ-সময়ের ক্লাসগুলিকে সহায়তা করে ।java.util.DateCalendarSimpleDateFormat

Joda-টাইম প্রকল্প, এখন রক্ষণাবেক্ষণ মোড , মাইগ্রেশনে উপদেশ java.time ক্লাস।

আরও জানতে, ওরাকল টিউটোরিয়াল দেখুন । এবং অনেকগুলি উদাহরণ এবং ব্যাখ্যাগুলির জন্য স্ট্যাক ওভারফ্লো অনুসন্ধান করুন। স্পেসিফিকেশনটি জেএসআর 310

জাভা.টাইম ক্লাস কোথায় পাবেন?

ThreeTen-অতিরিক্ত প্রকল্প অতিরিক্ত শ্রেণীর সাথে java.time প্রসারিত করে। এই প্রকল্পটি জাভা.টাইমে ভবিষ্যতের সম্ভাব্য সংযোজনগুলির একটি প্রমাণ করার ক্ষেত্র। আপনি এখানে কিছু দরকারী শ্রেণীর যেমন খুঁজে পেতে পারেন Interval, YearWeek, YearQuarter, এবং আরো

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