et-orbi 0.9.5 → 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 (8) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/cases.txt +15 -0
  4. data/lib/et-orbi.rb +547 -1
  5. data/lib/et_orbi.rb +3 -0
  6. data/out.txt +2502 -0
  7. data/out2.txt +2487 -0
  8. metadata +18 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0b0845026be5ba2ba99cd43c9e91707a5167cc9
4
- data.tar.gz: cf5a240deda4fc762680ed76ced5577d60d99f90
3
+ metadata.gz: 603e93e83b1b3cff5b845a4de08563334e711ab4
4
+ data.tar.gz: 1c0f23f0b899708d5f38054b934ec72bd79f2411
5
5
  SHA512:
6
- metadata.gz: 1ea3c04b92874cf22162ae67b80028845ecabb64e582444161b1a088e1dfcc521c60f7fbfce41b664a8054b1b9e807d6174b4a386c88104619f213b350331fa5
7
- data.tar.gz: a76d3b266adfabbfc6010b21457d28d80c2a4945c138f791bd931ad999eda0126692ef07771ec3d7929e4d34f64ca3faaaee6446baefb3c8531ba0ce6a9e224f
6
+ metadata.gz: af80e0afd204638d24c8296335a91c7965ccb8cc63f9ec28c2c4dbc8070e15bb08343d6538fd88e219b8648741c1aed9b8c424b9ee649e2a49218f2df2a2a651
7
+ data.tar.gz: 3fd429a30a7a0549ced3e301a877eb39b7e4739243506998b1b068d038da7fa3279f4560e2a847bea1183872b2a0bb0b0c35b7fd1c8bb7d71372017ae4108a80
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+
2
+ # et-orbi CHANGELOG.md
3
+
4
+
5
+ ## et-orbi 1.0.0 not yet released
6
+
7
+ - First release for rufus-scheduler
8
+
9
+
10
+ ## et-orbi 0.9.5 released 2017-03-17
11
+
12
+ - Empty, initial release, 圓さんの家で
13
+
data/cases.txt ADDED
@@ -0,0 +1,15 @@
1
+
2
+ ZoTime.get_tzone(items.last)
3
+ ZoTime.get_tzone(:current)
4
+
5
+ t = ZoTime.new(time.to_f, @timezone)
6
+ zt = ZoTime.new(from.to_i + 1, @timezone)
7
+
8
+ ZoTime.now
9
+
10
+ stderr.puts("#{pre} local_tzone: #{Rufus::Scheduler::ZoTime.local_tzone.inspect}")
11
+
12
+ @first_at = ZoTime.make(first)
13
+ @last_at = last ? ZoTime.make(last) : nil
14
+ return Rufus::Scheduler::ZoTime.make(o) if o.is_a?(Time)
15
+
data/lib/et-orbi.rb CHANGED
@@ -1,6 +1,552 @@
1
1
 
2
+ require 'date' if RUBY_VERSION < '1.9.0'
3
+ require 'time'
4
+
5
+ require 'tzinfo'
6
+
7
+
2
8
  module EtOrbi
3
9
 
4
- VERSION = '0.9.5'
10
+ VERSION = '1.0.0'
11
+
12
+ class EoTime
13
+
14
+ #
15
+ # class methods
16
+
17
+ def self.now(zone=nil)
18
+
19
+ EoTime.new(Time.now.to_f, zone)
20
+ end
21
+
22
+ def self.parse(str, opts={})
23
+
24
+ if defined?(::Chronic) && t = ::Chronic.parse(str, opts)
25
+ return EoTime.new(t, nil)
26
+ end
27
+
28
+ #rold = RUBY_VERSION < '1.9.0'
29
+ #rold = RUBY_VERSION < '2.0.0'
30
+
31
+ #p [ '---', str ]
32
+ begin
33
+ DateTime.parse(str)
34
+ rescue
35
+ fail ArgumentError, "no time information in #{str.inspect}"
36
+ end #if rold
37
+ #
38
+ # is necessary since Time.parse('xxx') in Ruby < 1.9 yields `now`
39
+
40
+ zone = izone = get_tzone(list_iso8601_zones(str).last)
41
+
42
+ list_olson_zones(str).each { |s| break if zone; zone = get_tzone(s) }
43
+
44
+ zone ||= local_tzone
45
+
46
+ str = str.sub(zone.name, '') unless zone.name.match(/\A[-+]/)
47
+ #
48
+ # for 'Sun Nov 18 16:01:00 Asia/Singapore 2012',
49
+ # although where does rufus-scheduler have it from?
50
+
51
+ local = Time.parse(str)
52
+
53
+ secs =
54
+ if izone
55
+ local.to_f
56
+ else
57
+ zone.period_for_local(local).to_utc(local).to_f
58
+ end
59
+
60
+ EoTime.new(secs, zone)
61
+ end
62
+
63
+ def self.time_to_eo_time(t)
64
+
65
+ z =
66
+ get_tzone(t.zone) ||
67
+ (
68
+ local_tzone.period_for_local(t).abbreviation.to_s == t.zone &&
69
+ local_tzone
70
+ ) ||
71
+ t.zone
72
+
73
+ EoTime.new(t.to_f, z)
74
+ end
75
+
76
+ def self.make(o)
77
+
78
+ ot =
79
+ case o
80
+ when Time
81
+ time_to_eo_time(
82
+ o)
83
+ when Date
84
+ time_to_eo_time(
85
+ o.respond_to?(:to_time) ?
86
+ o.to_time :
87
+ Time.parse(o.strftime('%Y-%m-%d %H:%M:%S')))
88
+ when String
89
+ #Rufus::Scheduler.parse_in(o, :no_error => true) || self.parse(o)
90
+ parse(o)
91
+ else
92
+ o
93
+ end
94
+
95
+ ot = EoTime.new(Time.now.to_f + ot, nil) if ot.is_a?(Numeric)
96
+
97
+ fail ArgumentError.new(
98
+ "cannot turn #{o.inspect} to a EoTime instance"
99
+ ) unless ot.is_a?(EoTime)
100
+
101
+ ot
102
+ end
103
+
104
+ def self.to_offset(n)
105
+
106
+ i = n.to_i
107
+ sn = i < 0 ? '-' : '+'; i = i.abs
108
+ hr = i / 3600; mn = i % 3600; sc = i % 60
109
+ (sc > 0 ? "%s%02d:%02d:%02d" : "%s%02d:%02d") % [ sn, hr, mn, sc ]
110
+ end
111
+
112
+ def self.get_tzone(o)
113
+
114
+ #p [ :gtz, o ]
115
+ return nil if o == nil
116
+ return local_tzone if o == :local
117
+ return o if o.is_a?(::TZInfo::Timezone)
118
+ return ::TZInfo::Timezone.get('Zulu') if o == 'Z'
119
+
120
+ o = to_offset(o) if o.is_a?(Numeric)
121
+
122
+ return nil unless o.is_a?(String)
123
+
124
+ (@custom_tz_cache ||= {})[o] ||
125
+ get_offset_tzone(o) ||
126
+ (::TZInfo::Timezone.get(o) rescue nil)
127
+ end
128
+
129
+ def self.get_offset_tzone(str)
130
+
131
+ # custom timezones, no DST, just an offset, like "+08:00" or "-01:30"
132
+
133
+ m = str.match(/\A([+-][0-1][0-9]):?([0-5][0-9])?\z/)
134
+ return nil unless m
135
+
136
+ hr = m[1].to_i
137
+ mn = m[2].to_i
138
+
139
+ hr = nil if hr.abs > 11
140
+ hr = nil if mn > 59
141
+ mn = -mn if hr && hr < 0
142
+
143
+ return (
144
+ @custom_tz_cache[str] =
145
+ begin
146
+ tzi = TZInfo::TransitionDataTimezoneInfo.new(str)
147
+ tzi.offset(str, hr * 3600 + mn * 60, 0, str)
148
+ tzi.create_timezone
149
+ end
150
+ ) if hr
151
+
152
+ nil
153
+ end
154
+
155
+ def self.local_tzone
156
+
157
+ @local_tzone = nil \
158
+ if @local_tzone_loaded_at && (Time.now > @local_tzone_loaded_at + 1800)
159
+ @local_tzone = nil \
160
+ if @local_tzone_tz != ENV['TZ']
161
+
162
+ @local_tzone ||=
163
+ begin
164
+ @local_tzone_tz = ENV['TZ']
165
+ @local_tzone_loaded_at = Time.now
166
+ determine_local_tzone
167
+ end
168
+ end
169
+
170
+ def self.determine_local_tzone
171
+
172
+ etz = ENV['TZ']
173
+
174
+ tz = ::TZInfo::Timezone.get(etz) rescue nil
175
+ return tz if tz
176
+
177
+ tz = Time.zone.tzinfo \
178
+ if Time.respond_to?(:zone) && Time.zone.respond_to?(:tzinfo)
179
+ return tz if tz
180
+
181
+ tzs = determine_local_tzones
182
+
183
+ (etz && tzs.find { |z| z.name == etz }) || tzs.first
184
+ end
185
+
186
+ def self.determine_local_tzones
187
+
188
+ tabbs = (-6..5)
189
+ .collect { |i| (Time.now + i * 30 * 24 * 3600).zone }
190
+ .uniq
191
+ .sort
192
+
193
+ t = Time.now
194
+ tu = t.dup.utc # /!\ dup is necessary, #utc modifies its target
195
+
196
+ twin = Time.utc(t.year, 1, 1) # winter
197
+ tsum = Time.utc(t.year, 7, 1) # summer
198
+
199
+ ::TZInfo::Timezone.all.select do |tz|
200
+
201
+ pabbs =
202
+ [
203
+ tz.period_for_utc(twin).abbreviation.to_s,
204
+ tz.period_for_utc(tsum).abbreviation.to_s
205
+ ].uniq.sort
206
+
207
+ pabbs == tabbs
208
+ end
209
+ end
210
+
211
+ # https://en.wikipedia.org/wiki/ISO_8601
212
+ # Postel's law applies
213
+ #
214
+ def self.list_iso8601_zones(s)
215
+
216
+ s.scan(
217
+ %r{
218
+ (?<=:\d\d)
219
+ \s*
220
+ (?:
221
+ [-+]
222
+ (?:[0-1][0-9]|2[0-4])
223
+ (?:(?::)?(?:[0-5][0-9]|60))?
224
+ (?![-+])
225
+ |
226
+ Z
227
+ )
228
+ }x
229
+ ).collect(&:strip)
230
+ end
231
+
232
+ def self.list_olson_zones(s)
233
+
234
+ s.scan(
235
+ %r{
236
+ (?<=\s|\A)
237
+ (?:[A-Za-z][A-Za-z0-9+_-]+)
238
+ (?:\/(?:[A-Za-z][A-Za-z0-9+_-]+)){0,2}
239
+ }x)
240
+ end
241
+
242
+ def self.platform_info
243
+
244
+ etos = Proc.new { |k, v| "#{k}:#{v.inspect}" }
245
+
246
+ '(' +
247
+ {
248
+ 'etz' => ENV['TZ'],
249
+ 'tnz' => Time.now.zone,
250
+ 'tzid' => defined?(TZInfo::Data),
251
+ 'rv' => RUBY_VERSION,
252
+ 'rp' => RUBY_PLATFORM,
253
+ 'eov' => EtOrbi::VERSION,
254
+ }.collect(&etos).join(',') + ',' +
255
+ gather_tzs.collect(&etos).join(',') +
256
+ ')'
257
+ end
258
+
259
+ #def in_zone(&block)
260
+ #
261
+ # current_timezone = ENV['TZ']
262
+ # ENV['TZ'] = @zone
263
+ #
264
+ # block.call
265
+ #
266
+ #ensure
267
+ #
268
+ # ENV['TZ'] = current_timezone
269
+ #end
270
+ #
271
+ # kept around as a (thread-unsafe) relic
272
+
273
+ #
274
+ # instance methods
275
+
276
+ attr_reader :seconds
277
+ attr_reader :zone
278
+
279
+ def initialize(s, zone)
280
+
281
+ @seconds = s.to_f
282
+ @zone = self.class.get_tzone(zone || :local)
283
+
284
+ #fail ArgumentError.new(
285
+ # "cannot determine timezone from #{zone.inspect}" +
286
+ # " (etz:#{ENV['TZ'].inspect},tnz:#{Time.now.zone.inspect}," +
287
+ # "tzid:#{defined?(TZInfo::Data).inspect}," +
288
+ # "rv:#{RUBY_VERSION.inspect},rp:#{RUBY_PLATFORM.inspect}," +
289
+ # "stz:(#{self.class.gather_tzs.map { |k, v| "#{k}:#{v.inspect}"}.join(',')})) \n" +
290
+ # "Try setting `ENV['TZ'] = 'Continent/City'` in your script " +
291
+ # "(see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)" +
292
+ # (defined?(TZInfo::Data) ? '' : " and adding 'tzinfo-data' to your gems")
293
+ #) unless @zone
294
+ fail ArgumentError.new(
295
+ "cannot determine timezone from #{zone.inspect}" +
296
+ "\n#{self.class.platform_info}" +
297
+ "\nTry setting `ENV['TZ'] = 'Continent/City'` in your script " +
298
+ "(see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)" +
299
+ (defined?(TZInfo::Data) ? '' : "\nand adding gem 'tzinfo-data'")
300
+ ) unless @zone
301
+
302
+ @time = nil # cache for #to_time result
303
+ end
304
+
305
+ def seconds=(f)
306
+
307
+ @time = nil
308
+ @seconds = f
309
+ end
310
+
311
+ def zone=(z)
312
+
313
+ @time = nil
314
+ @zone = self.class.get_tzone(zone || :current)
315
+ end
316
+
317
+ def utc
318
+
319
+ Time.utc(1970, 1, 1) + @seconds
320
+ end
321
+
322
+ alias getutc utc
323
+ alias getgm utc
324
+
325
+ def to_f
326
+
327
+ @seconds
328
+ end
329
+
330
+ def to_i
331
+
332
+ @seconds.to_i
333
+ end
334
+
335
+ def strftime(format)
336
+
337
+ format = format.gsub(/%(\/?Z|:{0,2}z)/) { |f| strfz(f) }
338
+
339
+ to_time.strftime(format)
340
+ end
341
+
342
+ # Returns a Ruby Time instance.
343
+ #
344
+ # Warning: the timezone of that Time instance will be UTC.
345
+ #
346
+ def to_time
347
+
348
+ @time ||= begin; u = utc; @zone.period_for_utc(u).to_local(u); end
349
+ end
350
+
351
+ def is_dst?
352
+
353
+ @zone.period_for_utc(utc).std_offset != 0
354
+ end
355
+ alias isdst is_dst?
356
+
357
+ def to_debug_s
358
+
359
+ uo = self.utc_offset
360
+ uos = uo < 0 ? '-' : '+'
361
+ uo = uo.abs
362
+ uoh, uom = [ uo / 3600, uo % 3600 ]
363
+
364
+ [
365
+ 'ot',
366
+ self.strftime('%Y-%m-%d %H:%M:%S'),
367
+ "%s%02d:%02d" % [ uos, uoh, uom ],
368
+ "dst:#{self.isdst}"
369
+ ].join(' ')
370
+ end
371
+
372
+ def utc_offset
373
+
374
+ #@zone.period_for_utc(utc).utc_offset
375
+ #@zone.period_for_utc(utc).utc_total_offset
376
+ #@zone.period_for_utc(utc).std_offset
377
+ @zone.period_for_utc(utc).utc_offset
378
+ end
379
+
380
+ %w[
381
+ year month day wday hour min sec usec asctime
382
+ ].each do |m|
383
+ define_method(m) { to_time.send(m) }
384
+ end
385
+ def iso8601(fraction_digits=0); to_time.iso8601(fraction_digits); end
386
+
387
+ def ==(o)
388
+
389
+ o.is_a?(EoTime) && o.seconds == @seconds && o.zone == @zone
390
+ end
391
+ #alias eq? == # FIXME see Object#== (ri)
392
+
393
+ def >(o); @seconds > _to_f(o); end
394
+ def >=(o); @seconds >= _to_f(o); end
395
+ def <(o); @seconds < _to_f(o); end
396
+ def <=(o); @seconds <= _to_f(o); end
397
+ def <=>(o); @seconds <=> _to_f(o); end
398
+
399
+ def add(t); @time = nil; @seconds += t.to_f; end
400
+ def subtract(t); @time = nil; @seconds -= t.to_f; end
401
+
402
+ def +(t); inc(t, 1); end
403
+ def -(t); inc(t, -1); end
404
+
405
+ WEEK_S = 7 * 24 * 3600
406
+
407
+ def monthdays
408
+
409
+ date = to_time
410
+
411
+ pos = 1
412
+ d = self.dup
413
+
414
+ loop do
415
+ d.add(-WEEK_S)
416
+ break if d.month != date.month
417
+ pos = pos + 1
418
+ end
419
+
420
+ neg = -1
421
+ d = self.dup
422
+
423
+ loop do
424
+ d.add(WEEK_S)
425
+ break if d.month != date.month
426
+ neg = neg - 1
427
+ end
428
+
429
+ [ "#{date.wday}##{pos}", "#{date.wday}##{neg}" ]
430
+ end
431
+
432
+ def to_s
433
+
434
+ strftime('%Y-%m-%d %H:%M:%S %z')
435
+ end
436
+
437
+ # Debug current time by showing local time / delta / utc time
438
+ # for example: "0120-7(0820)"
439
+ #
440
+ def to_utc_comparison_s
441
+
442
+ per = @zone.period_for_utc(utc)
443
+ off = per.utc_total_offset
444
+
445
+ off = off / 3600
446
+ off = off >= 0 ? "+#{off}" : off.to_s
447
+
448
+ strftime('%H%M') + off + utc.strftime('(%H%M)')
449
+ end
450
+
451
+ def to_time_s
452
+
453
+ strftime("%H:%M:%S.#{'%06d' % usec}")
454
+ end
455
+
456
+ #
457
+ # protected
458
+
459
+ def strfz(code)
460
+
461
+ return @zone.name if code == '%/Z'
462
+
463
+ per = @zone.period_for_utc(utc)
464
+
465
+ return per.abbreviation.to_s if code == '%Z'
466
+
467
+ off = per.utc_total_offset
468
+ #
469
+ sn = off < 0 ? '-' : '+'; off = off.abs
470
+ hr = off / 3600
471
+ mn = (off % 3600) / 60
472
+ sc = 0
473
+
474
+ fmt =
475
+ if code == '%z'
476
+ "%s%02d%02d"
477
+ elsif code == '%:z'
478
+ "%s%02d:%02d"
479
+ else
480
+ "%s%02d:%02d:%02d"
481
+ end
482
+
483
+ fmt % [ sn, hr, mn, sc ]
484
+ end
485
+
486
+ def inc(t, dir)
487
+
488
+ if t.is_a?(Numeric)
489
+ nt = self.dup
490
+ nt.seconds += dir * t.to_f
491
+ nt
492
+ elsif t.respond_to?(:to_f)
493
+ @seconds + dir * t.to_f
494
+ else
495
+ fail ArgumentError.new(
496
+ "cannot call EoTime #- or #+ with arg of class #{t.class}")
497
+ end
498
+ end
499
+
500
+ def _to_f(o)
501
+
502
+ fail ArgumentError(
503
+ "comparison of EoTime with #{o.inspect} failed"
504
+ ) unless o.is_a?(EoTime) || o.is_a?(Time)
505
+
506
+ o.to_f
507
+ end
508
+
509
+ #
510
+ # system tz determination
511
+
512
+ def self.debian_tz
513
+
514
+ path = '/etc/timezone'
515
+
516
+ File.exist?(path) ? File.read(path).strip : nil
517
+ rescue; nil; end
518
+
519
+ def self.centos_tz
520
+
521
+ path = '/etc/sysconfig/clock'
522
+
523
+ File.open(path, 'rb') do |f|
524
+ until f.eof?
525
+ if m = f.readline.match(/ZONE="([^"]+)"/); return m[1]; end
526
+ end
527
+ end if File.exist?(path)
528
+
529
+ nil
530
+ rescue; nil; end
531
+
532
+ def self.osx_tz
533
+
534
+ path = '/etc/localtime'
535
+
536
+ File.symlink?(path) ?
537
+ File.readlink(path).split('/')[4..-1].join('/') :
538
+ nil
539
+ rescue; nil; end
540
+
541
+ # def self.find_tz
542
+ #
543
+ # debian_tz || centos_tz || osx_tz
544
+ # end
545
+
546
+ def self.gather_tzs
547
+
548
+ { :debian => debian_tz, :centos => centos_tz, :osx => osx_tz }
549
+ end
550
+ end
5
551
  end
6
552