JalaliDate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +8 -0
- data/MIT-LICENSE +21 -0
- data/README +1 -0
- data/TODO +1 -0
- data/lib/jalali_date.rb +273 -0
- data/test/test.rb +8 -0
- metadata +61 -0
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
== License
|
2
|
+
Copyright (c) 2008 Aziz Ashofte Bargi
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
=== README
|
data/lib/jalali_date.rb
ADDED
@@ -0,0 +1,273 @@
|
|
1
|
+
# :title:JalaliDate
|
2
|
+
#
|
3
|
+
class JalaliDate
|
4
|
+
#:stopdoc:
|
5
|
+
$KCODE = 'u'
|
6
|
+
require 'jcode'
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
GDaysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
10
|
+
JDaysInMonth = [31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29]
|
11
|
+
PERSIAN_MONTH_NAMES = [nil, "فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"]
|
12
|
+
PERSIAN_WEEKDAY_NAMES = ["یکشنبه","دوشنبه","سهشنبه","چهارشنبه","پنجشنبه","جمعه","شنبه"]
|
13
|
+
PERSIAN_ABBR_WEEKDAY_NAMES = ["۱ش","۲ش","۳ش","۴ش","۵ش","ج","ش"]
|
14
|
+
PERSIAN_MERIDIAN_INDICATOR = ["قبل از ظهر","بعد از ظهر"]
|
15
|
+
PERSIAN_ABBR_MERIDIAN_INDICATOR = ["ق.ظ","ب.ظ"]
|
16
|
+
#:startdoc:
|
17
|
+
|
18
|
+
attr_accessor :year,:month,:day
|
19
|
+
attr_reader :g_year, :g_month, :g_day
|
20
|
+
|
21
|
+
|
22
|
+
def initialize(year,month,day)
|
23
|
+
raise ArgumentError, "invalid arguments or invalid Jalali date" unless self.class.valid_date?(year,month,day)
|
24
|
+
@year = year
|
25
|
+
@month = month
|
26
|
+
@day = day
|
27
|
+
@g_year, @g_month, @g_day = self.class.jalali_to_gregorian(year,month,day)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Return a new JalaliDate object but accept a Ruby Date object as the parameter,
|
31
|
+
# rather than 3 values for jalali year, jalali month and jalali date (which is what JalaliDate#new does).
|
32
|
+
def self.build(date)
|
33
|
+
g_to_j(date)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return a JalaliDate object representing today's date in calendar
|
37
|
+
def self.today(date = Time.now)
|
38
|
+
g_to_j(date)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return a JalaliDate object representing yesterday's date in calendar
|
42
|
+
def self.yesterday
|
43
|
+
tod = Time.now
|
44
|
+
today(Date.new(tod.year,tod.month,tod.day) - 1)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return a JalaliDate object representing tomorrow's date in calendar
|
48
|
+
def self.tomorrow
|
49
|
+
tod = Time.now
|
50
|
+
today(Date.new(tod.year,tod.month,tod.day) + 1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Accpets a four digit number as the jalaliyear and returns true if that particular year
|
54
|
+
# is a leap year in jalali calendar otherwise it returns false.
|
55
|
+
def self.leap?(y)
|
56
|
+
[6,22,17,13,9,5,1,30].include?(y%33) ? true : false
|
57
|
+
end
|
58
|
+
|
59
|
+
# Accpets three numbers for year (4 digit), month and day in jalali calendar and checks if it's a
|
60
|
+
# valid date according to jalali calendar or not.
|
61
|
+
def self.valid_date?(y,m,d)
|
62
|
+
(y.class == Fixnum && y > 0 &&
|
63
|
+
m.class == Fixnum && (1..12).include?(m) &&
|
64
|
+
d.class == Fixnum && (((1..JDaysInMonth[m-1]).include?(d)) || (d == 30 && m == 12 && leap?(y) ))
|
65
|
+
) ? true : false
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts a JalaiDate object to Ruby Date object
|
69
|
+
def to_gregorian; Date.new(@g_year,@g_month,@g_day); end;
|
70
|
+
alias :to_g :to_gregorian
|
71
|
+
|
72
|
+
# Returns a string represtation of the JalaliDate object in format like this: y/m/d
|
73
|
+
def to_s() [@year,@month,@day].join("/") end
|
74
|
+
|
75
|
+
# Returns a hash in a format like this: {:year => @year, :month => @month, :day => @day}
|
76
|
+
def to_hash() {:year => @year, :month => @month, :day => @day} end
|
77
|
+
|
78
|
+
# Returns an array in a format like this: [y,m,d]
|
79
|
+
def to_a() [@year,@month,@day] end
|
80
|
+
|
81
|
+
# Adds n days to the current JalaliDate object
|
82
|
+
def +(days) self.class.g_to_j( to_g + days ) end
|
83
|
+
|
84
|
+
# Subtracts n days from the current JalaliDate object
|
85
|
+
def -(days) self.class.g_to_j( to_g - days ) end
|
86
|
+
|
87
|
+
# Compares two JalaliDate objects. acts like Date#<=>
|
88
|
+
def <=>(other) to_g <=> other.to_g end
|
89
|
+
|
90
|
+
# Move JalaliDate object forward by n months
|
91
|
+
def >>(months)
|
92
|
+
y, m = (@year * 12 + (@month - 1) + months).divmod(12)
|
93
|
+
m, = (m + 1) .divmod(1)
|
94
|
+
d = @day
|
95
|
+
d -= 1 until self.class.valid_date?(y, m, d)
|
96
|
+
self.class.new(y,m,d)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Move JalaliDate object backward by n months
|
100
|
+
def <<(months) self >> -months end
|
101
|
+
|
102
|
+
# Return the next day for the current JalaliDate object
|
103
|
+
def next(n=1) self + n end
|
104
|
+
|
105
|
+
# Return the previous day for the current JalaliDate object
|
106
|
+
def previous(n=-1) self - n end
|
107
|
+
alias :succ :next
|
108
|
+
|
109
|
+
# Step the current date forward step days at a time (or backward, if step is negative) until we reach
|
110
|
+
# limit (inclusive), yielding the resultant date at each step.
|
111
|
+
def step(limit, step=1)
|
112
|
+
da = self
|
113
|
+
op = %w(- <= >=)[step <=> 0]
|
114
|
+
while da.__send__(op, limit)
|
115
|
+
yield da
|
116
|
+
da += step
|
117
|
+
end
|
118
|
+
self
|
119
|
+
end
|
120
|
+
|
121
|
+
# Step forward one day at a time until we reach max (inclusive), yielding each date as we go.
|
122
|
+
def upto(max, &block) step(max, +1, &block) end
|
123
|
+
|
124
|
+
# Step backward one day at a time until we reach min (inclusive), yielding each date as we go.
|
125
|
+
def downto(min, &block) step(min, -1, &block) end
|
126
|
+
|
127
|
+
# Return internal object state as a programmer-readable string.
|
128
|
+
def inspect() "#<%#{self.class}: :year => #{@year} , :month => #{@month} , :day => #{@day} >" end
|
129
|
+
|
130
|
+
# Is this a leap year?
|
131
|
+
def leap?() self.class.leap?(@year) end
|
132
|
+
|
133
|
+
# Get the week day of this date. Sunday is day-of-week 0; Saturday is day-of-week 6.
|
134
|
+
def wday() to_g.wday end
|
135
|
+
|
136
|
+
# Get the day-of-the-year of this date.
|
137
|
+
# Farvardin 1 is day-of-the-year 1
|
138
|
+
def yday()
|
139
|
+
m = (@month-2 < 0) ? 0 : @month-2
|
140
|
+
(@month==1) ? @day : @day + JDaysInMonth[0..m].inject(0) {|sum, n| sum + n }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Formats time according to the directives in the given format string. Any text not listed as a directive will be
|
144
|
+
# passed through to the output string.
|
145
|
+
#
|
146
|
+
# Format meaning:
|
147
|
+
#
|
148
|
+
#<tt>%a - The abbreviated weekday name (۳ش)</tt>
|
149
|
+
#<tt>%A - The full weekday name (یکشنبه)</tt>
|
150
|
+
#<tt>%b or %B - The month name (اردیبهشت)</tt>
|
151
|
+
#<tt>%d - Day of the month (1..31)</tt>
|
152
|
+
#<tt>%j - Day of the year (1..366)</tt>
|
153
|
+
#<tt>%m - Month of the year (1..12)</tt>
|
154
|
+
#<tt>%w - Day of the week (Sunday is 0, 0..6)</tt>
|
155
|
+
#<tt>%x - Preferred representation for the date alone, no time in format YY/M/D</tt>
|
156
|
+
#<tt>%y - Year without a century (00..99)</tt>
|
157
|
+
#<tt>%Y - Year with century</tt>
|
158
|
+
#<tt>%% - Literal %'' character</tt>
|
159
|
+
|
160
|
+
# d = JalaliDate.today
|
161
|
+
# d.strftime("Printed on %Y/%m/%d") #=> "Printed on 87/5/26
|
162
|
+
def strftime(format_str = '%Y/%m/%d')
|
163
|
+
clean_fmt = format_str.gsub(/%{2}/, "SUBSTITUTION_MARKER").
|
164
|
+
gsub(/%a/, PERSIAN_ABBR_WEEKDAY_NAMES[wday]).
|
165
|
+
gsub(/%A/, PERSIAN_WEEKDAY_NAMES[wday]).
|
166
|
+
gsub(/%b/, PERSIAN_MONTH_NAMES[@month]).
|
167
|
+
gsub(/%B/, PERSIAN_MONTH_NAMES[@month]).
|
168
|
+
gsub(/%d/, @day.to_s).
|
169
|
+
gsub(/%m/, @month.to_s).
|
170
|
+
gsub(/%Y/, @year.to_s).
|
171
|
+
gsub(/%y/, @year.to_s.slice(2,2)).
|
172
|
+
gsub(/%j/, yday.to_s).
|
173
|
+
gsub(/%w/, wday.to_s).
|
174
|
+
gsub(/%x/, [@year.to_s.slice(2,2),@month,@day].join("/")).
|
175
|
+
gsub(/#{"SUBSTITUTION_MARKER"}/, '%')
|
176
|
+
end
|
177
|
+
alias :format :strftime
|
178
|
+
|
179
|
+
private #-------------------------------------------------------------------------
|
180
|
+
def self.gregorian_to_jalali(year, month, day)
|
181
|
+
gy = year - 1600
|
182
|
+
gm = month - 1
|
183
|
+
gd = day - 1
|
184
|
+
g_day_no = 365*gy + (gy+3)/4 - (gy+99)/100 + (gy+399)/400
|
185
|
+
gm.times { |i| g_day_no += GDaysInMonth[i] }
|
186
|
+
g_day_no += 1 if gm > 1 && ((gy%4 == 0 && gy%100 != 0) || (gy%400 == 0))
|
187
|
+
g_day_no += gd
|
188
|
+
|
189
|
+
j_day_no = g_day_no-79
|
190
|
+
j_np = j_day_no/12053
|
191
|
+
j_day_no %= 12053
|
192
|
+
jy = 979 + 33 * j_np + 4*(j_day_no/1461)
|
193
|
+
j_day_no %= 1461
|
194
|
+
|
195
|
+
if (j_day_no >= 366)
|
196
|
+
jy += (j_day_no - 1)/365
|
197
|
+
j_day_no = (j_day_no - 1) % 365
|
198
|
+
end
|
199
|
+
|
200
|
+
11.times do |i|
|
201
|
+
if j_day_no >= JDaysInMonth[i]
|
202
|
+
j_day_no -= JDaysInMonth[i]
|
203
|
+
$j = i + 1
|
204
|
+
else
|
205
|
+
$j = i
|
206
|
+
break
|
207
|
+
end
|
208
|
+
end
|
209
|
+
jm = $j + 1
|
210
|
+
jd = j_day_no + 1
|
211
|
+
|
212
|
+
[jy, jm, jd]
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.jalali_to_gregorian(year,month,day)
|
216
|
+
jy = year - 979
|
217
|
+
jm = month - 1
|
218
|
+
jd = day - 1
|
219
|
+
j_day_no = 365*jy + (jy/33)*8 + (jy % 33 + 3)/4
|
220
|
+
jm.times { |i| j_day_no += JDaysInMonth[i] }
|
221
|
+
j_day_no += jd
|
222
|
+
|
223
|
+
g_day_no = j_day_no + 79
|
224
|
+
gy = 1600 + 400*(g_day_no/146097)
|
225
|
+
g_day_no %= 146097
|
226
|
+
|
227
|
+
leap = true
|
228
|
+
if g_day_no >= 36525
|
229
|
+
g_day_no -= 1
|
230
|
+
gy += 100 * (g_day_no/36524)
|
231
|
+
g_day_no %= 36524
|
232
|
+
(g_day_no >= 365) ? g_day_no += 1 : leap = false
|
233
|
+
end
|
234
|
+
|
235
|
+
gy += 4 * (g_day_no/1461)
|
236
|
+
g_day_no %= 1461
|
237
|
+
|
238
|
+
if g_day_no >= 366
|
239
|
+
leap = false
|
240
|
+
g_day_no -= 1
|
241
|
+
gy += g_day_no/365
|
242
|
+
g_day_no %= 365
|
243
|
+
end
|
244
|
+
|
245
|
+
11.times do |i|
|
246
|
+
leap_day = (i==1 && leap) ? 1 : 0
|
247
|
+
if g_day_no >= (GDaysInMonth[i] + leap_day )
|
248
|
+
g_day_no -= (GDaysInMonth[i] + leap_day )
|
249
|
+
$g = i + 1
|
250
|
+
else
|
251
|
+
$g = i
|
252
|
+
break
|
253
|
+
end
|
254
|
+
end
|
255
|
+
gm = $g + 1
|
256
|
+
gd = g_day_no + 1
|
257
|
+
|
258
|
+
[gy,gm,gd]
|
259
|
+
end
|
260
|
+
|
261
|
+
# Accept a Date or Time object and return a JalaliDate object
|
262
|
+
def self.g_to_j(date)
|
263
|
+
y,m,d = gregorian_to_jalali(date.year, date.month, date.day)
|
264
|
+
JalaliDate.new(y,m,d)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Accept a JalaliDate and return a Ruby Date object
|
268
|
+
def self.j_to_g(date)
|
269
|
+
y,m,d = jalali_to_gregorian(date.year, date.month, date.day)
|
270
|
+
Date.new(y,m,d)
|
271
|
+
end
|
272
|
+
|
273
|
+
end
|
data/test/test.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: JalaliDate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aziz Ashofte Bargi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-08-25 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: aziz.bargi@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
- CHANGELOG
|
25
|
+
- TODO
|
26
|
+
- MIT-LICENSE
|
27
|
+
files:
|
28
|
+
- lib/jalali_date.rb
|
29
|
+
- test/test.rb
|
30
|
+
- README
|
31
|
+
- CHANGELOG
|
32
|
+
- TODO
|
33
|
+
- MIT-LICENSE
|
34
|
+
has_rdoc: true
|
35
|
+
homepage: http://jalalidate.rubyforge.org
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
version:
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
requirements: []
|
54
|
+
|
55
|
+
rubyforge_project: JalaliDate
|
56
|
+
rubygems_version: 1.0.1
|
57
|
+
signing_key:
|
58
|
+
specification_version: 2
|
59
|
+
summary: A port of class Date in ruby that works based on Jalali Calendar (a.k.a Persian Calendar)
|
60
|
+
test_files:
|
61
|
+
- test/test.rb
|