JalaliDate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/CHANGELOG +8 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +1 -0
  4. data/TODO +1 -0
  5. data/lib/jalali_date.rb +273 -0
  6. data/test/test.rb +8 -0
  7. metadata +61 -0
data/CHANGELOG ADDED
@@ -0,0 +1,8 @@
1
+ === History
2
+
3
+ ==== 0.02 - 08.AUG.2008
4
+ * added jalali to geregorian date convertor.
5
+ * added JalaliDate class and ported Date class method to JalaliDate
6
+
7
+ ==== 0.01 - 07.AUG.2008
8
+ * planning the project
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/TODO ADDED
@@ -0,0 +1 @@
1
+ here is the social todo
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'jalali_date'
5
+
6
+ class TC_JalaliDate < Test::Unit::TestCase
7
+
8
+ end
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