marsdate 1.0.6
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.
- checksums.yaml +7 -0
- data/lib/marsdate.rb +311 -0
- metadata +47 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 46364c46ce4a423c9376c10ec34426467f89d0b8
|
4
|
+
data.tar.gz: adbaec504c348791e582a534838cb7cb17a478fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 09c4472b3934a6b2c07574a30fdd517bdd58f6ad28a70c0ea107530396c5035df45235ef7ff3989bae38466094f52ce516d70fd37c17143308ccdb72dd5d9387
|
7
|
+
data.tar.gz: bfc2eacf38bb51e75858d8a914a85a5b240acc530d0e5205fc99ac2e3f5ce4c04af87c378ab4f8ac9a1abf0eeef032955062a58c4676ef5adaf422948eb475f9
|
data/lib/marsdate.rb
ADDED
@@ -0,0 +1,311 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
class MarsDateTime
|
4
|
+
|
5
|
+
VERSION = "1.0.6"
|
6
|
+
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
MSEC_PER_SOL = 88775244
|
10
|
+
SOLS_PER_MYEAR = 668.5921
|
11
|
+
MSEC_PER_DAY = 86400000
|
12
|
+
|
13
|
+
FAKE_MSEC_PER_MYEAR = (668*MSEC_PER_SOL)
|
14
|
+
|
15
|
+
TimeStretch = MSEC_PER_SOL/MSEC_PER_DAY.to_f
|
16
|
+
|
17
|
+
Months = %w[ UNDEFINED
|
18
|
+
January Gemini February Cancer
|
19
|
+
March Leo April Virgo
|
20
|
+
May Libra June Scorpio
|
21
|
+
July Sagittarius August Capricorn
|
22
|
+
September Aquarius October Pisces
|
23
|
+
November Aries December Taurus ]
|
24
|
+
# no month 0
|
25
|
+
|
26
|
+
Week = %w[ Sunday Monday Tuesday Wednesday Thursday Friday Saturday ]
|
27
|
+
|
28
|
+
EpochMCE = DateTime.new(1,1,21)
|
29
|
+
EpochCE = DateTime.new(1,1,1)
|
30
|
+
FudgeOffset = 67784 + 44000 + 1099 + 87 - 56
|
31
|
+
JulianDay1 = 1721443 # was ...24
|
32
|
+
|
33
|
+
attr_reader :year, :month, :sol, :epoch_sol, :year_sol
|
34
|
+
attr_reader :shr, :smin, :ssec # stretched time
|
35
|
+
attr_reader :mems
|
36
|
+
|
37
|
+
attr_reader :dow, :day_of_week
|
38
|
+
attr_reader :mhrs, :mmin, :msec
|
39
|
+
|
40
|
+
alias myear year
|
41
|
+
alias hr mhrs
|
42
|
+
alias min mmin
|
43
|
+
alias sec msec
|
44
|
+
|
45
|
+
def self.leap?(myear) # class method for convenience
|
46
|
+
return (myear % 2 == 1) if (myear % 10 != 0)
|
47
|
+
return true if (myear % 1000 == 0)
|
48
|
+
return false if (myear % 100 == 0)
|
49
|
+
return true
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.sols_in_month(m, year)
|
53
|
+
return 28 if m < 24
|
54
|
+
return 25 if leap?(year)
|
55
|
+
return 24
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.now
|
59
|
+
d = DateTime.now
|
60
|
+
MarsDateTime.new(d)
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.today
|
64
|
+
d = DateTime.now
|
65
|
+
MarsDateTime.new(d)
|
66
|
+
end
|
67
|
+
|
68
|
+
def leaps(myr)
|
69
|
+
n = 0
|
70
|
+
1.upto(myr) {|i| n+=1 if leap?(i) }
|
71
|
+
n
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_yaml_properties
|
75
|
+
%w[@myear @month @sol @epoch_sol @year_sol @dow @day_of_week @msme @mhrs @mmin @msec]
|
76
|
+
end
|
77
|
+
|
78
|
+
def inspect
|
79
|
+
time = ('%02d' % @mhrs) + ":" + ('%02d' % @mmin) + ":" + ('%02d' % @msec)
|
80
|
+
"#@year/#{'%02d' % @month}/#{'%02d' % @sol} " +
|
81
|
+
"(#@year_sol, #@epoch_sol) #@day_of_week " +
|
82
|
+
time
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
time = self.strftime('%H:%M:%S [%P:%Q:%R]')
|
87
|
+
"#@day_of_week, #{Months[@month]} #@sol, #@year at #{time}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def leap?(myear)
|
91
|
+
MarsDateTime.leap?(myear) # DRY
|
92
|
+
end
|
93
|
+
|
94
|
+
def month_name
|
95
|
+
Months[@month]
|
96
|
+
end
|
97
|
+
|
98
|
+
###########
|
99
|
+
|
100
|
+
def initialize(*params)
|
101
|
+
n = params.size
|
102
|
+
case n
|
103
|
+
when 3..6
|
104
|
+
init_yms(*params)
|
105
|
+
when 0
|
106
|
+
init_datetime(DateTime.now)
|
107
|
+
when 1
|
108
|
+
case params.first
|
109
|
+
when Integer, Float
|
110
|
+
init_mems(params.first)
|
111
|
+
when DateTime
|
112
|
+
init_datetime(params.first)
|
113
|
+
else
|
114
|
+
raise "Expected number or DateTime"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
raise "Bad params: #{params.inspect}"
|
118
|
+
end
|
119
|
+
compute_stretched
|
120
|
+
end
|
121
|
+
|
122
|
+
def check_ymshms(my, mm, msol, mhr=0, mmin=0, msec=0)
|
123
|
+
text = ""
|
124
|
+
text << "year #{my} is not an integer\n" unless my.is_a? Fixnum
|
125
|
+
text << "month #{mm} is out of range" unless (1..24).include? mm
|
126
|
+
text << "sol #{msol} is out of range" unless (1..28).include? msol
|
127
|
+
text << "hour #{mhr} is out of range" unless (0..24).include? mhr
|
128
|
+
text << "minute #{mmin} is out of range" unless (0..59).include? mmin
|
129
|
+
text << "second #{msec} is out of range" unless (0..59).include? msec
|
130
|
+
if !leap?(my) && mm == 24 && msol > 24
|
131
|
+
text << "sol #{msol} is invalid in a non-leap year"
|
132
|
+
end
|
133
|
+
raise text unless text.empty?
|
134
|
+
end
|
135
|
+
|
136
|
+
def init_yms(my, mm, msol, mhr=0, mmin=0, msec=0)
|
137
|
+
check_ymshms(my, mm, msol, mhr, mmin, msec)
|
138
|
+
zsol = msol - 1 # z means zero-based
|
139
|
+
zmy = my - 1 # my means Martian year
|
140
|
+
zesol = zmy*668 + leaps(my-1) + (mm-1)*28 + zsol
|
141
|
+
# @mems is "Martian (time since) epoch in milliseconds"
|
142
|
+
@mems = zesol*MSEC_PER_SOL + (mhr*3600 + mmin*60 + msec)*1000
|
143
|
+
@year, @month, @sol, @mhrs, @mmin, @msec = my, mm, msol, mhr, mmin, msec
|
144
|
+
@epoch_sol = zesol + 1
|
145
|
+
@dow = (@epoch_sol-1) % 7
|
146
|
+
@day_of_week = Week[@dow]
|
147
|
+
@year_sol = (mm-1)*28 + msol
|
148
|
+
end
|
149
|
+
|
150
|
+
def compute_stretched
|
151
|
+
# Handle stretched time...
|
152
|
+
sec = @mhrs*3600 + @mmin*60 + @msec
|
153
|
+
sec /= TimeStretch
|
154
|
+
@shr, sec = sec.divmod(3600)
|
155
|
+
@smin, sec = sec.divmod(60)
|
156
|
+
@ssec = sec.round
|
157
|
+
end
|
158
|
+
|
159
|
+
def init_mems(mems)
|
160
|
+
full_years = 0
|
161
|
+
loop do
|
162
|
+
millisec = FAKE_MSEC_PER_MYEAR
|
163
|
+
millisec += MSEC_PER_SOL if leap?(full_years+1)
|
164
|
+
break if mems < millisec
|
165
|
+
mems -= millisec
|
166
|
+
# puts "Subtracting #{millisec} -- one full year => #{mems}"
|
167
|
+
full_years += 1
|
168
|
+
end
|
169
|
+
|
170
|
+
mspm = MSEC_PER_SOL*28
|
171
|
+
full_months,mems = mems.divmod(mspm)
|
172
|
+
full_days, mems = mems.divmod(MSEC_PER_SOL)
|
173
|
+
full_hrs, mems = mems.divmod(3_600_000)
|
174
|
+
full_min, mems = mems.divmod(60_000)
|
175
|
+
sec = mems/1000.0
|
176
|
+
|
177
|
+
my = full_years + 1 # 1-based
|
178
|
+
mm = full_months + 1
|
179
|
+
ms = full_days + 1
|
180
|
+
mhr = full_hrs # 0-based
|
181
|
+
mmin = full_min
|
182
|
+
msec = sec.to_i
|
183
|
+
frac = sec - msec # fraction of a sec
|
184
|
+
|
185
|
+
# # check for leap year...
|
186
|
+
# if mm == 24
|
187
|
+
# max = leap?(my) ? 25 : 24
|
188
|
+
# diff = ms - max
|
189
|
+
# if diff > 0
|
190
|
+
# my, mm, ms = my+1, 1, diff
|
191
|
+
# end
|
192
|
+
# end
|
193
|
+
|
194
|
+
init_yms(my, mm, ms, mhr, mmin, msec)
|
195
|
+
end
|
196
|
+
|
197
|
+
def init_datetime(dt)
|
198
|
+
days = dt.jd - JulianDay1
|
199
|
+
secs = days*86400 + dt.hour*3600 + dt.min*60 + dt.sec
|
200
|
+
secs -= FudgeOffset
|
201
|
+
init_mems(secs*1000)
|
202
|
+
end
|
203
|
+
|
204
|
+
def ymshms
|
205
|
+
[@year, @month, @sol, @mhrs, @mmin, @msec]
|
206
|
+
end
|
207
|
+
|
208
|
+
def -(other)
|
209
|
+
case other
|
210
|
+
when MarsDateTime
|
211
|
+
diff = @mems - other.mems
|
212
|
+
diff.to_f / MSEC_PER_SOL
|
213
|
+
when DateTime
|
214
|
+
other = MarsDateTime.new(other)
|
215
|
+
diff = @mems - other.mems
|
216
|
+
diff.to_f / MSEC_PER_SOL
|
217
|
+
when Fixnum, Float
|
218
|
+
self + (-other)
|
219
|
+
else
|
220
|
+
raise "Unexpected data type"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def +(sols)
|
225
|
+
millisec = sols * MSEC_PER_SOL
|
226
|
+
MarsDateTime.new(@mems + millisec)
|
227
|
+
end
|
228
|
+
|
229
|
+
def <=>(other)
|
230
|
+
case other
|
231
|
+
when MarsDateTime
|
232
|
+
@mems <=> other.mems
|
233
|
+
when DateTime
|
234
|
+
@mems <=> MarsDateTime.new(other).mems
|
235
|
+
else
|
236
|
+
raise "Invalid comparison"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def earth_date
|
241
|
+
secs = @mems/1000 + FudgeOffset
|
242
|
+
days,secs = secs.divmod(86400)
|
243
|
+
hrs, secs = secs.divmod(3600)
|
244
|
+
min, secs = secs.divmod(60)
|
245
|
+
jday = days + JulianDay1
|
246
|
+
DateTime.jd(jday, hrs, min, secs)
|
247
|
+
end
|
248
|
+
|
249
|
+
def strftime(fmt)
|
250
|
+
str = fmt.dup
|
251
|
+
pieces = str.scan(/(%.|[^%]+)/).flatten
|
252
|
+
final = ""
|
253
|
+
zmonth = '%02d' % @month
|
254
|
+
zsol = '%02d' % @sol
|
255
|
+
zhh = '%02d' % @mhrs # stretched
|
256
|
+
zmm = '%02d' % @mmin
|
257
|
+
zss = '%02d' % @msec
|
258
|
+
zhc = '%02d' % @shr # canonical
|
259
|
+
zmc = '%02d' % @smin
|
260
|
+
zsc = '%02d' % @ssec
|
261
|
+
|
262
|
+
pieces.each do |piece|
|
263
|
+
case piece
|
264
|
+
when "%a"; final << @day_of_week[0..2]
|
265
|
+
when "%A"; final << @day_of_week
|
266
|
+
when "%b"; final << month_name[0..2]
|
267
|
+
when "%B"; final << month_name
|
268
|
+
when "%d"; final << zsol
|
269
|
+
when "%e"; final << ('%2d' % @sol)
|
270
|
+
when "%F"; final << "#@year-#@month-#@sol"
|
271
|
+
when "%H"; final << zhh
|
272
|
+
when "%j"; final << @year_sol.to_s
|
273
|
+
when "%m"; final << @month.to_s
|
274
|
+
when "%M"; final << zmm
|
275
|
+
when "%s"; final << @msec.to_s # was: (@mems*1000).to_i.to_s
|
276
|
+
when "%S"; final << zss
|
277
|
+
when "%u"; final << (@dow + 1).to_s
|
278
|
+
when "%U"; final << (@year_sol/7 + 1).to_s
|
279
|
+
when "%w"; final << @dow.to_s
|
280
|
+
when "%x"; final << "#@year/#{zmonth}/#{zsol}"
|
281
|
+
when "%X"; final << "#{zhh}:#{zmm}:#{zss}"
|
282
|
+
when "%Y"; final << @year.to_s
|
283
|
+
when "%n"; final << "\n"
|
284
|
+
when "%t"; final << "\t"
|
285
|
+
when "%%"; final << "%"
|
286
|
+
when "%P"; final << ("%02d" % @shr)
|
287
|
+
when "%Q"; final << ("%02d" % @smin)
|
288
|
+
when "%R"; final << ("%02d" % @ssec)
|
289
|
+
else
|
290
|
+
final << piece
|
291
|
+
end
|
292
|
+
end
|
293
|
+
final
|
294
|
+
end
|
295
|
+
|
296
|
+
=begin
|
297
|
+
* %I - Hour of the day, 12-hour clock (01..12)
|
298
|
+
* %p - Meridian indicator (``AM'' or ``PM'')
|
299
|
+
%U - Week number of the current year,
|
300
|
+
starting with the first Sunday as the first
|
301
|
+
day of the first week (00..53)
|
302
|
+
%W - Week number of the current year,
|
303
|
+
starting with the first Monday as the first
|
304
|
+
day of the first week (00..53)
|
305
|
+
* %y - Year without a century (00..99)
|
306
|
+
%Z - Time zone name
|
307
|
+
|
308
|
+
=end
|
309
|
+
|
310
|
+
end
|
311
|
+
|
metadata
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: marsdate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hal Fulton
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: |2
|
14
|
+
This is a library for handling dates and times on Mars
|
15
|
+
for the Martian Common Era calendar (created by Hal Fulton).
|
16
|
+
The functionality closely follows that of Ruby's Time class.
|
17
|
+
email: rubyhacker@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/marsdate.rb
|
23
|
+
homepage: https://github.com/Hal9000/marsdate
|
24
|
+
licenses:
|
25
|
+
- Ruby License
|
26
|
+
metadata: {}
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubyforge_project:
|
43
|
+
rubygems_version: 2.2.2
|
44
|
+
signing_key:
|
45
|
+
specification_version: 4
|
46
|
+
summary: Date/time library for Mars
|
47
|
+
test_files: []
|