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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/marsdate.rb +311 -0
  3. metadata +47 -0
@@ -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
@@ -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: []