third_base 1.0.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 (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