third_base 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +19 -0
  2. data/README +261 -0
  3. data/benchmark/date.rb +18 -0
  4. data/benchmark/datetime.rb +18 -0
  5. data/bin/third_base +4 -0
  6. data/lib/third_base/compat/date/format.rb +3 -0
  7. data/lib/third_base/compat/date.rb +3 -0
  8. data/lib/third_base/compat.rb +405 -0
  9. data/lib/third_base/date.rb +674 -0
  10. data/lib/third_base/datetime.rb +385 -0
  11. data/lib/third_base.rb +2 -0
  12. data/spec/compat/compat_class_methods_spec.rb +208 -0
  13. data/spec/compat/compat_instance_methods_spec.rb +54 -0
  14. data/spec/compat/date_spec.rb +56 -0
  15. data/spec/compat/datetime_spec.rb +77 -0
  16. data/spec/compat_spec_helper.rb +2 -0
  17. data/spec/date/accessor_spec.rb +134 -0
  18. data/spec/date/add_month_spec.rb +28 -0
  19. data/spec/date/add_spec.rb +24 -0
  20. data/spec/date/boat_spec.rb +31 -0
  21. data/spec/date/civil_spec.rb +47 -0
  22. data/spec/date/commercial_spec.rb +34 -0
  23. data/spec/date/constants_spec.rb +18 -0
  24. data/spec/date/downto_spec.rb +17 -0
  25. data/spec/date/eql_spec.rb +9 -0
  26. data/spec/date/hash_spec.rb +13 -0
  27. data/spec/date/julian_spec.rb +13 -0
  28. data/spec/date/leap_spec.rb +19 -0
  29. data/spec/date/minus_month_spec.rb +26 -0
  30. data/spec/date/minus_spec.rb +47 -0
  31. data/spec/date/ordinal_spec.rb +13 -0
  32. data/spec/date/parse_spec.rb +227 -0
  33. data/spec/date/step_spec.rb +55 -0
  34. data/spec/date/strftime_spec.rb +132 -0
  35. data/spec/date/strptime_spec.rb +118 -0
  36. data/spec/date/succ_spec.rb +16 -0
  37. data/spec/date/today_spec.rb +11 -0
  38. data/spec/date/upto_spec.rb +17 -0
  39. data/spec/date_spec_helper.rb +3 -0
  40. data/spec/datetime/accessor_spec.rb +53 -0
  41. data/spec/datetime/add_spec.rb +36 -0
  42. data/spec/datetime/boat_spec.rb +43 -0
  43. data/spec/datetime/constructor_spec.rb +58 -0
  44. data/spec/datetime/eql_spec.rb +11 -0
  45. data/spec/datetime/minus_spec.rb +65 -0
  46. data/spec/datetime/now_spec.rb +14 -0
  47. data/spec/datetime/parse_spec.rb +338 -0
  48. data/spec/datetime/strftime_spec.rb +102 -0
  49. data/spec/datetime/strptime_spec.rb +84 -0
  50. data/spec/datetime_spec_helper.rb +3 -0
  51. data/spec/spec_helper.rb +54 -0
  52. metadata +107 -0
@@ -0,0 +1,385 @@
1
+ require 'third_base/date'
2
+
3
+ module ThirdBase
4
+ # ThirdBase's DateTime class, which builds on the Date class and adds a time component of
5
+ # hours, minutes, seconds, microseconds, and an offset from UTC.
6
+ class DateTime < Date
7
+
8
+ PARSER_LIST = []
9
+ DEFAULT_PARSER_LIST = [:time, :iso, :us, :num]
10
+ DEFAULT_PARSERS = {}
11
+ TIME_RE_STRING = '(?:[T ]?([\d ]?\d):(\d\d)(?::(\d\d(\.\d+)?))?([ap]m?)? ?(Z|[+-](?:\d\d:?(?:\d\d)?))?)?'
12
+ DEFAULT_PARSERS[:time] = [[%r{\A#{TIME_RE_STRING}\z}io, proc do |m|
13
+ unless m[0] == ''
14
+ t = Time.now
15
+ add_parsed_time_parts(m, {:civil=>[t.year, t.mon, t.day]}, 1)
16
+ end
17
+ end]]
18
+ DEFAULT_PARSERS[:iso] = [[%r{\A(-?\d{4})[-./ ](\d\d)[-./ ](\d\d)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[m[1].to_i, m[2].to_i, m[3].to_i])}]]
19
+ DEFAULT_PARSERS[:us] = [[%r{\A(\d\d?)[-./ ](\d\d?)[-./ ](\d\d(?:\d\d)?)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[two_digit_year(m[3]), m[1].to_i, m[2].to_i])}],
20
+ [%r{\A(\d\d?)/(\d?\d)#{TIME_RE_STRING}\z}o, proc{|m| add_parsed_time_parts(m, {:civil=>[Time.now.year, m[1].to_i, m[2].to_i]}, 3)}],
21
+ [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?,?(?:[-./ ](-?(?:\d\d(?:\d\d)?)))?#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[m[3] ? two_digit_year(m[3]) : Time.now.year, MONTH_NUM_MAP[m[1].downcase], m[2].to_i])}],
22
+ [%r{\A(\d\d?)(?:st|nd|rd|th)?[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[m[3].to_i, MONTH_NUM_MAP[m[2].downcase], m[1].to_i])}],
23
+ [%r{\A(-?\d{4})[-./ ]#{MONTHNAME_RE_PATTERN}[-./ ](\d\d?)(?:st|nd|rd|th)?#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[m[1].to_i, MONTH_NUM_MAP[m[2].downcase], m[3].to_i])}],
24
+ [%r{\A#{MONTHNAME_RE_PATTERN}[-./ ](-?\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, {:civil=>[m[2].to_i, MONTH_NUM_MAP[m[1].downcase], 1]}, 3)}]]
25
+ DEFAULT_PARSERS[:eu] = [[%r{\A(\d\d?)[-./ ](\d\d?)[-./ ](\d{4})#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[m[3].to_i, m[2].to_i, m[1].to_i])}],
26
+ [%r{\A(\d\d?)[-./ ](\d?\d)[-./ ](\d?\d)#{TIME_RE_STRING}\z}io, proc{|m| add_parsed_time_parts(m, :civil=>[two_digit_year(m[1]), m[2].to_i, m[3].to_i])}]]
27
+ DEFAULT_PARSERS[:num] = [[%r{\A(\d{2,8})#{TIME_RE_STRING}\z}io, proc do |n|
28
+ m = n[1]
29
+ add_parsed_time_parts(n, (
30
+ case m.length
31
+ when 2
32
+ t = Time.now
33
+ {:civil=>[t.year, t.mon, m.to_i]}
34
+ when 3
35
+ {:ordinal=>[Time.now.year, m.to_i]}
36
+ when 4
37
+ {:civil=>[Time.now.year, m[0..1].to_i, m[2..3].to_i]}
38
+ when 5
39
+ {:ordinal=>[two_digit_year(m[0..1]), m[2..4].to_i]}
40
+ when 6
41
+ {:civil=>[two_digit_year(m[0..1]), m[2..3].to_i, m[4..5].to_i]}
42
+ when 7
43
+ {:ordinal=>[m[0..3].to_i, m[4..6].to_i]}
44
+ when 8
45
+ {:civil=>[m[0..3].to_i, m[4..5].to_i, m[6..7].to_i]}
46
+ end
47
+ ), 2)
48
+ end
49
+ ]]
50
+
51
+ STRPTIME_PROC_H = proc{|h,x| h[:hour] = x.to_i}
52
+ STRPTIME_PROC_M = proc{|h,x| h[:min] = x.to_i}
53
+ STRPTIME_PROC_P = proc{|h,x| h[:meridian] = x.downcase == 'pm' ? :pm : :am}
54
+ STRPTIME_PROC_S = proc{|h,x| h[:sec] = x.to_i}
55
+ STRPTIME_PROC_s = proc do |h,x|
56
+ j, i = x.to_i.divmod(86400)
57
+ hours, i = i.divmod(3600)
58
+ minutes, seconds = i.divmod(60)
59
+ h.merge!(:jd=>j+UNIXEPOCH, :hour=>hours, :min=>minutes, :sec=>seconds)
60
+ end
61
+ STRPTIME_PROC_z = proc{|h,x| x=x.gsub(':',''); h[:offset] = (x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60)}
62
+
63
+ # Public Class Methods
64
+
65
+ # Create a new DateTime with the given year, month, day of month, hour, minute, second, microsecond and offset.
66
+ def self.civil(year, mon, day, hour=0, min=0, sec=0, usec=0, offset=0)
67
+ new!(:civil=>[year, mon, day], :parts=>[hour, min, sec, usec], :offset=>offset)
68
+ end
69
+
70
+ # Create a new DateTime with the given commercial week year, commercial week, commercial week day, hour, minute
71
+ # second, microsecond, and offset.
72
+ def self.commercial(cwyear, cweek, cwday=5, hour=0, min=0, sec=0, usec=0, offset=0)
73
+ new!(:commercial=>[cwyear, cweek, cwday], :parts=>[hour, min, sec, usec], :offset=>offset)
74
+ end
75
+
76
+ # Create a new DateTime with the given julian date, hour, minute, second, microsecond, and offset.
77
+ def self.jd(jd, hour=0, min=0, sec=0, usec=0, offset=0)
78
+ new!(:jd=>jd, :parts=>[hour, min, sec, usec], :offset=>offset)
79
+ end
80
+
81
+ # Create a new DateTime with the given julian day, fraction of the day (0.5 is Noon), and offset.
82
+ def self.jd_fract(jd, fract=0.0, offset=0)
83
+ new!(:jd=>jd, :fract=>fract, :offset=>offset)
84
+ end
85
+
86
+ # Create a new DateTime with the current date and time.
87
+ def self.now
88
+ t = Time.now
89
+ new!(:civil=>[t.year, t.mon, t.day], :parts=>[t.hour, t.min, t.sec, t.usec], :offset=>t.utc_offset)
90
+ end
91
+
92
+ # Create a new DateTime with the given year, day of year, hour, minute, second, microsecond, and offset.
93
+ def self.ordinal(year, yday, hour=0, min=0, sec=0, usec=0, offset=0)
94
+ new!(:ordinal=>[year, yday], :parts=>[hour, min, sec, usec], :offset=>offset)
95
+ end
96
+
97
+ # Private Class Methods
98
+
99
+ def self._expand_strptime_format(v)
100
+ case v
101
+ when '%c' then '%a %b %e %H:%M:%S %Y'
102
+ when '%T', '%X' then '%H:%M:%S'
103
+ when '%R' then '%H:%M'
104
+ when '%r' then '%I:%M:%S %p'
105
+ when '%+' then '%a %b %e %H:%M:%S %z %Y'
106
+ else super(v)
107
+ end
108
+ end
109
+
110
+ def self._strptime_part(v)
111
+ case v
112
+ when 'H', 'I' then ['(\d\d)', STRPTIME_PROC_H]
113
+ when 'k', 'l' then ['(\d?\d)', STRPTIME_PROC_H]
114
+ when 'M' then ['(\d\d)', STRPTIME_PROC_M]
115
+ when 'P', 'p' then ['([ap]m)', STRPTIME_PROC_P]
116
+ when 'S' then ['(\d\d)', STRPTIME_PROC_S]
117
+ when 's' then ['(\d+)', STRPTIME_PROC_s]
118
+ when 'z', 'Z' then ['(Z|[+-](?:\d{4}|\d\d:\d\d))', STRPTIME_PROC_z]
119
+ else super(v)
120
+ end
121
+ end
122
+
123
+ # m:
124
+ # * i + 0 : hour
125
+ # * i + 1 : minute
126
+ # * i + 2 : second
127
+ # * i + 3 : sec fraction
128
+ # * i + 4 : meridian indicator
129
+ # * i + 5 : time zone
130
+ def self.add_parsed_time_parts(m, h, i=4)
131
+ hour = m[i].to_i
132
+ meridian = m[i+4]
133
+ hour = hour_with_meridian(hour, /a/io.match(meridian) ? :am : :pm) if meridian
134
+ offset = if m[i+5]
135
+ x = m[i+5].gsub(':','')
136
+ x == 'Z' ? 0 : x[0..2].to_i*3600 + x[3..4].to_i*60
137
+ else
138
+ Time.now.utc_offset
139
+ end
140
+ h.merge!(:parts=>[hour, m[i+1].to_i, m[i+2].to_i, (m[i+3].to_f/0.000001).to_i], :offset=>offset)
141
+ h
142
+ end
143
+
144
+ def self.default_parser_hash
145
+ DEFAULT_PARSERS
146
+ end
147
+
148
+ def self.default_parser_list
149
+ DEFAULT_PARSER_LIST
150
+ end
151
+
152
+ def self.hour_with_meridian(hour, meridian)
153
+ raise(ArgumentError, 'invalid date') unless hour and hour >= 1 and hour <= 12
154
+ if meridian == :am
155
+ hour == 12 ? 0 : hour
156
+ else
157
+ hour < 12 ? hour + 12 : hour
158
+ end
159
+ end
160
+
161
+ def self.new_from_parts(date_hash)
162
+ date_hash[:hour] = hour_with_meridian(date_hash[:hour], date_hash[:meridian]) if date_hash[:meridian]
163
+ d = now
164
+ weights = {:cwyear=>1, :year=>1, :cweek=>2, :cwday=>3, :yday=>3, :month=>2, :day=>3, :hour=>4, :min=>5, :sec=>6}
165
+ columns = {}
166
+ min = 7
167
+ max = 0
168
+ date_hash.each do |k,v|
169
+ if w = weights[k]
170
+ min = w if w < min
171
+ max = w if w > max
172
+ end
173
+ end
174
+ offset = date_hash[:offset] || d.offset
175
+ hour = date_hash[:hour] || (min > 4 ? d.hour : 0)
176
+ minute = date_hash[:min] || (min > 5 ? d.min : 0)
177
+ sec = date_hash[:sec] || 0
178
+ if date_hash[:jd]
179
+ jd(date_hash[:jd], hour, minute, sec, 0, offset)
180
+ elsif date_hash[:year] || date_hash[:yday] || date_hash[:month] || date_hash[:day] || !(date_hash[:cwyear] || date_hash[:cweek])
181
+ if date_hash[:yday]
182
+ ordinal(date_hash[:year]||d.year, date_hash[:yday], hour, minute, sec, 0, offset)
183
+ else
184
+ civil(date_hash[:year]||d.year, date_hash[:month]||(min > 2 ? d.mon : 1), date_hash[:day]||(min > 3 ? d.day : 1), hour, minute, sec, 0, offset)
185
+ end
186
+ elsif date_hash[:cwyear] || date_hash[:cweek] || date_hash[:cwday]
187
+ commercial(date_hash[:cwyear]||d.cwyear, date_hash[:cweek]||(min > 2 ? d.cweek : 1), date_hash[:cwday]||(min > 3 ? d.cwday : 1), hour, minute, sec, 0, offset)
188
+ else
189
+ raise ArgumentError, 'invalid date'
190
+ end
191
+ end
192
+
193
+ def self.parser_hash
194
+ PARSERS
195
+ end
196
+
197
+ def self.parser_list
198
+ PARSER_LIST
199
+ end
200
+
201
+ def self.strptime_default
202
+ '%Y-%m-%dT%H:%M:%S'
203
+ end
204
+
205
+ private_class_method :_expand_strptime_format, :_strptime_part, :add_parsed_time_parts, :default_parser_hash, :default_parser_list, :new_from_parts, :parser_hash, :parser_list, :strptime_default
206
+
207
+ reset_parsers!
208
+
209
+ # Instance Methods
210
+
211
+ # This datetime's offset from UTC, in seconds.
212
+ attr_reader :offset
213
+ alias utc_offset offset
214
+
215
+ # Called by DateTime.new!, should be a hash with the following possible keys:
216
+ #
217
+ # * :civil, :commericial, :jd, :ordinal : See ThirdBase::Date#initialize
218
+ # * :fract : The fraction of the day (0.5 is Noon)
219
+ # * :offset : offset from UTC, in seconds.
220
+ # * :parts : an array with 4 elements, hour, minute, second, and microsecond
221
+ #
222
+ # Raises an ArgumentError if an invalid date is used. DateTime objects are immutable once created.
223
+ def initialize(opts)
224
+ @offset = opts[:offset]
225
+ raise(ArgumentError, 'invalid datetime') unless @offset.is_a?(Integer) and @offset <= 43200 and @offset >= -43200
226
+ if opts[:parts]
227
+ @hour, @min, @sec, @usec = opts[:parts]
228
+ raise(ArgumentError, 'invalid datetime') unless @hour.is_a?(Integer) and @min.is_a?(Integer) and @sec.is_a?(Integer) and @usec.is_a?(Integer)
229
+ elsif opts[:fract]
230
+ @fract = opts[:fract]
231
+ raise(ArgumentError, 'invalid datetime') unless @fract.is_a?(Float) and @fract < 1.0 and @fract >= 0.0
232
+ else
233
+ raise(ArgumentError, 'invalid datetime')
234
+ end
235
+ super(opts)
236
+ end
237
+
238
+ # Return a new datetune with the given number of days added to this datetime. If d is a Float
239
+ # adds a fractional date, with possible loss of precision. If d is an integer,
240
+ # the returned date has the same time components as the current date. In both
241
+ # cases, the offset for the new date is the same as for this date.
242
+ def +(d)
243
+ case d
244
+ when Float
245
+ d, f = d.to_f.divmod(1)
246
+ f = fract + f
247
+ m, f = f.divmod(1)
248
+ self.class.jd_fract(jd+d+m, f, @offset)
249
+ when Integer
250
+ new_jd(jd+d)
251
+ else
252
+ raise(TypeError, "d must be a Float or Integer")
253
+ end
254
+ end
255
+
256
+ # Return a new datetune with the given number of days subtracted from this datetime.
257
+ # If d is a DateTime, returns the difference between the two datetimes as a Float,
258
+ # considering both datetimes date, time, and offest.
259
+ def -(d)
260
+ case d
261
+ when self.class
262
+ (jd - d.jd) + (fract - d.fract) + (@offset - d.offset)/86400.0
263
+ when Integer, Float
264
+ self + -d
265
+ else
266
+ raise TypeError, "d should be #{self.class}, Float, or Integer"
267
+ end
268
+ end
269
+
270
+ # Compares two datetimes. If the given datetime is an Integer, returns 1 unless
271
+ # this datetime's time components are all 0, in which case it returns 0.
272
+ # If the given datetime is a Float, calculates this date's julian date plus the
273
+ # date fraction and compares it to the given datetime, and returns 0 only if the
274
+ # two are very close together. This code does not take into account time offsets.
275
+ def <=>(datetime)
276
+ case datetime
277
+ when Integer
278
+ if ((d = (jd <=> datetime)) == 0)
279
+ (hour == 0 and min == 0 and sec == 0 and usec == 0) ? 0 : 1
280
+ else
281
+ d
282
+ end
283
+ when Float
284
+ diff = jd+fract - datetime
285
+ if diff.abs <= 1.15740740740741e-011
286
+ 0
287
+ else
288
+ diff > 0.0 ? 1 : -1
289
+ end
290
+ when self.class
291
+ ((d = super) == 0) && ((d = (hour <=> datetime.hour)) == 0) && ((d = (min <=> datetime.min)) == 0) && ((d = (sec <=> datetime.sec)) == 0) && ((d = (usec <=> datetime.usec)) == 0)
292
+ d
293
+ else
294
+ raise TypeError, "d should be #{self.class}, Float, or Integer"
295
+ end
296
+ end
297
+
298
+ # Two DateTimes are equal only if their dates and time components are the same, not counting the offset.
299
+ def ==(datetime)
300
+ return false unless DateTime === datetime
301
+ super and hour == datetime.hour and min == datetime.min and sec == datetime.sec and usec == datetime.usec
302
+ end
303
+ alias_method :eql?, :==
304
+
305
+ # Returns the fraction of the day for this datetime (Noon is 0.5)
306
+ def fract
307
+ @fract ||= (@hour*3600+@min*60+@sec+@usec/1000000.0)/86400.0
308
+ end
309
+
310
+ # Returns the hour of this datetime.
311
+ def hour
312
+ @hour ||= time_parts[0]
313
+ end
314
+
315
+ # Returns the minute of this datetime.
316
+ def min
317
+ @min ||= time_parts[1]
318
+ end
319
+
320
+ # Returns the second of this datetime.
321
+ def sec
322
+ @sec ||= time_parts[2]
323
+ end
324
+
325
+ # Returns the microsecond of this datetime.
326
+ def usec
327
+ @usec ||= time_parts[3]
328
+ end
329
+
330
+ # Return the offset as a time zone string (+/-HHMM).
331
+ def zone
332
+ strftime('%z')
333
+ end
334
+
335
+ private
336
+
337
+ def _strftime(v)
338
+ case v
339
+ when 'c' then strftime('%a %b %e %H:%M:%S %Y')
340
+ when 'H' then '%02d' % hour
341
+ when 'I' then '%02d' % ((hour % 12).nonzero? or 12)
342
+ when 'k' then '%2d' % hour
343
+ when 'l' then '%2d' % ((hour % 12).nonzero? or 12)
344
+ when 'M' then '%02d' % min
345
+ when 'P' then hour < 12 ? 'am' : 'pm'
346
+ when 'p' then hour < 12 ? 'AM' : 'PM'
347
+ when 'R' then strftime('%H:%M')
348
+ when 'r' then strftime('%I:%M:%S %p')
349
+ when 'S' then '%02d' % sec
350
+ when 's' then '%d' % ((jd - UNIXEPOCH)*86400 + hour*3600 + min*60 + sec - @offset)
351
+ when 'T', 'X' then strftime('%H:%M:%S')
352
+ when '+' then strftime('%a %b %e %H:%M:%S %z %Y')
353
+ when 'Z' then @offset == 0 ? 'Z' : _strftime('z')
354
+ when 'z' then "%+03d:%02d" % (@offset/60).divmod(60)
355
+ else super(v)
356
+ end
357
+ end
358
+
359
+ def fract_to_hmsu(p)
360
+ hour, p = (p.to_f*24).divmod(1)
361
+ min, p = (p*60).divmod(1)
362
+ sec, sec_fract = (p*60).divmod(1)
363
+ [hour, min, sec, (sec_fract*1000000).to_i]
364
+ end
365
+
366
+ def new_civil(y, m, d)
367
+ self.class.new(y, m, d, hour, min, sec, usec, @offset)
368
+ end
369
+
370
+ def new_jd(j)
371
+ self.class.jd(j, hour, min, sec, usec, @offset)
372
+ end
373
+
374
+ def strftime_default
375
+ '%Y-%m-%dT%H:%M:%S%z'
376
+ end
377
+
378
+ def time_parts
379
+ unless @hour && @min && @sec && @usec
380
+ @hour, @min, @sec, @usec = fract_to_hmsu(fract)
381
+ end
382
+ [@hour, @min, @sec, @usec]
383
+ end
384
+ end
385
+ end
data/lib/third_base.rb ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ require 'third_base/datetime'
@@ -0,0 +1,208 @@
1
+ require(File.join(File.dirname(__FILE__), '..', 'compat_spec_helper'))
2
+
3
+ describe ThirdBase::CompatClassMethods do
4
+ it "#new0 should be the same as new!" do
5
+ Date.new0(:jd=>2454156).should == Date.new!(:jd=>2454156)
6
+ end
7
+
8
+ it "#new1 should be the same as jd" do
9
+ Date.new1(2454156).should == Date.jd(2454156)
10
+ end
11
+
12
+ it "#new2 should be the same as ordinal" do
13
+ Date.new2(2008, 10).should == Date.ordinal(2008, 10)
14
+ end
15
+
16
+ it "#new3 should be the same as new" do
17
+ Date.new3(2008, 10, 2).should == Date.new(2008, 10, 2)
18
+ end
19
+
20
+ it "#neww should be the same as commercial" do
21
+ Date.neww(2008, 10, 2).should == Date.commercial(2008, 10, 2)
22
+ end
23
+
24
+ it "#_parse should parse the date string and return a hash" do
25
+ Date._parse('2008-10-20 11:12:13-08:00').should == {:mon=>10, :zone=>'-08:00', :sec=>13, :sec_fraction=>0.0, :year=>2008, :hour=>11, :offset=>-28800, :mday=>20, :min=>12}
26
+ Date._parse('2008-10-20 11:12:13-08:00', true).should == {:mon=>10, :zone=>'-08:00', :sec=>13, :sec_fraction=>0.0, :year=>2008, :hour=>11, :offset=>-28800, :mday=>20, :min=>12}
27
+ end
28
+
29
+ it "#ajd_to_amjd should convert a astronomical julian date to a astronomical modified julian date" do
30
+ Date.ajd_to_amjd(2400002).should == 1
31
+ end
32
+
33
+ it "#ajd_to_amjd should convert a astronomical julian date to a julian date" do
34
+ Date.ajd_to_jd(1).should == 1
35
+ Date.ajd_to_jd(1, 1).should == 1
36
+ end
37
+
38
+ it "#amjd_to_amd should convert a astronomical modified julian date to a astronomical julian date" do
39
+ Date.amjd_to_ajd(1).should == 2400002
40
+ end
41
+
42
+ it "#civil_to_jd should convert a civil date into a Julian day number" do
43
+ Date.civil_to_jd(2007, 2, 24).should == 2454156
44
+ Date.civil_to_jd(2007, 2, 24, 1).should == 2454156
45
+ end
46
+
47
+ it "#commercial_to_jd should convert a commercial date (year - week - day of week) into a Julian day number" do
48
+ Date.commercial_to_jd(2007, 45, 1).should == 2454410
49
+ Date.commercial_to_jd(2007, 45, 1, 1).should == 2454410
50
+ end
51
+
52
+ it "#day_fraction_to_time should convert a fraction of a day to an array of time parts" do
53
+ Date.day_fraction_to_time(0.5).should == [12, 0, 0, 0.0]
54
+ end
55
+
56
+ it "#gregorian? should return whether the first argument is greater than the second" do
57
+ Date.gregorian?(1, 1).should == false
58
+ Date.gregorian?(2, 1).should == true
59
+ end
60
+
61
+ it "#ns? should be the same as gregorian?" do
62
+ Date.ns?(2, 1).should == Date.gregorian?(2, 1)
63
+ end
64
+
65
+ it "#leap? should determine whether a year is a leap year" do
66
+ Date.leap?(1900).should == false
67
+ Date.leap?(1901).should == false
68
+ Date.leap?(1899).should == false
69
+ Date.leap?(1904).should == true
70
+ Date.leap?(1896).should == true
71
+ Date.leap?(1999).should == false
72
+ Date.leap?(2001).should == false
73
+ Date.leap?(2000).should == true
74
+ end
75
+
76
+ it "#gregorian_leap? should be the same as leap?" do
77
+ Date.gregorian_leap?(2000).should == Date.leap?(2000)
78
+ end
79
+
80
+ it "#jd_to_ajd should convert a Julian day into a astronomical julian date" do
81
+ Date.jd_to_ajd(2454156, 0).should == 2454156
82
+ Date.jd_to_ajd(2454156, 1, 1).should == 2454156
83
+ end
84
+
85
+ it "#jd_to_civil should convert a Julian day into a civil date" do
86
+ Date.jd_to_civil(2454156).should == [2007, 2, 24]
87
+ Date.jd_to_civil(2454156, 1).should == [2007, 2, 24]
88
+ end
89
+
90
+ it "#jd_to_commercial should convert a Julian day number into a commercial date" do
91
+ Date.jd_to_commercial(2454410).should == [2007, 45, 1]
92
+ Date.jd_to_commercial(2454410, 1).should == [2007, 45, 1]
93
+ end
94
+
95
+ it "#jd_to_ld should convert a Julian day into a number of days since italian calendar reform day" do
96
+ Date.jd_to_ld(2299161).should == 1
97
+ end
98
+
99
+ it "#jd_to_mjd should convert a Julian day into a modified julian date" do
100
+ Date.jd_to_mjd(2400002).should == 1
101
+ end
102
+
103
+ it "#jd_to_ordinal should convert a Julian day number into an ordinal date" do
104
+ Date.jd_to_ordinal(2454156).should == [2007, 55]
105
+ Date.jd_to_ordinal(2454156, 1).should == [2007, 55]
106
+ end
107
+
108
+ it "#jd_to_wday should be able to convert a Julian day number into a week day number" do
109
+ Date.jd_to_wday(2454482).should == 3
110
+ end
111
+
112
+ it "#julian? should return whether the first argument is less than the second" do
113
+ Date.julian?(1, 1).should == false
114
+ Date.julian?(1, 2).should == true
115
+ end
116
+
117
+ it "#os? should be the same as julian?" do
118
+ Date.os?(1, 2).should == Date.julian?(1, 2)
119
+ end
120
+
121
+ it "#julian leap? should determine whether a year is a leap year in the julian calendar" do
122
+ Date.julian_leap?(1900).should == true
123
+ Date.julian_leap?(1901).should == false
124
+ Date.julian_leap?(1899).should == false
125
+ Date.julian_leap?(1904).should == true
126
+ Date.julian_leap?(1896).should == true
127
+ Date.julian_leap?(1999).should == false
128
+ Date.julian_leap?(2001).should == false
129
+ Date.julian_leap?(2000).should == true
130
+ end
131
+
132
+ it "#ld_to_jd should convert a number of days since italian calendar reform day to a julian date" do
133
+ Date.ld_to_jd(1).should == 2299161
134
+ end
135
+
136
+ it "#mjd_to_jd should convert a modified julian date into a julian date" do
137
+ Date.mjd_to_jd(1).should == 2400002
138
+ end
139
+
140
+ it "#ordinal_to_jd should convert an ordinal date (year-day) to a Julian day number" do
141
+ Date.ordinal_to_jd(2007, 55).should == 2454156
142
+ end
143
+
144
+ it "#time_to_day_fraction should convert time parts to a fraction" do
145
+ Date.time_to_day_fraction(12, 0, 0).should == 0.5
146
+ end
147
+
148
+ it "#valid_civil? should return corresponding julian date if valid and nil if not" do
149
+ Date.valid_civil?(2007, 2, 24).should == 2454156
150
+ Date.valid_civil?(2007, 2, 24, 1).should == 2454156
151
+ Date.valid_civil?(2007, 2, 30, 1).should == nil
152
+ end
153
+
154
+ it "#valid_date? should be the same as valid_civil?" do
155
+ Date.valid_date?(2007, 2, 24, 1).should == Date.valid_civil?(2007, 2, 24, 1)
156
+ end
157
+
158
+ it "#exist? should be the same as valid_date?" do
159
+ Date.exist?(2007, 2, 24, 1).should == Date.valid_date?(2007, 2, 24, 1)
160
+ end
161
+
162
+ it "#exist3? should be the same as valid_date?" do
163
+ Date.exist3?(2007, 2, 24, 1).should == Date.valid_date?(2007, 2, 24, 1)
164
+ end
165
+
166
+ it "#valid_commercial? should return corresponding julian date if valid and nil if not" do
167
+ Date.valid_commercial?(2007, 45, 1).should == 2454410
168
+ Date.valid_commercial?(2007, 45, 1, 1).should == 2454410
169
+ Date.valid_commercial?(2007, 54, 1, 1).should == nil
170
+ end
171
+
172
+ it "#existw? should be the same as valid_date?" do
173
+ Date.existw?(2007, 45, 1, 1).should == Date.valid_commercial?(2007, 45, 1, 1)
174
+ end
175
+
176
+ it "#valid_jd? should return the given julian date" do
177
+ Date.valid_jd?(2454156).should == 2454156
178
+ Date.valid_jd?(2454156, 1).should == 2454156
179
+ end
180
+
181
+ it "#exist1? should be the same as valid_jd?" do
182
+ Date.exist1?(2454156, 1).should == Date.valid_jd?(2454156, 1)
183
+ end
184
+
185
+ it "#valid_ordinal? should return corresponding julian date if valid and nil if not" do
186
+ Date.valid_ordinal?(2007, 55).should == 2454156
187
+ Date.valid_ordinal?(2007, 55, 1).should == 2454156
188
+ Date.valid_ordinal?(2007, 367, 1).should == nil
189
+ end
190
+
191
+ it "#exist2? should be the same as valid_ordinal?" do
192
+ Date.exist2?(2007, 55, 1).should == Date.valid_ordinal?(2007, 55)
193
+ end
194
+
195
+ it "#valid_time? should return corresponding day fraction if valid and nil if not" do
196
+ Date.valid_time?(12, 0, 0).should == 0.5
197
+ Date.valid_time?(25, 0, 0).should == nil
198
+ Date.valid_time?(12, 61, 0).should == nil
199
+ Date.valid_time?(12, 0, 61).should == nil
200
+ end
201
+
202
+ it "#zone_to_diff? should return the offset in seconds if a valid time zone, or 0 if not" do
203
+ Date.zone_to_diff('-0800').should == -28800
204
+ Date.zone_to_diff('+08:00').should == 28800
205
+ Date.zone_to_diff('YY').should == 0
206
+ end
207
+
208
+ end
@@ -0,0 +1,54 @@
1
+ require(File.join(File.dirname(__FILE__), '..', 'compat_spec_helper'))
2
+
3
+ describe ThirdBase::CompatInstanceMethods do
4
+ before do
5
+ @d = Date.civil(2008, 10, 11)
6
+ end
7
+
8
+ it "#ajd should be the same as jd" do
9
+ @d.ajd.should == @d.jd
10
+ end
11
+
12
+ it "#amjd should be the astronomical modified julian date" do
13
+ @d.amjd.should == 54750
14
+ end
15
+
16
+ it "#gregorian, #england, #julian, #italy, #new_start, and #newsg should be the same as self" do
17
+ @d.gregorian.should == @d
18
+ @d.england.should == @d
19
+ @d.julian.should == @d
20
+ @d.italy.should == @d
21
+ @d.new_start.should == @d
22
+ @d.newsg.should == @d
23
+ @d.new_start(1).should == @d
24
+ @d.newsg(1).should == @d
25
+ end
26
+
27
+ it "#gregorian? and ns? should be true" do
28
+ @d.gregorian?.should == true
29
+ @d.ns?.should == true
30
+ end
31
+
32
+ it "#julian? and os? should be false" do
33
+ @d.julian?.should == false
34
+ @d.os?.should == false
35
+ end
36
+
37
+ it "#ld should be the days since italian calendar reform day" do
38
+ @d.ld.should == 155591
39
+ end
40
+
41
+ it "#mday should be the same as day" do
42
+ @d.mday.should == @d.day
43
+ end
44
+
45
+ it "#mjd should be the modified julian date" do
46
+ @d.mjd.should == 54750
47
+ end
48
+
49
+ it "#start and #sg should equal 0" do
50
+ @d.start.should == 0
51
+ @d.sg.should == 0
52
+ end
53
+
54
+ end