لینوکس، عشق، برنامه نویسی

لینوکس، عشق، برنامه نویسی

در این وبلاگ مطالبی درباره سیستم عامل لینوکس و همچنین درمورد برنامه نویسی و کامپیوتر مینویسم.

دوشنبه, ۲۱ بهمن ۱۳۹۸، ۰۴:۱۱ ب.ظ

 تبدیل تاریخ در جاوا با کتابخانه icu4j شرکت IBM

 

دوستان سلام. من میخاستم تاریخ شمسی رو به میلادی و قمری در زبان جاوا تبدیل کنم. بعد از چندین روز جستجوی های فراوان و صرف وقت بسیار، در نهایت تونستم این کار رو بکنم. در این پست می خوام به شما هم آموزش بدم تا وقت شما مثل من تلف نشه

 

در این پست می خوام اموزش تبدیل انواع تاریخ (شمسی به میلادی، شمسی به قمری، میلادی به شمسی، میلادی به قمری، قمری به شمسی و قمری به میلادی) رو آموزش بدم.

 

اول از همه بگم که با کلاس های خود جاوا نمیتونید این کار رو انجام بدید و بنابراین مجبورید از کد ها و لایبرری هایی که دیگران نوشته اند استفاده کنید.

 

اگه در گوگل سرچ کنید، کد های زیادی برای تبدیل تاریخ در جاوا پیدا میکنید، ولی اکثرا ایراد دارن و در یک محدوده ی زمانی مشخصی خروجی درست میدن و برای بقیه زمان ها خروجی غلط میدن.

 

من بعد از کلی جستجو، یک کتابخانه ی بسیار خوب به نام icu4j پیدا کردم که توسط شرکت معروف IBM برای جاوا توسعه داده شده. این کتابخانه قابلیت های فراوانی داره و یکی از قابلیت هاش تبدیل انواع تاریخ به یکدیگر هست.

 

دوستان عزیز، متاسفانه متاسفانه و باز هم متاسفانه، در اینترنت داکیومنت و مستند سازی خوبی برای این لایبرری و نحوه ی تبدیل تاریخ با اون انجام نشده و شما کل اینترنت رو جستجو کنید شاید یک یا نهایتا دو نمونه کد ازش پیدا کنید. من با کلی بدبختی و آزمون و خطا و صرف کلی وقت تونستم در نهایت باهاش تبدیل تاریخ انجام بدم و در مقاله میخوام به شما هم آموزش بدم.

 

دوستان یک نکته رو همینجا بگم، اصولا مبحث تبدیل تاریخ کار راحتی نیست، مفاهیم بسیار زیادی داره، از جمله سال کبیسه، مبحث timezone و موارد دیگه که مجالش نیست براتون بگم. خب بریم سراغ اصل کار و من براتون چندتا کد مینویسم و تبدیل تاریخ انجام میدیم.

 

دانلود فایل لایبرری icu4j و اضافه کردن ان به اکلیپس:

فایل icu4j.jar رو میتونید از اینجا دانلود کنید و به پروژتون در اکلیپس اضافه کنید (اسکرین شات های زیر رو تماشا کنید).

 

دوستان زمانی که من دارم این پست رو مینویسم اخرین ورژن این لایبرری 65.1 هست. ورژن های جدید تر ممکنه در آینده بیاد. برای دانلود آخرین ورژن لایبرری روی عدد 65.1 کلیک کنید (مطابق عکس زیر)
 



و سپس عکس زیر
 

 

و اما بریم سراغ مثال ها و چندتا نمونه کد براتون بنویسم. اولین مثال رو به هر دو روش مینویسم. اما مثال های بعدی رو فقط با روش دوم.

 

تبدیل تاریخ میلادی به هجری شمسی در جاوا با icu4j: (روش اول)

package finalCal;

import java.time.ZoneId;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.GregorianCalendar;
import com.ibm.icu.util.ULocale;

public class From_Gregorian_to_Persian {

    public  From_Gregorian_to_Persian () {

        ULocale PERSIAN_LOCALE = new ULocale("fa_IR@calendar=persian");
        ULocale GREGORIAN_LOCALE = new ULocale("en@calendar=gregorian");
        ZoneId IRAN_ZONE_ID = ZoneId.of("Asia/Tehran");

        Calendar gregoriancalendar = new GregorianCalendar(GREGORIAN_LOCALE);
        gregorianCalendar.setLenient(false);
        gregoriancal.set(2025, Calendar.AUGUST, 1);

        System.out.println("Gregorian Calendar:\t" + (gregoriancal.get(Calendar.YEAR)) + "/" + ( gregoriancal.get(Calendar.MONTH ) +1) + "/" + gregoriancal.get(Calendar.DATE));

        Calendar persiancal = Calendar.getInstance(PERSIAN_LOCALE);
        persiancal.clear();
        persiancal.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));

        persiancal.setTime(gregoriancal.getTime());

        // Display the date.
        System.out.println("Persian Calendar:\t" + (persiancal.get(Calendar.YEAR) ) + "/" + ( persiancal.get (Calendar.MONTH) + 1 ) + "/" + persiancal.get(Calendar.DATE));

    }

}
Output:

Gregorian Calendar:    2025/8/1
Persian Calendar:    1404/5/10

 

در واقع در کد بالا، لازم نبود که آبجکت    persiancal    رو بسازیم. بدون اون هم میتونستیم تاریخ فارسی رو بدست بیارم. کد پایین رو از روش دوم نوشتم، ببینید

 

تبدیل تاریخ میلادی به هجری شمسی در جاوا با icu4j: (روش دوم)

package finalCal;

import java.time.ZoneId;

import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;

public class From_Gregorian_to_Islamic {

      public From_Gregorian_to_Islamic () {

           
            ULocale PERSIAN_LOCALE = new ULocale("fa@calendar=persian");
            ULocale GREGORIAN_LOCALE = new ULocale("en@calendar=gregorian");
            ZoneId IRAN_ZONE_ID = ZoneId.of("Asia/Tehran");

            Calendar gregorianCalendar = Calendar.getInstance(GREGORIAN_LOCALE);
            gregorianCalendar.setLenient(false);
            gregorianCalendar.clear();
            gregorianCalendar.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));
            // 29 september 2019
            gregorianCalendar.set(2019, 8, 29);

            // full date
            DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, PERSIAN_LOCALE);
            System.out.println(df.format(gregorianCalendar.getTime()));

            // date in "yyyy MMM dd" format
            SimpleDateFormat df1 = new SimpleDateFormat ("yyyy MMM dd", PERSIAN_LOCALE );
            System.out.println(df1.format(gregorianCalendar.getTime()));

            // name of month
            SimpleDateFormat df2 = new SimpleDateFormat (SimpleDateFormat.MONTH, PERSIAN_LOCALE );
            System.out.println(df2.format(gregorianCalendar.getTime()));

            // name of weekday
            SimpleDateFormat df3 = new SimpleDateFormat (SimpleDateFormat.WEEKDAY, PERSIAN_LOCALE );
            System.out.println(df3.format(gregorianCalendar.getTime()));
      }
}
Output:

۱۳۹۸ مهر ۷, یکشنبه
۱۳۹۸ مهر ۰۷
مهر
یکشنبه

 

در مثال بالا باید چند تا نکته رو به شما بگم.


نکته ی اول: اول اینکه اگه در این کد  ULocale PERSIAN_LOCALE = new ULocale("fa_IR@calendar=persian")   اون   fa_IR   رو حذف کنید، نتیجه جالبی میگیرید (نتیجه این میشه که خروجی با حروف فارسی نیست و با حروف انگلیسی هست.  اینجوری :

Output:

AP 1398 Mehr 7, Sun
1398 Mehr 07
Mehr
Sun

نکته ی دوم: اگه در کد      SimpleDateFormat df1 = new SimpleDateFormat ("yyyy MMM dd", PERSIAN_LOCALE )      بجای سه تا MMM دوتا MM بزارید، ماه رو دیگه فارسی نمینویسه، فقط عددشو میگه. اینجوری:

Output:

۱۳۹۸ مهر ۷, یکشنبه
۱۳۹۸ ۰۷ ۰۷
مهر
یکشنبه

 

تبدیل تاریخ میلادی به هجری قمری در جاوا با icu4j:

package finalCal;

import java.time.ZoneId;

import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;

public class From_Gregorian_to_Islamic {

      public From_Gregorian_to_Islamic () {

            ULocale  islamic_LOCALE = new ULocale("ar@calendar=islamic-civil");
            ULocale GREGORIAN_LOCALE = new ULocale("en@calendar=gregorian");
            ZoneId IRAN_ZONE_ID = ZoneId.of("Asia/Tehran");

            Calendar gregorianCalendar = Calendar.getInstance(GREGORIAN_LOCALE);
            gregorianCalendar.setLenient(false);
            gregorianCalendar.clear();
            gregorianCalendar.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));
            // 29 september 2019
            gregorianCalendar.set(2019, 8, 29);

            // full date
            DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, islamic_LOCALE);
            System.out.println(df.format(gregorianCalendar.getTime()));

            // date in "yyyy MMM dd" format
            SimpleDateFormat df1 = new SimpleDateFormat ("yyyy MMM dd", islamic_LOCALE);
            System.out.println(df1.format(gregorianCalendar.getTime()));

            // name of month
            SimpleDateFormat df2 = new SimpleDateFormat (SimpleDateFormat.MONTH, islamic_LOCALE);
            System.out.println(df2.format(gregorianCalendar.getTime()));

            // name of weekday
            SimpleDateFormat df3 = new SimpleDateFormat (SimpleDateFormat.WEEKDAY, islamic_LOCALE);
            System.out.println(df3.format(gregorianCalendar.getTime()));

      }
}
Output:

الأحد، ٢٩ محرم ١٤٤١ هـ
١٤٤١ محرم ٢٩
محرم
الأحد

 

نکته ی اول: در      ULocale islamic_LOCALE = new ULocale("ar@calendar=islamic-civil")      اگه    ar     رو حذف کنید، خروجی بصورت حروف انگلیسی در میاد. مثل زیر:

Output:

AH 1441 Muharram 29, Sun
1441 Muh. 29
Muharram
Sun

 

نکته ی دوم که بسیار مهمه: دوستان، برای تاریخ قمری، سه نوع locale داریم. ینی

          "ar@calendar=islamic-civil"      و       "ar@calendar=islamic"      و       "ar@calendar=ISLAMIC_UMALQURA"        

هر کدوم از اینها ممکنه خروجی متفاوت بده. در یکی از این ها، تعداد روزها در 6 ماهه اول ماه های قمری ثابت در نظر گرفته شده (ینی 31 روز) اما در دیگری ممکنه مثلا ماه دوم قمری یکبار 30 روز باشه و یک بار 29 روز! برای همین در ابتدای این مقاله گفتم که تبدیل تاریخ اصولا مبحث ساده و راحتی نیست. در اینجا فرق این سه locale رو توضیح داده. خودتون بخونید، من که کامل متوجه نشدم.

 

تبدیل تاریخ هجری شمسی به میلادی در جاوا با icu4j: (دوستان، در تبدیل تقویم فارسی به میلادی به مشکل برخوردم. برای بعضی تاریخ ها یک روز اختلاف میاره نمیدونم چرا. من حوصله نکردم دلیلشو پیدا کنم. شما اگه پیدا کردید به منم بگید در کامنت ها)

package finalCal;

import java.time.ZoneId;
import java.util.Date;
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.GregorianCalendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;

public class From_Persian_to_Gregorian {

    public From_Persian_to_Gregorian() {

        ULocale PERSIAN_LOCALE = new ULocale("fa_IR@calendar=persian");
        ULocale GREGORIAN_LOCALE = new ULocale("en@calendar=gregorian");
        ZoneId IRAN_ZONE_ID = ZoneId.of("Asia/Tehran");

        Calendar persiancal = Calendar.getInstance(PERSIAN_LOCALE);
        persiancal.clear();
        persiancal.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));
        persiancal.set(1365, 2, 29);
        System.out.println(persiancal.getTime());


        // date in "yyyy MMM dd" format
        SimpleDateFormat df1 = new SimpleDateFormat ("yyyy MMM dd", GREGORIAN_LOCALE);
        System.out.println(df1.format(persiancal.getTime()));

    }
}
Output:

Thu Jun 19 00:00:00 IRST 1986
1986 Jun 19

 

تبدیل تاریخ هجری شمسی به قمری در جاوا با icu4j:

package finalCal;

import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;

public class From_Persian_to_Islamic {

    public From_Persian_to_Islamic() {

        ULocale PERSIAN_LOCALE = new ULocale("@calendar=persian");
        ULocale islamic_LOCALE = new ULocale("@calendar=islamic-civil");

        Calendar persiancal = Calendar.getInstance(PERSIAN_LOCALE);
        persiancal.setLenient(false);
        persiancal.clear();
        persiancal.setTimeZone(TimeZone.getTimeZone("Asia/Tehran"));

        int persianMonth =9; // mehr دوستان دقت کنید. در این لایبرری، ماه ها از صفر شروع میشن. ینی صفر میشه فروردین
        persiancal.set(1398, persianMonth , 6);

        SimpleDateFormat df2 = new SimpleDateFormat ("yyyy MM dd", PERSIAN_LOCALE);
        System.out.println("Persian Calendar: " + df2.format( persiancal.getTime()));

        SimpleDateFormat df1 = new SimpleDateFormat ("yyyy MM dd", islamic_LOCALE);
        System.out.println("Islamic Calendar: " + df1.format(persiancal.getTime()));

    }
}
Output:

Persian Calendar: 1398 10 06
Islamic Calendar: 1441 04 29


دوستان عزیز، مقاله همینجا تموم شد. امیدوارم این کدها بتونه راهنمای خوبی برای شما جهت کار کردن با این لایبرری باشه و تونسته باشم در وقت شما صرفه جویی کنم و کار شمارو اسان تر کرده باشم. اگر این مقاله به دردتون خورده، حتما واسم کامنت بزارید و نظرتونو بگید :)


و اما نکته ی آخر:
دوستان این لایبرری بسیار قوی هست، کار های زیادی میشه باهاش انجام داد، کارکردش فقط تبدیل تاریخ نیست (هر چند در زمینه تبدیل تاریخ هم میشه کد های دیگری رو به جز کدهای بالایی نوشت. مثلا میتونید بهش یک رنج از تاریخ بدید و بگید در این رنج چند تا سه شنبه وجود داره. دیگه کشف و نوشتن اون کدها رو به خود شما میسپارم :)


من همینقدر تونستم تبدیل تاریخ انجام بدم و کار خودمو راه بندازم، و وظیفه ی خودم دونستم به شما هم آموزش بدم :)


در مورد اون ایرادی که در تبدیل شمسی به میلادی هست و یک روز اختلاف میاره، در اون باره حتما سرچ کنید و دلیلشو پیدا کنید و به منم بگید در کامنت ها. ممنون از همتون :)

 

 

نظرات (۱۱)

۲۸ آبان ۹۹ ، ۰۵:۲۳ امیرمهدی حسینی

تشکر به کارم اومد

 

پاسخ:
خواهش میکنم
۲۸ آبان ۹۹ ، ۰۵:۲۸ امیرمهدی حسینی

در روش اول متد نام شی 

gregorianCalendar

اشتباه تایپی است اصلاح شود

پاسخ:
اصلاح شد ممنون

سلام چطوری روز در سال بگیرم مثلا 25 مهر چندمین روز درسال هست

پاسخ:
سلام. والا منم نتونستم پیدا کنم. تا همون قدری که نوشتم تونستم کارمو راه بندازم. باید تو گوگل بیشتر سرچ کنید

برای تبدیل Gregorian to Jalali

مثلا 2020/12/12 به 1399/10/01 تبدیل کنه متدد کسی کار کرده برای تبدیل

پاسخ:
بالا مثال هایی رو گذاشتم. با اون ها کار کنید

می خوام مقدار از روی دیتابیس بخونه یعنی متغیر باشه مثلا

 
java.util.Calendar gregorianCal = java.util.GregorianCalendar.getInstance();
gregorianCal.set(2016, 2, 30);
اینجا مشکل دارم ماه 2 قرار می دم خروجی صفر
اما این پایین جواب می ده
gregorianCal.set(2016, java.util.Calendar.JUNE, 30);
 

persianCalendar.setTime(gregorianCal.getTime());
System.out.println(persianCalendar.get(Calendar.YEAR));         // 1395
System.out.println(persianCalendar.get(Calendar.MONTH));        // 3
System.out.println(persianCalendar.get(Calendar.DAY_OF_MONTH)); // 10
پاسخ:
شما پکیج اشتباه رو import کردی، چیزی که import کردی  اینه java.util.Calendar 

باید اینو import کنی import com.ibm.icu.util.GregorianCalendar


به کدی که نوشتی دقت کن!

2020, java.util.Calendar.JANUARY, 1

چطروری تبدیل کنم به

2020/01/01

سلام بعد تبدیل میلادی به شمسی معمولا ماه جلو یا عقب مشکلی نیست از add(Calendar.MONTH, -1) استفاده کنیم؟

پاسخ:
سلام منم اونو دقیقا متوجه نشدم که چرا یک ماه رو اختلاف داره ، دلیلشم نتونستم پیدا کنم

سلام

تبدیل تاریخ میلادی به هجری شمسی در جاوا با icu4j: (روش دوم)

 

نمی دانم چرا یک ماه اختلاف دارهممکن از کجا باشه

خدا عمرت بده   متشکر از نوشته های  خوبتون

پاسخ:
سلام ممنونم از شما :) و سپاس از کامنتتان :)

تابع تبدیل میلادی به جلالی

        Calendar calendar = Calendar.getInstance(new ULocale("fa_IR@calendar=persian"));
        DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, new ULocale("fa_IR@calendar=persian"));

        System.out.println(df.format(calendar));

بدون خطا

سلام دوستان مکن راهنمایی کنین من مقدارم روی String هست مصلا 

"String t1 = "1400-01-01

می خوام به کد پایین اضافه کنم تاریخ بر اساس استریگ کاربر می فرسته تبدیل انجام بده ممکن راهنمایی کنین

 

PersianCalendar persianCalendar1 = new PersianCalendar(new Date());
GregorianCalendar gregorianCalendar = new GregorianCalendar();
gregorianCalendar.setTime(persianCalendar1.getTime());
System.out.println("Year:" + gregorianCalendar.get(Calendar.YEAR));
System.out.println("Month:" + (gregorianCalendar.get(Calendar.MONTH) + 1));
System.out.println("Day:" + gregorianCalendar.get(Calendar.DAY_OF_MONTH));

ارسال نظر

ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی