58

I'm developing a Java App and I have a timeStamp (in long). I can easily use this code to change it to a Gregorian date:

Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeStamp);

But I need to have the date in Jalali Calendar. I searched but didn't found any good library. Do you know a reliable and good library for converting (or creating dates in Jalali format from timeStamp)? I don't need an implementation or an algorithm, cause this issue is too buggy and has a lot of rules, I need a reliable solution

frogatto
  • 28,539
  • 11
  • 83
  • 129
Saeed
  • 7,262
  • 14
  • 43
  • 63

5 Answers5

84

For better localization and language support, it is often convenient to use the ICU (International Components for Unicode) library from IBM.

The APIs are similar to the standard Java APIs, but add additional support for localization and internationalization (e.g. time and calendar issues, sorting, formatting rules and a regex implementation with proper Unicode support).

To create a Persian calendar and output the formatted date in Farsi, you would e.g. do something like this:

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

...

ULocale locale = new ULocale("fa_IR@calendar=persian");

Calendar calendar = Calendar.getInstance(locale);
DateFormat df = DateFormat.getDateInstance(DateFormat.FULL, locale);

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

This will output:

چهارشنبه ۱۰ اردیبهشت ۱۳۹۳ ه‍.ش.

jarnbjo
  • 33,923
  • 7
  • 70
  • 94
  • which version of ICU you use? – Mehrdad Faraji Jul 09 '15 at 23:24
  • ICU is the best option when you want to convert Jalali date to Gregorian. It's best part is the string parser for Jalali date. none of the other option has this feature. – Pooya Sep 01 '15 at 08:27
  • 1
    @Пуя can you give a code snippet of the conversion? The example above simply displays the current gregorian date to farsi. – ampofila Jan 28 '16 at 09:11
  • @Пуя Now another option exists with parsing capabilities for Persian calendar date strings - see my answer. – Meno Hochschild Feb 09 '16 at 13:57
  • and if you need an instance of **java.util.Calendar**, use: `java.util.Calendar c = CalendarICU.wrap(com.ibm.icu.util.Calendar.getInstance(ulocale));` – Omid Oct 18 '16 at 15:42
  • And what about HMS? Java `Date` shows them by default. – Alireza Mohamadi Feb 16 '17 at 21:04
  • 1
    @ampofila a bit late now `com.ibm.icu.util.Calendar calendar = com.ibm.icu.util.Calendar.getInstance(locale); calendar.setTime(date); com.ibm.icu.text.DateFormat df = com.ibm.icu.text.DateFormat.getDateInstance(DateFormat.FULL, locale)` – V H Apr 18 '17 at 16:29
  • 8
    6 MB library size????? too much. – Iman Marashi Sep 10 '17 at 18:00
  • android already has an icu library but it requires api 24 and above . whaaaaaat? – alireza easazade Feb 18 '19 at 14:03
  • I added a year to the current date and it showed a wrong day! I don't think it is a good solution. – mohamad ali gharat Jun 25 '19 at 13:49
  • @mohamadaligharat Assuming that you have made sure that your own software is correct, why don't you report a bug to the ICU team instead of commenting here? This is a 5 year old question and you can't expect that anyone here will feel responsible for your problems. – jarnbjo Jun 25 '19 at 14:13
  • I will. But I just wanted to help. As this answer would guide many to an unreliable library I made this statement that after 5 years there is some drawbacks. They can test the API simply by adding a year to it and printing the result. – mohamad ali gharat Jun 25 '19 at 14:33
  • 2
    @mohamadaligharat Considering that there are probably millions of ICU library users who are *not* having any problems with a trivial task like adding a year, I still strongly believe that the problem is in *your* code. Unless you reveal exactly what you are doing, what the ICU library returns and what you expect it to return, it does not help anyone that you are claiming that the library is unreliable. – jarnbjo Jun 25 '19 at 14:43
  • it didnot worked for me – Omid Rostami Oct 10 '21 at 09:25
26

Take a look on this: https://github.com/amirmehdizadeh/JalaliCalendar

The code looks nice, maven based project, a lot of unit tests.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • I tried to convert 5/11/1394 to gregorian using YearMonthDate.jalaliToGregorian and the conversion is wrong. Instead of 25/01/2016 it returns 24/01/2016. – ampofila Jan 28 '16 at 08:44
  • @ampofila Well, this library works as designed, but you have entered a pitfall of its horrible API-style. It uses zero-based months - see [my anwer](http://stackoverflow.com/a/35293883/2491410) where I show at the end how the proposed library of amirmehdizadeh works. – Meno Hochschild Feb 09 '16 at 13:59
  • @MenoHochschild, good to know that there is an alternative to Joda. – AlexR Feb 09 '16 at 14:05
  • Just to note, Joda has its big merits compared with `java.util.Calendar`, (avoiding zero-based months or immutable design) but cannot help here because a) there is no Persian calendar and b) the internationalization is notoriously bad (other regional calendar example: [ethiopic months](https://github.com/JodaOrg/joda-time/issues/270)). – Meno Hochschild Feb 09 '16 at 14:44
  • This class has some bugs for example in Jalali leap dates. I suggest using https://github.com/smhjamali/PersianCalendar_2_1 instead – Amir Keshavarz Jan 04 '17 at 06:17
  • 1
    this is not working..... it has several error – Ali Dec 08 '18 at 07:29
  • it is not in maven repo so i use this answer `https://stackoverflow.com/a/45936351/5456789` that used ibm icu library – Amir Azizkhani Sep 16 '20 at 10:55
10

There is a good library on github which has a very simple API and it has a lot of capabilities and it also it available on mavenCentral :

https://github.com/razeghi71/JalaliCalendar

Mohammad Razeghi
  • 1,574
  • 2
  • 14
  • 33
  • it gives me this error Error:Error converting bytecode to dex: Cause: Dex cannot parse version 52 byte code. This is caused by library dependencies that have been compiled using Java 8 or above. If you are using the 'java' gradle plugin in a library submodule add targetCompatibility = '1.7' sourceCompatibility = '1.7' to that submodule's build.gradle file. any help?? – Amal El-galant Jul 09 '17 at 12:15
  • this one solved my problem. simple solution . simple API. thanks for the library – alireza easazade Feb 18 '19 at 15:59
9

I have developed my own Persian (jalali) calendar in Java within my library Time4J. The implementation deploys the algorithm of Borkowski (valid at least until gregorian year 2129 - no 2025-bug).

Solution for the concrete problem of OP:

// conversion from jalali to gregorian by constructed input
PersianCalendar jalali = PersianCalendar.of(1394, 11, 5);
// or use a safe enum instead of the month number:
// PersianCalendar jalali = PersianCalendar.of(1394, PersianMonth.BAHMAN, 5);

PlainDate gregorian = jalali.transform(PlainDate.class); 
System.out.println(gregorian); // 2016-01-25

// conversion to millis-since-unix (timezone-dependent)
Moment moment1 = gregorian.atStartOfDay().inTimezone(ASIA.TEHRAN);
long millisSinceUnix = TemporalType.MILLIS_SINCE_UNIX.from(moment1);
System.out.println(millisSinceUnix); // 1453667400000L

// conversion of millis-since-unix to jalali (timezone-dependent)
Moment moment2 = TemporalType.MILLIS_SINCE_UNIX.translate(millisSinceUnix);
PlainDate gregorian2 = moment2.toZonalTimestamp(ASIA.TEHRAN).toDate();
System.out.println(gregorian2.transform(PersianCalendar.class)); // AP-1394-11-05

// formatting and parsing in Farsi language using full style
ChronoFormatter<PersianCalendar> f1 = 
    ChronoFormatter.ofStyle(DisplayMode.FULL, new Locale("fa"), PersianCalendar.axis());
System.out.println(f1.format(jalali)); // ه‍.ش. ۱۳۹۴ بهمن ۵, دوشنبه
System.out.println(f1.parse("ه‍.ش. ۱۳۹۴ بهمن ۵, دوشنبه")); // AP-1394-11-05

// formatting in English language using custom pattern
ChronoFormatter<PersianCalendar> f2 = 
    ChronoFormatter.ofPattern(
        "d. MMMM yyyy", PatternType.CLDR, Locale.ENGLISH, PersianCalendar.axis());
System.out.println(f2.format(jalali)); // 5. Bahman 1394

Of course, the calendar offers more features like date arithmetic (adding days or months, calculating the delta in days, months etc.) or field/element-manipulations (easy going to the last day of month etc).

Side notes about other libraries proposed here so far:

The libraries amirmehdizadeh/JalaliCalendar as well as ICU4J both use zero-based months. This can be extremely confusing. Non-intuitive example using amirmehdizadeh's library:

YearMonthDate jalali = new YearMonthDate(1394, 10, 5); // 11th month (Bahman)
YearMonthDate gregorian = JalaliCalendar.jalaliToGregorian(jalali);
System.out.println(gregorian); // 2016/0/25 => 1st month (January)

About internationalization, I don't think that ICU4J offers more than Time4J on the area of Persian calendar since latter one is based on newest CLDR-version v28, too. Time4J actually supports about 25 languages for Persian months and eras (including Farsi and Pashto).

user3399000
  • 353
  • 3
  • 18
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • hello PersianCalendar in Years Of 2023 Has Bug. Best Use time4j-base Package. And Do Not Use Expired Package (Or Nor Updated). – Silent Jan 05 '23 at 19:42
4

You can use JalCal that Jalali(Persian) Calender Convertor in Java:

<dependency>
    <groupId>com.github.sbahmani</groupId>
    <artifactId>jalcal</artifactId>
    <version>1.0</version>
</dependency>

1. Jalali to Gregorian

  Calendar expected4 = Calendar.getInstance(TimeZone.getDefault());
  expected4.set(2014, 7, 5, 1, 23, 1);
  assertThat(JalCal.jalaliToGregorian(1393, 5, 14, 1, 23, 1).toString()).isEqualTo(expected4.getTime().toString());

2. Gregorian to Jalali

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.DAY_OF_MONTH, 5);
    cal.set(Calendar.MONTH, 6);
    cal.set(Calendar.YEAR, 2014);
    cal.set(Calendar.HOUR_OF_DAY, 10);
    cal.set(Calendar.MINUTE, 25);
    cal.set(Calendar.SECOND, 1);
    cal.set(Calendar.MILLISECOND, 0);
    assertThat(JalCal.gregorianToJalali(cal.getTime(), true)).isEqualTo("14/04/1393   10:25:01");
    assertThat(JalCal.gregorianToJalali(new Date(1426883400000l), true)).isEqualTo("01/01/1394   00:00:00");
Sajad Bahmani
  • 17,325
  • 27
  • 86
  • 108