JalaliDate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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