third_base 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README +261 -0
- data/benchmark/date.rb +18 -0
- data/benchmark/datetime.rb +18 -0
- data/bin/third_base +4 -0
- data/lib/third_base/compat/date/format.rb +3 -0
- data/lib/third_base/compat/date.rb +3 -0
- data/lib/third_base/compat.rb +405 -0
- data/lib/third_base/date.rb +674 -0
- data/lib/third_base/datetime.rb +385 -0
- data/lib/third_base.rb +2 -0
- data/spec/compat/compat_class_methods_spec.rb +208 -0
- data/spec/compat/compat_instance_methods_spec.rb +54 -0
- data/spec/compat/date_spec.rb +56 -0
- data/spec/compat/datetime_spec.rb +77 -0
- data/spec/compat_spec_helper.rb +2 -0
- data/spec/date/accessor_spec.rb +134 -0
- data/spec/date/add_month_spec.rb +28 -0
- data/spec/date/add_spec.rb +24 -0
- data/spec/date/boat_spec.rb +31 -0
- data/spec/date/civil_spec.rb +47 -0
- data/spec/date/commercial_spec.rb +34 -0
- data/spec/date/constants_spec.rb +18 -0
- data/spec/date/downto_spec.rb +17 -0
- data/spec/date/eql_spec.rb +9 -0
- data/spec/date/hash_spec.rb +13 -0
- data/spec/date/julian_spec.rb +13 -0
- data/spec/date/leap_spec.rb +19 -0
- data/spec/date/minus_month_spec.rb +26 -0
- data/spec/date/minus_spec.rb +47 -0
- data/spec/date/ordinal_spec.rb +13 -0
- data/spec/date/parse_spec.rb +227 -0
- data/spec/date/step_spec.rb +55 -0
- data/spec/date/strftime_spec.rb +132 -0
- data/spec/date/strptime_spec.rb +118 -0
- data/spec/date/succ_spec.rb +16 -0
- data/spec/date/today_spec.rb +11 -0
- data/spec/date/upto_spec.rb +17 -0
- data/spec/date_spec_helper.rb +3 -0
- data/spec/datetime/accessor_spec.rb +53 -0
- data/spec/datetime/add_spec.rb +36 -0
- data/spec/datetime/boat_spec.rb +43 -0
- data/spec/datetime/constructor_spec.rb +58 -0
- data/spec/datetime/eql_spec.rb +11 -0
- data/spec/datetime/minus_spec.rb +65 -0
- data/spec/datetime/now_spec.rb +14 -0
- data/spec/datetime/parse_spec.rb +338 -0
- data/spec/datetime/strftime_spec.rb +102 -0
- data/spec/datetime/strptime_spec.rb +84 -0
- data/spec/datetime_spec_helper.rb +3 -0
- data/spec/spec_helper.rb +54 -0
- 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
|