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,405 @@
1
+ #!/usr/bin/env ruby
2
+ require 'third_base'
3
+
4
+ Object.send(:remove_const, :Date) if Object.const_get(:Date) rescue nil
5
+ Object.send(:remove_const, :DateTime) if Object.const_get(:DateTime) rescue nil
6
+
7
+ module ThirdBase
8
+ MJD_JD = 2400001
9
+ LD_JD = 2299160
10
+ ITALY = 2299161
11
+ ENGLAND = 2361222
12
+ JULIAN = -100000000000000000000000000000000000
13
+ GREGORIAN = 100000000000000000000000000000000000
14
+
15
+ # Compatibility class methods for Date and DateTime, necessary because ruby doesn't
16
+ # support multiple inheritance.
17
+ module CompatClassMethods
18
+ [ %w(os? julian?),
19
+ %w(ns? gregorian?),
20
+ %w(exist1? valid_jd?),
21
+ %w(exist2? valid_ordinal?),
22
+ %w(exist3? valid_date?),
23
+ %w(exist? valid_date?),
24
+ %w(existw? valid_commercial?),
25
+ %w(new0 new!),
26
+ %w(new1 jd),
27
+ %w(new2 ordinal),
28
+ %w(new3 new),
29
+ %w(neww commercial)
30
+ ].each{|old, new| module_eval("def #{old}(*args, &block); #{new}(*args, &block); end")}
31
+
32
+ # Return the parts of the parsed date as a hash witht he following keys:
33
+ #
34
+ # * :hour : hour
35
+ # * :mday : day of month
36
+ # * :min : minute
37
+ # * :mon : month
38
+ # * :offset : time zone offset from UTC in seconds
39
+ # * :sec : second
40
+ # * :sec_fraction : fraction of a second
41
+ # * :year : year
42
+ # * :zone : time zone offset as string
43
+ def _parse(str, comp=false)
44
+ d = DateTime.parse(str)
45
+ {:mon=>d.mon, :zone=>d.zone, :sec=>d.sec, :year=>d.year, :hour=>d.hour, :offset=>d.offset, :mday=>d.day, :min=>d.min, :sec_fraction=>d.usec/1000000.0}
46
+ end
47
+
48
+ # Converts an Astronomical Julian Date to an Astronomical Modified Julian Date (substracts an integer from ajd)
49
+ def ajd_to_amjd(ajd)
50
+ ajd - MJD_JD
51
+ end
52
+
53
+ # Converts an Astronomical Julian Date to a Julian Date (returns ajd, ignores of)
54
+ def ajd_to_jd(ajd, of=0)
55
+ ajd
56
+ end
57
+
58
+ # Converts an Astronomical Modified Julian Date to an Astronomical Julian Date (adds an integer to amjd)
59
+ def amjd_to_ajd(amjd)
60
+ amjd + MJD_JD
61
+ end
62
+
63
+ # Returns the julian date for the given civil date arguments, ignores sg.
64
+ def civil_to_jd(year, mon, day, sg=nil)
65
+ civil(year, mon, day).jd
66
+ end
67
+
68
+ # Returns the julian date for the given commercial date arguments, ignores sg.
69
+ def commercial_to_jd(cwyear, cweek, cwday, sg=nil)
70
+ commercial(cwyear, cweek, cwday).jd
71
+ end
72
+
73
+ # Returns the fraction of the date as an array of hours, minutes, seconds, and fraction on a second.
74
+ def day_fraction_to_time(fr)
75
+ hours, fr = (fr * 24).divmod(1)
76
+ minutes, fr = (fr * 60).divmod(1)
77
+ seconds, sec_fract = (fr * 60).divmod(1)
78
+ [hours, minutes, seconds, sec_fract]
79
+ end
80
+
81
+ # True if jd is greater than sg, false otherwise.
82
+ def gregorian?(jd, sg)
83
+ jd > sg
84
+ end
85
+
86
+ # All years divisible by 4 are leap years in the Gregorian calendar,
87
+ # except for years divisible by 100 and not by 400.
88
+ def leap?(y)
89
+ y % 4 == 0 && y % 100 != 0 || y % 400 == 0
90
+ end
91
+ alias gregorian_leap? leap?
92
+
93
+ # Converts a Julian Date to an Astronomical Julian Date (returns j, ignores fr and of)
94
+ def jd_to_ajd(j, fr, of=0)
95
+ j
96
+ end
97
+
98
+ # Returns [year, month, day] for the given julian date, ignores sg.
99
+ def jd_to_civil(j, sg=nil)
100
+ jd(j).send(:civil)
101
+ end
102
+
103
+ # Returns [cwyear, cweek, cwday] for the given julian date, ignores sg.
104
+ def jd_to_commercial(j, sg=nil)
105
+ jd(j).send(:commercial)
106
+ end
107
+
108
+ # Converts a julian date to the number of days since the adoption of
109
+ # the gregorian calendar in Italy (subtracts an integer from j).
110
+ def jd_to_ld(j)
111
+ j - LD_JD
112
+ end
113
+
114
+ # Convert a Julian Date to a Modified Julian Date (subtracts an integer from j).
115
+ def jd_to_mjd(j)
116
+ j - MJD_JD
117
+ end
118
+
119
+ # Returns [year, yday] for the given julian date, ignores sg.
120
+ def jd_to_ordinal(j, sg=nil)
121
+ jd(j).send(:ordinal)
122
+ end
123
+
124
+ # Returns the day of week for the given julian date.
125
+ def jd_to_wday(j)
126
+ jd(j).wday
127
+ end
128
+
129
+ # Returns true if jd is less than sg, false otherwise.
130
+ def julian?(jd, sg)
131
+ jd < sg
132
+ end
133
+
134
+ # All years divisible by 4 are leap years in the Julian calendar.
135
+ def julian_leap?(y)
136
+ y % 4 == 0
137
+ end
138
+
139
+ # Converts a number of days since the adoption of the gregorian calendar in Italy
140
+ # to a julian date (adds an integer to ld).
141
+ def ld_to_jd(ld)
142
+ ld + LD_JD
143
+ end
144
+
145
+ # Converts a Modified Julian Date to a Julian Date (adds an integer to mjd).
146
+ def mjd_to_jd(mjd)
147
+ mjd + MJD_JD
148
+ end
149
+
150
+ # Converts the given year and day of year to a julian date, ignores sg.
151
+ def ordinal_to_jd(year, yday, sg=nil)
152
+ ordinal(year, yday).jd
153
+ end
154
+
155
+ # Converts the given hour, minute, and second to a fraction of a day as a Float.
156
+ def time_to_day_fraction(h, min, s)
157
+ (h*3600 + min*60 + s)/86400.0
158
+ end
159
+
160
+ # Return the julian date of the given year, month, and day if valid, or nil if not, ignores sg.
161
+ def valid_civil?(year, mon, day, sg=nil)
162
+ civil(year, mon, day).jd rescue nil
163
+ end
164
+ alias valid_date? valid_civil?
165
+
166
+ # Return the julian date of the given commercial week year, commercial week, and commercial
167
+ # week day if valid, or nil if not, ignores sg.
168
+ def valid_commercial?(cwyear, cweek, cwday, sg=nil)
169
+ commercial(cwyear, cweek, cwday).jd rescue nil
170
+ end
171
+
172
+ # Returns the julian date if valid (always returns jd, ignores sg).
173
+ def valid_jd?(jd, sg=nil)
174
+ jd
175
+ end
176
+
177
+ # Return the julian date of the given year and day of year if valid, or nil if not, ignores sg.
178
+ def valid_ordinal?(year, yday, sg=nil)
179
+ ordinal(year, yday).jd rescue nil
180
+ end
181
+
182
+ # Returns the fraction of the day if the time is valid, or nil if the time is not valid.
183
+ def valid_time?(h, min, s)
184
+ h += 24 if h < 0
185
+ min += 60 if min < 0
186
+ s += 60 if s < 0
187
+ return unless ((0..23) === h &&
188
+ (0..59) === min &&
189
+ (0..59) === s) ||
190
+ (24 == h &&
191
+ 0 == min &&
192
+ 0 == s)
193
+ time_to_day_fraction(h, min, s)
194
+ end
195
+
196
+ # Converts a time zone string to a offset from UTC in seconds.
197
+ def zone_to_diff(zone)
198
+ if m = /\A([+-](?:\d{4}|\d\d:\d\d))\z/.match(zone)
199
+ x = m[1].gsub(':','')
200
+ x[0..2].to_i*3600 + x[3..4].to_i*60
201
+ else
202
+ 0
203
+ end
204
+ end
205
+ end
206
+
207
+ # Compatibility instance methods for Date and DateTime, necessary because ruby doesn't
208
+ # support multiple inheritance.
209
+ module CompatInstanceMethods
210
+ # Returns the Astronomical Julian Date for this date (alias for jd)
211
+ def ajd
212
+ jd
213
+ end
214
+
215
+ # Returns the Astronomical Modified Julian Date for this date (jd plus an integer)
216
+ def amjd
217
+ jd - MJD_JD
218
+ end
219
+ alias mjd amjd
220
+
221
+ # Returns self.
222
+ def gregorian
223
+ self
224
+ end
225
+ alias england gregorian
226
+ alias julian gregorian
227
+ alias italy gregorian
228
+
229
+ # True, since the gregorian calendar is always used.
230
+ def gregorian?
231
+ true
232
+ end
233
+ alias ns? gregorian?
234
+
235
+ # False, since the gregorian calendar is never used.
236
+ def julian?
237
+ false
238
+ end
239
+ alias os? julian?
240
+
241
+ # Returns the days since the date of the adoption of the gregorian calendar in Italy
242
+ # (substracts an integer from jd).
243
+ def ld
244
+ jd - LD_JD
245
+ end
246
+
247
+ # Alias for day.
248
+ def mday
249
+ day
250
+ end
251
+
252
+ # Returns self, ignores sg.
253
+ def new_start(sg=nil)
254
+ self
255
+ end
256
+ alias newsg new_start
257
+
258
+ # Returns 0, since the gregorian calendar is always used.
259
+ def start
260
+ 0
261
+ end
262
+ alias sg start
263
+ end
264
+
265
+ # ThirdBase's top level Date compatibility class, striving to be as close as possible
266
+ # to the standard Date class's API.
267
+ class ::Date < Date
268
+ extend CompatClassMethods
269
+ include CompatInstanceMethods
270
+
271
+ # Parse the date using strptime with the given format.
272
+ def self._strptime(str, fmt='%F')
273
+ strptime(str, fmt)
274
+ end
275
+
276
+ # Creates a new Date with the given year, month, and day of month, ignores sg.
277
+ def self.civil(year=-4712, mon=1, day=1, sg=nil)
278
+ super(year, mon, day)
279
+ end
280
+
281
+ # Creates a new Date with the given commercial week year, commercial week, and commercial week day, ignores sg.
282
+ def self.commercial(cwyear=1582, cweek=41, cwday=5, sg=nil)
283
+ super(cwyear, cweek, cwday)
284
+ end
285
+
286
+ # Creates a new Date with the given julian date, ignores sg.
287
+ def self.jd(j=0, sg=nil)
288
+ super(j)
289
+ end
290
+
291
+ # Creates a new Date with the given year and day of year, ignores sg.
292
+ def self.ordinal(year=-4712, yday=1, sg=nil)
293
+ super(year, yday)
294
+ end
295
+
296
+ # Parse given string using ThirdBase::Date's date parser, ignores comp and sg.
297
+ def self.parse(str="-4712-01-01", comp=false, sg=nil)
298
+ super(str)
299
+ end
300
+
301
+ # Parse given string using given format, ignores sg.
302
+ def self.strptime(str="-4712-01-01", fmt='%F', sg=nil)
303
+ super(str, fmt)
304
+ end
305
+
306
+ # Creates a new Date with today's date, ignores sg.
307
+ def self.today(sg=nil)
308
+ super()
309
+ end
310
+
311
+ # Returns a formatted string representing the date.
312
+ def asctime
313
+ strftime('%a %b %e 00:00:00 %Y')
314
+ end
315
+ alias ctime asctime
316
+
317
+ # Returns 0.0, since Date don't have fractional days.
318
+ def day_fraction
319
+ 0.0
320
+ end
321
+ end
322
+
323
+ # ThirdBase's top level DateTime compatibility class, striving to be as close as possible
324
+ # to the standard DateTime class's API.
325
+ class ::DateTime < DateTime
326
+ extend CompatClassMethods
327
+ include CompatInstanceMethods
328
+
329
+ # Parse the datetime using strptime with the given format.
330
+ def self._strptime(str, fmt='%FT%T%z')
331
+ strptime(str, fmt)
332
+ end
333
+
334
+ # Creates a new DateTime with the given year, month, day of month, hour, minute, second, and offset, ignores sg.
335
+ def self.civil(year=-4712, mon=1, day=1, hour=0, min=0, sec=0, offset=0, sg=nil)
336
+ super(year, mon, day, hour, min, sec, 0, (offset*86400).to_i)
337
+ end
338
+
339
+ # Creates a new DateTime with the given commercial week year, commercial week, commercial week day,
340
+ # hour, minute, second, and offset, ignores sg.
341
+ def self.commercial(cwyear=1582, cweek=41, cwday=5, hour=0, min=0, sec=0, offset=0, sg=nil)
342
+ super(cwyear, cweek, cwday, hour, min, sec, 0, (offset*86400).to_i)
343
+ end
344
+
345
+ # Creates a new DateTime with the given julian date, hour, minute, second, and offset, ignores sg.
346
+ def self.jd(j=0, hour=0, min=0, sec=0, offset=0, sg=nil)
347
+ super(j, hour, min, sec, 0, (offset*86400).to_i)
348
+ end
349
+
350
+ # Creates a new DateTime with the given year, day of year, hour, minute, second, and offset, ignores sg.
351
+ def self.ordinal(year=-4712, yday=1, hour=0, min=0, sec=0, offset=0, sg=nil)
352
+ super(year, yday, hour, min, sec, 0, (offset*86400).to_i)
353
+ end
354
+
355
+ # Parse given string using ThirdBase::DateTime's date parser, ignores comp and sg.
356
+ def self.parse(str="-4712-01-01T00:00:00+00:00", comp=false, sg=nil)
357
+ super(str)
358
+ end
359
+
360
+ # Parse given string using given format, ignores sg.
361
+ def self.strptime(str="-4712-01-01T00:00:00+00:00", fmt='%FT%T%z', sg=nil)
362
+ super(str, fmt)
363
+ end
364
+
365
+ # Creates a new DateTime with the current date and time, ignores sg.
366
+ def self.now(sg=nil)
367
+ super()
368
+ end
369
+
370
+ # Returns a formatted string representing the date.
371
+ def asctime
372
+ strftime('%c')
373
+ end
374
+ alias ctime asctime
375
+
376
+ alias day_fraction fract
377
+
378
+ # Returns a new DateTime with the same date and time as this datetime, but with a new offset.
379
+ def new_offset(offset=0)
380
+ self.class.new!(:civil=>civil, :parts=>time_parts, :offset=>(offset*86400).to_i)
381
+ end
382
+ alias newof new_offset
383
+
384
+ # Return the offset as a Float representing the fraction of the day different from UTC.
385
+ def offset
386
+ @offset/86400.0
387
+ end
388
+ alias of offset
389
+
390
+ # Return the offset as a number of seconds from UTC.
391
+ def offset_sec
392
+ @offset
393
+ end
394
+
395
+ # The fraction of a second represented as a fraction of the entire day.
396
+ def sec_fraction
397
+ usec/86400000000.0
398
+ end
399
+ end
400
+ end
401
+
402
+ $:.unshift(File.join(File.dirname(__FILE__), 'compat'))
403
+ require 'date'
404
+ require 'date/format'
405
+ $:.shift