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,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