Jalali Date Library

A lightweight Ruby library for converting, formatting, and parsing Jalali (جلالی/Persian/Shamsi) dates.

Jalalidate provides simple APIs for:

  • Gregorian → Jalali conversion
  • Jalali → Gregorian conversion
  • Jalali date formatting
  • Parsing Persian date strings
  • Working with Persian numerals and month names

Install

Add this line to your application's Gemfile:

 gem 'jalali-date' 

And then execute:

$ bundle install

Or install it manually:

$ gem install jalali-date

Usage

Date conversion and class methods:

require 'jalali_date'

# Create a jalali date object:
j_date = JalaliDate.new(1402,02,25)
#=> <JalaliDate, :year => 1402, :month => 2, :day => 25 >

j_date = JalaliDate.new(Date.today)
#=> <JalaliDate, :year => 1402, :month => 2, :day => 25 >

# Initialize with hour, minute and second
j_date = JalaliDate.new(Time.now)
#=> <JalaliDate, :year => 1402, :month => 2, :day => 25, :hour => 6, :minute => 01, :second => 30 >

# Convert to gregorian date
g_date = j_date.to_gregorian
g_date = j_date.to_g
#=> Mon, 15 May 2023


# Get yesterday, today, or tomorrow in jalali
j_today = JalaliDate.yesterday
#=> <JalaliDate, :year => 1402, :month => 2, :day => 24 >
j_today = JalaliDate.today
#=> <JalaliDate, :year => 1402, :month => 2, :day => 25 >
j_tomorrow = JalaliDate.tomorrow
#=> <JalaliDate, :year => 1402, :month => 2, :day => 26 >
 
# Get year, month, and day
year = j_date.year       #=> 1402
month = j_date.month     #=> 02
day = j_date.day         #=> 25

# Get gregorian year, month, and day
g_year = j_date.g_year   #=> 2023
g_month = j_date.g_month #=> 5
g_day = j_date.g_day     #=> 15

# Get day of the year
dy = j_date.yday #=> 51

# Get the next day
tomorrow = j_date.next
#=> <JalaliDate, :year => 1402, :month => 2, :day => 26 >

# Add and substract days
j_date + 6.days
#=> <JalaliDate, :year => 1402, :month => 2, :day => 31 >
j_date + 1.month
#=> <JalaliDate, :year => 1402, :month => 3, :day => 25 >
j_date + 2.years + 5.month + 12.days
#=> <JalaliDate, :year => 1404, :month => 8, :day => 5 >

# Shift the date with number of month
j_date >> 5
#=> <JalaliDate, :year => 1402, :month => 7, :day => 25 >
j_date << 5
#=> <JalaliDate, :year => 1401, :month => 9, :day => 25 >

# Compare two dates
j_date < j_date.next       #=> true
j_date > j_date.next       #=> false
j_date > j_date.previous   #=> true
j_date <=> j_date.next     #=> -1
j_date <=> j_date          #=> 0
j_date <=> j_date.previous #=> 1

# Cycle through dates in different ways, namely, step, upto and downto
# every 2 days, including j_date, for the next 10 days
j_date.step( j_date + 10 , 2)

# every day, including j_date and the next 5 days
j_date.upto(j_date + 5)

# every day, including j_date and the previous 5 days
j_date.downto(j_date - 5)


# Get day object as array or hash
j_date.to_a     #=> [1405, 2, 25]
j_date.to_hash  #=> {year: 1405, month: 2, day: 25}


# Check for leap year
JalaliDate.leap? 1402
#=> false

# Check for validity of a jalali date
JalaliDate.valid?(1402,02,25)
#=> true

JalaliDate.valid?(1402,12,30)
#=> false

Date formatting:

# Initialize with hour, minute and second
j_date = JalaliDate.new(Time.now)
#=> <JalaliDate, :year => 1402, :month => 2, :day => 25, :hour => 6, :minute => 01, :second => 30 >

j_date.strftime("%a %A %b %B %d %e %j %m %w %y %Y %% %x")
#=> "۲ش دوشنبه اردیبهشت Ordibehesht 25 25 56 2 1 02 1402 % 02/2/25"

j_date.strftime("%X")
#=> "06:01:30"

j_date.strftime("%H:%M - %Y/%n/%d")
#=> "06:01 - 1402/02/25"

Format meanings:

  • [%a] The abbreviated weekday name (۳ش)
  • [%A] The full weekday name (یکشنبه)
  • [%b] The month name (اردیبهشت)
  • [%B] The month name in pinglish (Ordibehesht)
  • [%d] Day of the month (01..31)
  • [%e] Day of the month (1..31)
  • [%j] Day of the year (1..366)
  • [%m] Month of the year (1..12)
  • [%n] Month of the year (01..12)
  • [%w] Day of the week (Sunday is 0, 0..6)
  • [%x] Preferred representation for the date alone, no time in format YY/M/D
  • [%y] Year without a century (00..99)
  • [%Y] Year with century
  • [%H] Hour of the day, 24-hour clock (00..23)
  • [%I] Hour of the day, 12-hour clock (01..12)
  • [%M] Minute of the hour (00..59)
  • [%p] Meridian indicator ("بعد از ظهر" or "قبل از ظهر")
  • [%P] Meridian indicator ("ب.ظ" or "ق.ظ")
  • [%S] Second of the minute (00..60)
  • [%X] Preferred representation for the time alone, no date
  • [%Z] Time zone name
  • [%%] teral %'' character

Parsing Jalali Dates

The parser supports multiple common Persian date formats.

Numeric Formats

JalaliDate.parse('1402/02/25')
JalaliDate.parse('1402-02-25')
JalaliDate.parse('1402.02.25')

Persian Month Names

JalaliDate.parse('25 اردیبهشت 1402')
JalaliDate.parse('اردیبهشت 25 1402')

DateTime Parsing

JalaliDate.parse('1402/02/25 06:01')
JalaliDate.parse('1402/02/25 06:01:30')
JalaliDate.parse('25 اردیبهشت ۱۴۰۲ ساعت ۰۶:۰۱')

Persian Digits

The parser automatically normalizes Persian and Arabic numerals:

JalaliDate.parse('۱۴۰۲/۰۲/۲۵')
JalaliDate.parse('١٤٠۲/٠٢/٢٥')

Tests

Simply run rspec command in the source directory:

$ bundle exec rspec

History

0.3.3 - 17.SEP.2013

  • added %n formatter for numeric representation of a month, with leading zeros, courtesy of Mohsen Alizadeh

0.3.2 - 8.APR.2013

0.3.1 - 26.APR.2011

  • Added ruby 1.9 compatibility, courtesy of Reza

0.3 - 6.JAN.2011

  • JalaiDate could be initialized with Time and DateTime objects
  • More options for strftime method %H,%M,%S,%X,%Z,%I,%p. read docs for more information
  • Added jdate and jcal binaries to access jcal from the command-line
  • Updated some documentations
  • Now using bundler

0.2 - 25.FEB.2010

  • Renamed the gem from JalaliDate to jalalidate
  • Added spec and a full test suite
  • Updated gemspec file for rubygems.org
  • Updated some documentations

0.02 - 8.AUG.2008

  • Added jalali to geregorian date convertor.
  • Added JalaliDate class and ported Date class method to JalaliDate

0.01 - 7.AUG.2008

  • Planning the project

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright (c) 2008-2011 Allen A. Bargi. See LICENSE for details.