when_exe 0.4.4 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/lib/when_exe.rb +89 -3
  3. data/lib/when_exe/basictypes.rb +37 -7
  4. data/lib/when_exe/calendarnote.rb +18 -13
  5. data/lib/when_exe/calendartypes.rb +3 -9
  6. data/lib/when_exe/coordinates.rb +23 -373
  7. data/lib/when_exe/ephemeris.rb +7 -7
  8. data/lib/when_exe/ephemeris/notes.rb +0 -14
  9. data/lib/when_exe/events.rb +1851 -0
  10. data/lib/when_exe/icalendar.rb +121 -4
  11. data/lib/when_exe/linkeddata.rb +29 -18
  12. data/lib/when_exe/locales/akt.rb +63 -0
  13. data/lib/when_exe/locales/locale.rb +60 -11
  14. data/lib/when_exe/mini_application.rb +14 -8
  15. data/lib/when_exe/namespace.rb +42 -0
  16. data/lib/when_exe/parts/enumerator.rb +13 -2
  17. data/lib/when_exe/parts/geometric_complex.rb +51 -1
  18. data/lib/when_exe/parts/method_cash.rb +15 -10
  19. data/lib/when_exe/parts/resource.rb +47 -29
  20. data/lib/when_exe/region/chinese.rb +4 -3
  21. data/lib/when_exe/region/chinese/calendars.rb +4 -4
  22. data/lib/when_exe/region/chinese/epochs.rb +6 -6
  23. data/lib/when_exe/region/chinese/notes.rb +3 -3
  24. data/lib/when_exe/region/chinese/twins.rb +6 -6
  25. data/lib/when_exe/region/islamic.rb +1 -1
  26. data/lib/when_exe/region/japanese.rb +4 -4
  27. data/lib/when_exe/region/japanese/eclipses.rb +2 -2
  28. data/lib/when_exe/region/japanese/location.rb +93 -0
  29. data/lib/when_exe/region/japanese/notes.rb +29 -11
  30. data/lib/when_exe/region/japanese/residues.rb +1 -1
  31. data/lib/when_exe/region/japanese/twins.rb +18 -6
  32. data/lib/when_exe/region/location.rb +40 -0
  33. data/lib/when_exe/region/martian.rb +1 -1
  34. data/lib/when_exe/region/ryukyu.rb +1 -1
  35. data/lib/when_exe/spatial.rb +611 -0
  36. data/lib/when_exe/timestandard.rb +3 -3
  37. data/lib/when_exe/tmobjects.rb +32 -0
  38. data/lib/when_exe/tmposition.rb +211 -1318
  39. data/lib/when_exe/tmptypes.rb +1265 -0
  40. data/lib/when_exe/tmreference.rb +35 -0
  41. data/lib/when_exe/version.rb +3 -3
  42. data/test/events/example-datasets +7 -0
  43. data/test/events/history-dataset.csv +22 -0
  44. data/test/events/japanese-holiday-index.csv +28 -0
  45. data/test/events/japanese-holiday.csv +77 -0
  46. data/test/events/japanese-holiday.ttl +778 -0
  47. data/test/events/make_events_ttl.rb +18 -0
  48. data/test/events/mori_wikichoshi.csv +14 -0
  49. data/test/events/ndl_koyomi.csv +220 -0
  50. data/test/events/ndl_koyomi_index.csv +44 -0
  51. data/test/events/primeminister-dataset.csv +19 -0
  52. data/test/events/shogun-dataset.csv +22 -0
  53. data/test/events/test-history-dataset-edge-sparql.csv +26 -0
  54. data/test/events/test-history-dataset-edge.csv +27 -0
  55. data/test/events/test-history-dataset-sparql.csv +22 -0
  56. data/test/events/test-history-dataset.csv +23 -0
  57. data/test/events/test-history-events-edge.ttl +89 -0
  58. data/test/events/test-history-events.csv +6 -0
  59. data/test/examples/Terms.m17n +1 -1
  60. data/test/test.rb +6 -0
  61. data/test/test/coordinates.rb +2 -2
  62. data/test/test/events.rb +32 -0
  63. data/test/test/region/japanese.rb +20 -0
  64. data/test/test/region/m17n.rb +2 -2
  65. data/test/test/region/mayan.rb +6 -6
  66. data/test/test/tmposition.rb +63 -1
  67. metadata +26 -2
@@ -57,7 +57,7 @@ module When::TimeStandard
57
57
 
58
58
  DeltaT = [ 63.467, # 1999
59
59
  63.827, 64.092, 64.300, 64.473, 64.573, 64.689, 64.846, 65.145, 65.456, 65.779, # 2000-
60
- 66.070, 66.324, 66.603, 66.909, 67.282 # 2010-
60
+ 66.070, 66.324, 66.603, 66.909, 67.282, 67.642 # 2010-
61
61
  ]
62
62
 
63
63
  class << self
@@ -377,7 +377,7 @@ module When::TimeStandard
377
377
  #
378
378
  def _normalize_time_basis
379
379
 
380
- @_time_basis ||= @time_basis || (@location ? @location.long / When::Coordinates::Spatial::DEGREE * 240 : When::UTC)
380
+ @_time_basis ||= @time_basis || (@location ? @location.long / @location.degree * 240 : When::UTC)
381
381
  @_time_basis = When::Locale._split(@_time_basis) if @_time_basis.kind_of?(String)
382
382
  @_time_basis = [@_time_basis] unless @_time_basis.kind_of?(Array)
383
383
  @_time_basis = @_time_basis.map {|clock| When.Clock(clock)}
@@ -404,7 +404,7 @@ module When::TimeStandard
404
404
  # @return [Numeric] difference / day
405
405
  #
406
406
  def localdate_difference
407
- @localdate_difference ||= @location.long / (360.0 * When::Coordinates::Spatial::DEGREE)
407
+ @localdate_difference ||= @location.long / (360.0 * @location.degree)
408
408
  end
409
409
 
410
410
  # local time と universal time の差 / 128秒
@@ -530,6 +530,13 @@ module When::TM
530
530
  #
531
531
  class Duration
532
532
 
533
+ # 繰り返し有無
534
+ #
535
+ # @return [Boolean]
536
+ #
537
+ attr_accessor :repeat
538
+ protected :repeat=
539
+
533
540
  #
534
541
  # When::TM::IntervalLength への変換
535
542
  #
@@ -556,6 +563,31 @@ module When::TM
556
563
  When::TM::PeriodDuration.new(duration / SECOND, When::SECOND)
557
564
  end
558
565
 
566
+ # オブジェクト変換オプションの遅延適用(ダミー)
567
+ #
568
+ # @param [Hash] options 以下の通り
569
+ # @option options [Hash<Integrt=>When::Coordinates::Residue>] :residue
570
+ # @option options [When::TM::Clock] :clock
571
+ # @option options [Array <When::TM::Calendar>] :frame
572
+ #
573
+ # @return [When::TM::Duration]
574
+ #
575
+ def apply_delayed_options(options)
576
+ self
577
+ end
578
+
579
+ # 繰り返し設定
580
+ #
581
+ # @param [Boolean] repeat 設定
582
+ #
583
+ # @return [When::TM::Duration]
584
+ #
585
+ def set_repeat(repeat)
586
+ repeated = dup
587
+ repeated.repeat = repeat
588
+ repeated
589
+ end
590
+
559
591
  #
560
592
  # Duration 用の Enumerator
561
593
  #
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  =begin
3
- Copyright (C) 2011-2015 Takashi SUGA
3
+ Copyright (C) 2011-2016 Takashi SUGA
4
4
 
5
5
  You may use and/or modify this file according to the license described in the LICENSE.txt file included in this archive.
6
6
  =end
@@ -313,21 +313,32 @@ module When::TM
313
313
  iso8601form = When::Parts::Resource::ContentLine.extract_rfc5545_Property(specification, options).
314
314
  gsub(When::Parts::Resource::IRIDecode) {|c| When::Parts::Resource::IRIDecodeTable[c]}
315
315
 
316
- # suffix - Frame specification
317
- if iso8601form =~ /\A(.*[^\d]|.+=[^:]+)\((([-+*&%@!>=<?\dW.T:]|\{.+?\})+)\)\z/
316
+ # delayed_options
317
+ delayed_options = {}
318
+
319
+ # Frame specifications - 暦法指定の取り出し
320
+ if iso8601form =~ /\A(.*[^\d]|.+=[^:]+)\((([-+*&%@!>=<?\d.A-Z:]|\{.+?\})+)\)\z/
318
321
  frame, iso8601form = $~[1..2]
319
322
  frame.sub!(/_+\z/, '')
320
323
  else
321
324
  iso8601form, frame, *rest = iso8601form.split(/(?:\^|%5E){1,2}/i)
322
- return rest.inject(_instance(iso8601form + '^' + frame, options)) {|p,c| When.Resource(c, '_c:').jul_trans(p)} unless rest.empty?
325
+ delayed_options[:frame] = rest.map{|calendar| When.Resource(calendar, '_c:')} unless rest.empty?
323
326
  end
324
327
 
325
328
  # add frame to options
326
329
  options = options.merge({:frame=>When.Resource(frame, '_c:')}) if frame
327
330
 
331
+ return _instance_element(iso8601form, options, delayed_options) unless iso8601form =~ /\A(.+?)(\.{2,3})(.+)\z/
332
+ first, separater, last = $1, $2, $3
333
+ When::Events::Range.new(_instance_element(first, options.dup, delayed_options.dup),
334
+ _instance_element(last, options.dup, delayed_options.dup), separater == '...')
335
+ end
336
+
337
+ def _instance_element(iso8601form, options, delayed_options)
338
+
328
339
  # indeterminateValue
329
340
  if (iso8601form.sub!(/\/After\z|\ABefore\/|\ANow\z|\AUnknown\z|\A[-+]Infinity\z/i, ''))
330
- options[:indeterminated_position] = When::TimeValue::S[$&.sub(/\//,'')]
341
+ options[:indeterminated_position] = When::TimeValue::S[$&.sub('/','')]
331
342
  case options[:indeterminated_position]
332
343
  when When::TimeValue::Now,
333
344
  When::TimeValue::Unknown,
@@ -337,10 +348,11 @@ module When::TM
337
348
  end
338
349
  end
339
350
 
340
- # each specification
341
- splitted = iso8601form.split(/\//)
342
- if (splitted[0] =~ /\AR(\d+)?\z/)
351
+ # each specification - '/' で区切られた個々の要素の取り出し
352
+ splitted = iso8601form.gsub(/\{.+?\}/) {|m| m.gsub('/', When::Locale::NUL)}.split('/').map {|m| m.gsub(When::Locale::NUL, '/')}
353
+ if (splitted[0] =~ /\AR(\d+)?(P.+)?\z/)
343
354
  repeat = $1 ? $1.to_i : true
355
+ delayed_options[:duration] = When.Duration($2) if $2
344
356
  splitted.shift
345
357
  end
346
358
  case splitted.length
@@ -353,77 +365,59 @@ module When::TM
353
365
  raise ArgumentError, "Irregal ISO8601 Format: #{iso8601form}"
354
366
  end
355
367
  options = self._options(options)
356
- element = splitted.map { |v| _date_time_or_duration(v, options.dup) }
368
+ element = splitted.map { |v|
369
+ d, r, z2 = _date_time_or_duration(v, options.dup)
370
+ delayed_options[:residue] = r if r
371
+ delayed_options[:clock ] = z2 if z2
372
+ d
373
+ }
357
374
 
358
- # total result
375
+ # 意味のある繰り返しのない場合
376
+ has_residue_options = delayed_options[:residue] && (delayed_options[:residue][0].kind_of?(String) ||
377
+ delayed_options[:residue][2].kind_of?(String))
359
378
  case repeat
360
- when nil
361
- case element[1]
362
- when nil
363
- return element[0]
364
- when Duration
365
- case element[0]
366
- when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
367
- when self ; return When::Parts::GeometricComplex.new(*element)
368
- else ; return When::Parts::GeometricComplex.new(element[0].first, element[1])
369
- end
370
- when self
371
- case element[0]
372
- when Duration ; return When::Parts::GeometricComplex.new([[element[1]-element[0],false], [element[1],true ]])
373
- when self ; return When::Parts::GeometricComplex.new(element[0]..element[1])
374
- else ; return When::Parts::GeometricComplex.new(element[0].first..element[1])
375
- end
376
- else
377
- case element[0]
378
- when Duration ; return When::Parts::GeometricComplex.new([[element[1].first-element[0],false],
379
- [element[1].last-element[0]-1,true ]])
380
- when self ; return When::Parts::GeometricComplex.new(element[0]...element[1].last)
381
- else ; return When::Parts::GeometricComplex.new(element[0].first...element[1].last)
382
- end
383
- end
384
- when 0 ; return []
385
- when Integer ; return [element[0]] * repeat unless element[1]
379
+ when nil ; return _instance_without_repeat(element).apply_delayed_options(delayed_options) unless has_residue_options
380
+ when 0 ; return []
381
+ when Integer
382
+ return [element[0]] * repeat if element.length == 1 && element[0].kind_of?(When::TM::Duration) # JIS X0301 5.6.3
383
+ raise ArgumentError, "Duration or TemporalPosition missing" unless element[1] || has_residue_options
386
384
  end
387
385
 
388
- case element[1]
389
- when Duration
390
- case element[0]
391
- when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
392
- else ; duration = element[1]
393
- end
394
- when self
395
- case element[0]
396
- when Duration ; duration = -element[0]
397
- when self ; duration = element[1] - element[0]
398
- else ; duration = element[1] - element[0].first
399
- end
400
- else
401
- case element[0]
402
- when Duration ; duration = -element[0]
403
- when self ; duration = element[1].first - element[0]
404
- else ; duration = element[1].first - element[0].first
386
+ # 繰り返しの起点と間隔
387
+ base = element[0].kind_of?(Duration) ? element[1] : element[0]
388
+ duration = _duration_for_repeat(element)
389
+
390
+ # 繰り返しのある場合
391
+ if repeat.kind_of?(Integer) && !has_residue_options
392
+
393
+ # iCalendar の機能を使用しない
394
+ result = []
395
+ seed = base
396
+ guard = (base - When::V::Event.default_until)...(base + When::V::Event.default_until)
397
+ while result.length < repeat && seed >= guard.first && seed < guard.last
398
+ applied = seed.apply_delayed_options(delayed_options)
399
+ applied = When::Parts::GeometricComplex.new(applied, delayed_options[:duration]) if delayed_options[:duration]
400
+ result << applied if applied
401
+ seed += duration
405
402
  end
406
- end
407
- base = element[0].kind_of?(Duration) ? element[1] : element[0]
408
-
409
- if repeat.kind_of?(Integer)
410
- result = case base
411
- when self ; (1..repeat-1).inject([base]) {|a,i| a << (a[-1] + duration) }
412
- else ; (1..repeat-1).inject([base]) {|a,i| a << When::Parts::GeometricComplex.new(
413
- a[-1].first+duration...a[-1].last+duration)}
414
- end
415
403
  result.reverse! if duration.sign < 0
416
404
  return result
417
405
 
418
406
  else
419
- duration = -duration if duration.sign < 0
420
- return case base
421
- when self ; When::V::Event.new({'rrule'=>{'FREQ'=>duration}, 'dtstart'=>base})
422
- else ; When::V::Event.new({'rrule'=>{'FREQ'=>duration}, 'dtstart'=>base.first,
423
- 'dtend' =>base.last})
424
- end
407
+
408
+ return duration.set_repeat(true) unless base
409
+
410
+ # iCalendar の機能を使用する
411
+ should_limit = base.precision == When::MONTH && !(delayed_options[:residue] && delayed_options[:residue][0])
412
+ iterator = When::V::Event.iterator_for_ISO8601(base, duration, delayed_options)
413
+ case repeat
414
+ when nil ; (result=iterator.succ).precision > base.precision && should_limit && base != result ? nil : result
415
+ when Integer ; (0...repeat).to_a.map {iterator.succ}
416
+ else ; iterator
417
+ end
425
418
  end
426
419
  end
420
+ private :_instance_element
427
421
 
428
422
  # When::TM::TemporalPosition の生成
429
423
  #
@@ -463,6 +457,10 @@ module When::TM
463
457
  else ; nil
464
458
  end
465
459
  }
460
+ parse = options.delete(:parse)
461
+ if parse && parse[:residue] && parse[:residue][2]
462
+ res << parse[:residue][2]
463
+ end
466
464
  if args.length > 0
467
465
  options[:clock] ||= Clock.local_time
468
466
  options[:clock] = When.Clock(options[:clock])
@@ -503,7 +501,7 @@ module When::TM
503
501
  main = {}
504
502
  clock = Clock.get_clock_option(query)
505
503
  main[:clock] = clock if clock
506
- [:indeterminated_position, :frame, :events, :precision,
504
+ [:indeterminated_position, :frame, :events, :precision, :parse,
507
505
  :era_name, :era, :abbr, :extra_year_digits, :ordinal_date_digits, :wkst, :time_standard, :location].each do |key|
508
506
  main[key] = query.delete(key) if query.key?(key)
509
507
  end
@@ -573,20 +571,94 @@ module When::TM
573
571
  when :week
574
572
  position = ((position + PeriodDuration.new(4, DAY)) & (Residue.day_of_week(options[:wkst]) << 1)) +
575
573
  PeriodDuration.new((w[0]-1)*7 + (w[1]||1)-1, DAY)
576
- position = When::Parts::GeometricComplex.new(position...(position+P1W)) unless w[1]
574
+ position = When::Parts::GeometricComplex.new(position, P1W) unless w[1]
577
575
  end
578
- if r
579
- r.keys.sort.each do |count|
580
- residue = When.Residue(r[count])
581
- if count == 0
582
- residue = residue.to('year')
583
- else
584
- position = position.succ if residue.carry < 0
585
- end
586
- position &= residue
576
+ [position, r, z2]
577
+ end
578
+
579
+ # オブジェクト変換オプションの遅延適用対象オブジェクト
580
+ #
581
+ # @param [Array<When::TM::TemporalPosition or When::TM::Duration>] element
582
+ #
583
+ # @return [When::TM::TemporalPosition] ISO8601 time point
584
+ # @return [When::Parts::GeometricComplex] ISO8601 遅延適用対象オブジェクト
585
+ #
586
+ def _instance_without_repeat(element)
587
+ case element[1]
588
+ when nil
589
+ return element[0]
590
+ when Duration
591
+ case element[0]
592
+ when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
593
+ when self ; return When::Parts::GeometricComplex.new(*element)
594
+ else ; return When::Parts::GeometricComplex.new(element[0].first, element[1])
595
+ end
596
+ when self
597
+ case element[0]
598
+ when Duration ; return When::Parts::GeometricComplex.new([[element[1]-element[0],false], [element[1],true ]])
599
+ when self ; return When::Parts::GeometricComplex.new(element[0]..element[1])
600
+ else ; return When::Parts::GeometricComplex.new(element[0].first..element[1])
601
+ end
602
+ else
603
+ case element[0]
604
+ when Duration ; return When::Parts::GeometricComplex.new([[element[1].first-element[0],false],
605
+ [element[1].last-element[0]-1,true ]])
606
+ when self ; return When::Parts::GeometricComplex.new(element[0]...element[1].last)
607
+ else ; return When::Parts::GeometricComplex.new(element[0].first...element[1].last)
608
+ end
609
+ end
610
+ end
611
+
612
+ # 繰り返し用の Duration 取得
613
+ #
614
+ # @param [Array<When::TM::TemporalPosition or When::TM::Duration>] element
615
+ #
616
+ # @return [When::TM::Duration] repeating interval
617
+ #
618
+ def _duration_for_repeat(element)
619
+ case element[1]
620
+ when Duration
621
+ case element[0]
622
+ when Duration ; raise TypeError, "Duplicate Duration: #{element[0]} and #{element[1]}"
623
+ else ; return element[1]
624
+ end
625
+ when self
626
+ case element[0]
627
+ when Duration ; return -element[0]
628
+ when self ; return element[1] - element[0]
629
+ else ; return element[1] - element[0].first
630
+ end
631
+ when nil
632
+ case element[0]
633
+ when Duration ; return element[0]
634
+ else ; nil
635
+ end
636
+ else
637
+ case element[0]
638
+ when Duration ; return -element[0]
639
+ when self ; return element[1].first - element[0]
640
+ else ; return element[1].first - element[0].first
587
641
  end
588
642
  end
589
- z2 ? z2 ^ position : position
643
+ end
644
+
645
+ # オブジェクト変換オプションの遅延適用
646
+ #
647
+ # @param [Object] object 遅延適用するオブジェクト
648
+ #
649
+ # @param [Hash] options 以下の通り
650
+ # @option options [Hash<Integrt=>When::Coordinates::Residue>] :residue
651
+ # @option options [When::TM::Clock] :clock
652
+ # @option options [Array <When::TM::Calendar>] :frame
653
+ #
654
+ # @return [Object] 遅延適用されたオブジェクト
655
+ #
656
+ def _apply_delayed_options(object, options)
657
+ case object
658
+ when Array ; object.map {|obj| _apply_delayed_options(obj, options)}
659
+ when self, When::Parts::GeometricComplex ; object.apply_delayed_options(options)
660
+ else ; object
661
+ end
590
662
  end
591
663
  end
592
664
 
@@ -759,13 +831,15 @@ module When::TM
759
831
  #
760
832
  def +(other)
761
833
  case other
762
- when Integer ; self + PeriodDuration.new(other, When::DAY)
763
- when Numeric ; self + IntervalLength.new(other, 'day')
764
- when PeriodDuration ; _plus(other)
765
- when Duration ; @frame.kind_of?(Calendar) ? @frame.jul_trans(JulianDate.dynamical_time(dynamical_time + other.duration), self._attr) :
766
- JulianDate.dynamical_time(dynamical_time + other.duration, self._attr)
767
- else ; raise TypeError, "The right operand should be Numeric or Duration"
834
+ when Integer ; return self + PeriodDuration.new(other, When::DAY)
835
+ when Numeric ; return self + IntervalLength.new(other, 'day')
836
+ when Duration ; begin other = other.set_repeat(false); return other.enum_for(self+other, :forward) end if other.repeat
837
+ when Array ; return other.map {|o| self + o}
838
+ else ; raise TypeError, "The right operand should be Numeric or Duration"
768
839
  end
840
+ return _plus(other) if other.kind_of?(PeriodDuration)
841
+ @frame.kind_of?(Calendar) ? @frame.jul_trans(JulianDate.dynamical_time(dynamical_time + other.duration), self._attr) :
842
+ JulianDate.dynamical_time(dynamical_time + other.duration, self._attr)
769
843
  rescue RangeError
770
844
  (@frame ^ self) + other
771
845
  end
@@ -779,16 +853,18 @@ module When::TM
779
853
  #
780
854
  def -(other)
781
855
  case other
782
- when TimeValue ; self.time_standard.rate_of_clock == other.time_standard.rate_of_clock && [@precision, other.precision].min <= When::DAY ?
783
- PeriodDuration.new(self.to_i - other.to_i, When::DAY) :
784
- IntervalLength.new((self.dynamical_time - other.dynamical_time) / Duration::SECOND, 'second')
785
- when Integer ; self - PeriodDuration.new(other, When::DAY)
786
- when Numeric ; self - IntervalLength.new(other, 'day')
787
- when PeriodDuration ; _plus(-other)
788
- when Duration ; @frame.kind_of?(Calendar) ? @frame.jul_trans(JulianDate.dynamical_time(dynamical_time - other.duration), self._attr) :
789
- JulianDate.dynamical_time(dynamical_time - other.duration, self._attr)
790
- else ; raise TypeError, "The right operand should be Numeric, Duration or TemporalPosition"
856
+ when TimeValue; return self.time_standard.rate_of_clock == other.time_standard.rate_of_clock && [@precision, other.precision].min <= When::DAY ?
857
+ PeriodDuration.new(self.to_i - other.to_i, When::DAY) :
858
+ IntervalLength.new((self.dynamical_time - other.dynamical_time) / Duration::SECOND, 'second')
859
+ when Integer ; return self - PeriodDuration.new(other, When::DAY)
860
+ when Numeric ; return self - IntervalLength.new(other, 'day')
861
+ when Duration ; begin other = other.set_repeat(false); return other.enum_for(self-other, :reverse) end if other.repeat
862
+ when Array ; return other.map {|o| self - o}
863
+ else ; raise TypeError, "The right operand should be Numeric, Duration or TemporalPosition"
791
864
  end
865
+ return _plus(-other) if other.kind_of?(PeriodDuration)
866
+ @frame.kind_of?(Calendar) ? @frame.jul_trans(JulianDate.dynamical_time(dynamical_time - other.duration), self._attr) :
867
+ JulianDate.dynamical_time(dynamical_time - other.duration, self._attr)
792
868
  rescue RangeError
793
869
  (@frame ^ self) - other
794
870
  end
@@ -804,31 +880,6 @@ module When::TM
804
880
  @period = When.Duration(period_name)
805
881
  end
806
882
 
807
- # 前の日時
808
- #
809
- # @return [When::TM::TemporalPosition]
810
- #
811
- # 分解能に対応する Duration だけ,日時を戻す
812
- #
813
- def prev
814
- @precision==When::DAY ? _force_euqal_day(-1) : self-period
815
- rescue RangeError
816
- (When::Gregorian ^ self) - period
817
- end
818
-
819
- # 次の日時
820
- #
821
- # @return [When::TM::TemporalPosition]
822
- #
823
- # 分解能に対応する Duration だけ,日時を進める
824
- #
825
- def succ
826
- @precision==When::DAY ? _force_euqal_day(+1) : self+period
827
- rescue RangeError
828
- (When::Gregorian ^ self) + period
829
- end
830
- alias :next :succ
831
-
832
883
  #
833
884
  # 前後の日時を取得可能か?
834
885
  #
@@ -857,7 +908,7 @@ module When::TM
857
908
  # @return [Boolean]
858
909
  #
859
910
  def has_time?
860
- (@precision > 0)
911
+ (@precision > DAY)
861
912
  end
862
913
 
863
914
  # 指定の日時を含むか?
@@ -927,6 +978,10 @@ module When::TM
927
978
  return result unless result == 0
928
979
  end
929
980
  @cal_date[prec - 1] <=> other.cal_date[prec - 1]
981
+ elsif prec < DAY && precision < other.precision
982
+ return +1 if other.to_i < self.to_i
983
+ return -1 if other.to_i >= succ.to_i
984
+ return 0
930
985
  else
931
986
  source = (prec >= self.precision ) ? self : self.floor(prec)
932
987
  target = (prec >= other.precision) ? other : other.floor(prec)
@@ -1000,6 +1055,41 @@ module When::TM
1000
1055
  scan(other, leaf, &block)
1001
1056
  end
1002
1057
 
1058
+ # オブジェクト変換オプションの遅延適用
1059
+ #
1060
+ # @param [Hash] options 以下の通り
1061
+ # @option options [Hash<Integrt=>When::Coordinates::Residue>] :residue
1062
+ # @option options [When::TM::Clock] :clock
1063
+ # @option options [Array <When::TM::Calendar>] :frame
1064
+ #
1065
+ # @return [When::TM::TemporalPosition]
1066
+ #
1067
+ def apply_delayed_options(options)
1068
+ position = self
1069
+ if options[:residue]
1070
+ options[:residue].keys.sort.each do |count|
1071
+ options[:residue][count] = When.Residue(options[:residue][count]) unless options[:residue][count].kind_of?(When::Coordinates::Residue)
1072
+ residue = options[:residue][count]
1073
+ if count == 0
1074
+ residue = residue.to('year')
1075
+ position &= residue
1076
+ else
1077
+ upper = position
1078
+ position = position.succ if residue.carry < 0
1079
+ position &= residue
1080
+ return nil if self.precision == When::MONTH && !(upper == position)
1081
+ end
1082
+ end
1083
+ end
1084
+ if options[:clock]
1085
+ position = options[:clock] ^ position
1086
+ end
1087
+ if options[:frame]
1088
+ position = options[:frame].inject(position) {|p,c| c.jul_trans(p)}
1089
+ end
1090
+ position
1091
+ end
1092
+
1003
1093
  # 属性を変更したコピーを作る
1004
1094
  #
1005
1095
  # @param [Hash] options { 属性=>属性値 }
@@ -1142,1201 +1232,4 @@ module When::TM
1142
1232
  end
1143
1233
  end
1144
1234
  end
1145
-
1146
- #
1147
- # 時間座標 - 単一の時間間隔によって定義する連続な間隔尺度を基礎とする
1148
- #
1149
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeCoordinateType gml schema}
1150
- #
1151
- class Coordinate < TemporalPosition
1152
-
1153
- class << self
1154
- # 内部時間によるオブジェクトの生成
1155
- alias :universal_time :new
1156
-
1157
- # 外部時間によるオブジェクトの生成
1158
- #
1159
- # @param [Numeric] dynamical_time 外部時間による時間座標値
1160
- #
1161
- # @param [Hash] options 下記の通り
1162
- # @option options [When::TimeStandard] :time_standard
1163
- #
1164
- # @return [When::TM::Coordinate]
1165
- #
1166
- def dynamical_time(dynamical_time, options={})
1167
- universal_time(When.Resource(options[:time_standard] || 'UniversalTime', '_t:').from_dynamical_time(dynamical_time), options)
1168
- end
1169
-
1170
- # 他種の時間位置によるオブジェクトの生成
1171
- #
1172
- # @param [Numeric, When::TM::ClockTime, ::Time, ::Date, ::DateTime] time 他種の時間位置によるオブジェクト
1173
- #
1174
- # @param [Hash] options 下記の通り
1175
- # @option options [When::TM::Clock] :clock
1176
- # @option options [When::Parts::Timezone] :tz
1177
- #
1178
- # @return [When::TM::Coordinate]
1179
- #
1180
- def new(time, options={})
1181
- options = options.dup
1182
- options[:frame] = Clock.get_clock_option(options)
1183
- case time
1184
- when Numeric
1185
- options[:frame] ||= When::UTC unless time.kind_of?(Integer)
1186
- universal_time = (2*time - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
1187
- when ClockTime
1188
- options[:frame] ||= time.clock
1189
- universal_time = time.clk_time[0] + time.universal_time
1190
- when ::Time
1191
- options[:frame] ||= When.Clock(time.gmtoff)
1192
- universal_time = options[:frame].time_standard.from_time_object(time)
1193
- when TimeValue
1194
- options[:frame] ||= time.clock
1195
- universal_time = time.universal_time
1196
- else
1197
- if ::Object.const_defined?(:Date) && ::Date.method_defined?(:+) && time.respond_to?(:ajd)
1198
- case time
1199
- when ::DateTime
1200
- options[:frame] ||= When.Clock((time.offset * 86400).to_i)
1201
- universal_time = (2*time.ajd - (2*JulianDate::JD19700101-1)) * Duration::DAY.to_i / 2.0
1202
- when ::Date
1203
- universal_time = JulianDate._d_to_t(time.jd)
1204
- if options[:frame] && options[:frame].rate_of_clock != 1.0
1205
- universal_time = options[:frame].time_standard.from_dynamical_time(
1206
- When::TimeStandard.to_dynamical_time(universal_time))
1207
- end
1208
- end
1209
- end
1210
- end
1211
- raise TypeError, "Can't create #{self} from #{time.class}" unless universal_time
1212
- universal_time(universal_time, options)
1213
- end
1214
- end
1215
-
1216
- # この時間位置と関連付けられた時間参照系 (relation - Reference)
1217
- #
1218
- # The time reference system associated with the temporal position being described
1219
- #
1220
- # @return [When::TM::ReferenceSystem]
1221
- #
1222
- alias :clock :frame
1223
-
1224
- # 内部時間による時間座標値
1225
- #
1226
- # @return [Numeric]
1227
- #
1228
- attr_accessor :universal_time
1229
- alias :coordinateValue :universal_time
1230
- protected :universal_time=
1231
-
1232
- # 内部時間(ローカル)
1233
- #
1234
- # @return [Numeric]
1235
- #
1236
- # 1970-01-01T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
1237
- #
1238
- def local_time
1239
- @universal_time
1240
- end
1241
-
1242
- # CoordinateSystem による時間座標値
1243
- #
1244
- # @return [Numeric]
1245
- #
1246
- def coordinateValue
1247
- (universal_time - frame.origin.universal_time) / frame.interval.to_f
1248
- end
1249
-
1250
- # 加算
1251
- #
1252
- # @param [Numeric, When::TM::IntervalLength] other
1253
- #
1254
- # @return [When::TM::TemporalPosition]
1255
- #
1256
- def +(other)
1257
- other = other.to_interval_length if other.kind_of?(PeriodDuration)
1258
- super(other)
1259
- end
1260
-
1261
- # 減算
1262
- #
1263
- # @param [When::TM::TemporalPosition, Numeric, When::TM::IntervalLength] other
1264
- #
1265
- # @return [When::TM::TemporalPosition] if other is a Numeric or When::TM::IntervalLength
1266
- # @return [When::TM::IntervalLength] if other is a When::TM::TemporalPosition
1267
- #
1268
- def -(other)
1269
- other = other.to_interval_length if other.kind_of?(PeriodDuration)
1270
- super(other)
1271
- end
1272
-
1273
- # オブジェクトの生成
1274
- #
1275
- # @param [Numeric] universal_time 内部時間による時間座標値
1276
- #
1277
- # @param [Hash] options 下記の通り
1278
- # @option options [When::TM::CoordinateSystem] :frame
1279
- #
1280
- def initialize(universal_time, options={})
1281
- super(options)
1282
- @universal_time = universal_time
1283
- end
1284
- end
1285
-
1286
- #
1287
- # ユリウス日
1288
- #
1289
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#JulianDateType CALENdeRsign}
1290
- #
1291
- class JulianDate < Coordinate
1292
-
1293
- # Julian Day Number
1294
- # 19700101T120000Z
1295
- JD19700101 = 2440588
1296
-
1297
- # Modified Julian Date
1298
- #
1299
- # see {https://en.wikipedia.org/wiki/Julian_day#Variants MJD}
1300
- JDN_of_MJD = 2400000.5
1301
-
1302
- # Countdown to Equinoctial Planetconjunction
1303
- #
1304
- # see {http://www.calendersign.com/en/cs_cep-pec.php CEP}
1305
- JDN_of_CEP = 2698162
1306
-
1307
- class << self
1308
-
1309
- JD19700100_5 = JD19700101 - 0.5
1310
-
1311
- #
1312
- # 日時の内部表現をユリウス日に変換
1313
- #
1314
- # @param [Numeric] t
1315
- #
1316
- # @return [Numeric]
1317
- #
1318
- def _t_to_d(t)
1319
- t / Duration::DAY + JD19700100_5
1320
- end
1321
-
1322
- #
1323
- # ユリウス日をに日時の内部表現変換
1324
- #
1325
- # @param [Numeric] d
1326
- #
1327
- # @return [Numeric]
1328
- #
1329
- def _d_to_t(d)
1330
- (d - JD19700100_5) * Duration::DAY
1331
- end
1332
-
1333
- # Generation of Temporal Objetct
1334
- #
1335
- # @param [String] specification ユリウス通日を表す文字列
1336
- # @param [Hash] options 暦法や時法などの指定 (see {When::TM::TemporalPosition._instance})
1337
- #
1338
- # @return [When::TM::TemporalPosition, When::TM::Duration, When::Parts::GeometricComplex or Array<them>]
1339
- #
1340
- def parse(specification, options={})
1341
- num, *calendars = specification.split(/\^{1,2}/)
1342
- jdn = num.sub!(/[.@]/, '.') ? num.to_f : num.to_i
1343
- case num
1344
- when/MJD/i ; jdn += JDN_of_MJD
1345
- when/CEP/i ; jdn += JDN_of_CEP
1346
- end
1347
- frame = calendars.shift || options[:frame]
1348
- return self.new(jdn, options) unless frame
1349
- calendars.unshift(frame).inject(jdn) {|date, calendar| When.Calendar(calendar).jul_trans(date, options)}
1350
- end
1351
- end
1352
-
1353
- # 加算
1354
- #
1355
- # @param [Numeric, When::TM::IntervalLength] other
1356
- #
1357
- # @return [When::TM::TemporalPosition]
1358
- #
1359
- def +(other)
1360
- new_date = super
1361
- new_date.frame = new_date.frame._daylight(new_date.universal_time) if new_date.frame && new_date.frame._need_validate
1362
- return new_date
1363
- end
1364
-
1365
- # ユリウス日が指定の剰余となる日
1366
- #
1367
- # @param [When::Coordinates::Residue] other
1368
- #
1369
- # @return [When::TM::TemporalPosition]
1370
- #
1371
- def &(other)
1372
- raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1373
- raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
1374
- jdn = to_i
1375
- new_date = self.dup
1376
- new_date.universal_time += ((other & jdn) - jdn) * Duration::DAY
1377
- return new_date
1378
- end
1379
-
1380
- # ユリウス日の剰余
1381
- #
1382
- # @param [When::Coordinates::Residue] other
1383
- #
1384
- # @return [Numeric]
1385
- #
1386
- def %(other)
1387
- raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1388
- raise ArgumentError,"The right operand should have a unit 'day'" unless other.event == 'day'
1389
- other % to_i
1390
- end
1391
-
1392
- private
1393
-
1394
- # オブジェクトの生成
1395
- #
1396
- # @param [Numeric] universal_time 内部時間による時間座標値
1397
- #
1398
- # @param [Hash] options 以下の通り
1399
- # @option options [When::TM::Clock] :frame
1400
- # @option options [Integer] :precision
1401
- #
1402
- def initialize(universal_time, options={})
1403
- @frame = options.delete(:frame)
1404
- @frame = When.Clock(@frame) if @frame.kind_of?(String)
1405
- @frame = @frame._daylight(universal_time) if @frame && @frame._need_validate
1406
- precision = options.delete(:precision)
1407
- precision ||= DAY unless @frame.kind_of?(Clock)
1408
- @precision = Index.precision(precision)
1409
- super
1410
- end
1411
- end
1412
-
1413
- #
1414
- # 順序時間参照系で参照する位置
1415
- #
1416
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#TimeOrdinalPositionType gml schema}
1417
- #
1418
- class OrdinalPosition < TemporalPosition
1419
-
1420
- # この順序位置と関連付けられた順序年代 (relation - Reference)
1421
- #
1422
- # The ordinal era associated with the ordinal position being described
1423
- #
1424
- # @return [When::TM::OrdinalEra]
1425
- #
1426
- attr_reader :ordinal_position
1427
- alias :ordinalPosition :ordinal_position
1428
-
1429
- # オブジェクトの生成
1430
- #
1431
- # @param [When::TM::OrdinalEra] ordinal_position この順序位置と関連付けられた順序年代
1432
- # @param [Hash] options see {When::TM::TemporalPosition._instance}
1433
- #
1434
- def initialize(ordinal_position, options={})
1435
- super(options)
1436
- @ordinal_position = ordinal_position
1437
- end
1438
- end
1439
-
1440
- #
1441
- # 時刻
1442
- #
1443
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#ClockTimeType gml schema}
1444
- #
1445
- class ClockTime < TemporalPosition
1446
-
1447
- # 時刻要素
1448
- #
1449
- # @return [Array<Numeric>]
1450
- #
1451
- # @note ISO19108 では sequence<Integer> だが、閏時・閏秒などが表現可能なよう Numeric としている。
1452
- #
1453
- attr_reader :clk_time
1454
- alias :clkTime :clk_time
1455
-
1456
- # この時間位置と関連付けられた時間参照系 (relation - Reference)
1457
- #
1458
- # The time reference system associated with the temporal position being described
1459
- #
1460
- # @return [When::TM::ReferenceSystem]
1461
- #
1462
- alias :clock :frame
1463
-
1464
- # 内部時間
1465
- #
1466
- # @param [Integer] sdn 参照事象の通し番号
1467
- #
1468
- # @return [Numeric]
1469
- #
1470
- # T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
1471
- #
1472
- # 時法によっては、異なる意味を持つことがある
1473
- #
1474
- def universal_time(sdn=nil)
1475
- raise NameError, "Temporal Reference System is not defined" unless @frame
1476
- @universal_time ||= @frame.to_universal_time(@clk_time, sdn)
1477
- end
1478
-
1479
- # 内部時間(ローカル)
1480
- #
1481
- # @param [Integer] sdn 参照事象の通し番号
1482
- #
1483
- # @return [Numeric]
1484
- #
1485
- # T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
1486
- #
1487
- # 時法によっては、異なる意味を持つことがある
1488
- #
1489
- def local_time(sdn=nil)
1490
- raise NameError, "Temporal Reference System is not defined" unless @frame
1491
- @local_time ||= @frame.to_local_time(@clk_time, sdn)
1492
- end
1493
-
1494
- # 繰り上がり
1495
- #
1496
- # @return [Numeric]
1497
- #
1498
- # 日付の境界が午前0時でない場合、clk_time の最上位桁に 0 以外が入ることがある
1499
- #
1500
- def carry
1501
- return @clk_time[0]
1502
- end
1503
-
1504
- # 要素の参照
1505
- #
1506
- # @param [Integer, String] index 参照する要素の指定
1507
- #
1508
- # @return [Numeric]
1509
- #
1510
- def value(index)
1511
- @clk_time[_digit(index) {|digit| digit >= DAY}]
1512
- end
1513
-
1514
- #protected
1515
- # 属性のコピー
1516
- # @private
1517
- def _copy(options={})
1518
- @clk_time = options[:time] if options.key?(:time)
1519
- if options.key?(:clock)
1520
- options.delete(:frame)
1521
- @frame = options[:clock]
1522
- end
1523
- if options.key?(:tz_prop)
1524
- @frame = @frame.dup
1525
- @frame.tz_prop = options[:tz_prop]
1526
- end
1527
- return super
1528
- end
1529
-
1530
- # オブジェクトの生成
1531
- #
1532
- # @param [String] time ISO8601形式の時刻表現
1533
- # @param [Array<Numeric>] time (日, 時, 分, 秒)
1534
- #
1535
- #
1536
- # @param [Hash] options 以下の通り
1537
- # @option options [When::TM::Clock] :frame
1538
- # @option options [Integer] :precision
1539
- #
1540
- def initialize(time, options={})
1541
- # 参照系の取得
1542
- @frame = options[:frame] || Clock.local_time
1543
- @frame = When.Clock(@frame) if (@frame.kind_of?(String))
1544
- options.delete(:frame)
1545
-
1546
- # 時刻表現の解読 ( Time Zone の解釈 )
1547
- if (time.kind_of?(String))
1548
- case time
1549
- when /\A([-+])?(\d{2,}?):?(\d{2})?:?(\d{2}(\.\d+)?)?\z/
1550
- sign, hh, mm, ss = $~[1..4]
1551
- time = @frame._validate([0,0,0,0],
1552
- [0,
1553
- -(sign.to_s + "0" + hh.to_s).to_i,
1554
- -(sign.to_s + "0" + mm.to_s).to_i,
1555
- Pair._en_number(-(sign.to_s + "0" + ss.to_s).to_f)])
1556
- time[0] = Pair.new(0, time[0].to_i) if (time[0] != 0)
1557
- when /\AZ\z/
1558
- time = [0,0,0,0]
1559
- else
1560
- raise ArgumentError, "Invalid Time Format"
1561
- end
1562
- end
1563
- @clk_time = time
1564
-
1565
- # 分解能
1566
- @precision = @frame._precision(time, options.delete(:precision))
1567
-
1568
- super(options)
1569
- end
1570
-
1571
- private
1572
-
1573
- # オブジェクトの正規化
1574
- def _normalize(options={})
1575
- # strftime で使用する locale
1576
- @keys |= @frame.keys
1577
-
1578
- # 時刻の正規化
1579
- @clk_time = @frame._validate(@clk_time) unless options[:validate]
1580
- end
1581
-
1582
- # 加減算共通処理
1583
- def _plus(period)
1584
- self.dup._copy({:time=>@frame._validate(@clk_time, @frame._arrange_length(period.time)),
1585
- :events=>nil, :query=>nil, :validate=>:done})
1586
- end
1587
- end
1588
-
1589
- #
1590
- # 暦日
1591
- #
1592
- # see {gml schema}[link:http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#CalDateType]
1593
- #
1594
- class CalDate < TemporalPosition
1595
-
1596
- # 検索オプション
1597
- # @private
1598
- SearchOption = {After=>[0, -2, Before], Before=>[-2, 0, After]}
1599
-
1600
- # 日付要素
1601
- #
1602
- # @return [Array<Numeric>]
1603
- #
1604
- # @note ISO19108 では sequence<Integer> だが、閏月などが表現可能なよう Numeric としている。
1605
- #
1606
- attr_reader :cal_date
1607
- alias :calDate :cal_date
1608
-
1609
- # この時間位置と関連付けられた時間参照系 (relation - Reference)
1610
- #
1611
- # The time reference system associated with the temporal position being described
1612
- #
1613
- # @return [When::TM::ReferenceSystem]
1614
- #
1615
- alias :calendar :frame
1616
-
1617
- # 暦年代
1618
- #
1619
- # @return [When::TM::CalendarEra]
1620
- #
1621
- attr_accessor :calendar_era
1622
- private :calendar_era=
1623
- alias :calendarEra :calendar_era
1624
-
1625
- # 暦年代属性
1626
- #
1627
- # @return [Array] ( name, epoch, reverse, go back )
1628
- # - name [String] 暦年代名
1629
- # - epoch [Integer] 使用する When::TM::Calendar で暦元に対応する年
1630
- # - reverse [Boolean] 年数が昇順(false,nil)か降順(true)か
1631
- # - go back [Boolean] 参照イベントより前の暦日か(true)、否か(false,nil)
1632
- #
1633
- attr_accessor :calendar_era_props
1634
- private :calendar_era_props=
1635
-
1636
- # 暦年代名
1637
- #
1638
- # @return [String] 暦年代名
1639
- #
1640
- def calendar_era_name
1641
- @calendar_era_props ? @calendar_era_props[0] : nil
1642
- end
1643
- alias :calendarEraName :calendar_era_name
1644
-
1645
- # 暦年代元期
1646
- #
1647
- # @return [Integer] 使用する When::TM::Calendar で暦元に対応する年
1648
- #
1649
- def calendar_era_epoch
1650
- @calendar_era_props ? @calendar_era_props[1] : 0
1651
- end
1652
-
1653
- # 暦年代正逆
1654
- #
1655
- # @return [Boolean] 年数が昇順(false,nil)か降順(true)か
1656
- #
1657
- def calendar_era_reverse
1658
- @calendar_era_props ? @calendar_era_props[2] : false
1659
- end
1660
-
1661
- # 暦年代遡及
1662
- #
1663
- # @return [Boolean] 参照イベントより前の暦日か(true)、否か(false,nil)
1664
- #
1665
- def calendar_era_go_back
1666
- @calendar_era_props ? @calendar_era_props[3] : false
1667
- end
1668
-
1669
- # 時法の取得 - ダミー
1670
- def clock
1671
- nil
1672
- end
1673
-
1674
- # 内部時間
1675
- #
1676
- # @return [Numeric]
1677
- #
1678
- # 当日正午の 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
1679
- #
1680
- def universal_time
1681
- return super if [Now, Max, Min].include?(@indeterminated_position)
1682
- @universal_time ||= JulianDate._d_to_t(to_i)
1683
- end
1684
- alias :local_time :universal_time
1685
-
1686
- # ユリウス日
1687
- #
1688
- # @return [Integer]
1689
- #
1690
- # -4712-01-01からの経過日数に対応する通番
1691
- #
1692
- def to_i
1693
- @sdn ||= _to_i
1694
- end
1695
-
1696
- #
1697
- # 暦法上の通日
1698
- #
1699
- def _to_i
1700
- void, epoch = @calendar_era_props
1701
- if epoch
1702
- date = @cal_date.dup
1703
- date[0] += epoch
1704
- else
1705
- date = @cal_date
1706
- end
1707
- @frame.to_julian_date(date)
1708
- end
1709
- private :_to_i
1710
-
1711
- # 剰余類化
1712
- #
1713
- # @param [Numeric] remainder 剰余
1714
- # @param [Integer] divisor 法(>0)
1715
- #
1716
- # @return [When::Coordinates::Residue] 当日、当年を基準とする剰余類
1717
- #
1718
- def to_residue(remainder, divisor)
1719
- When::Coordinates::Residue.new(remainder, divisor, {'day' => least_significant_coordinate,
1720
- 'year' => most_significant_coordinate})
1721
- end
1722
-
1723
- # 暦年代の削除
1724
- #
1725
- # @return [When::TM::CalDate] 暦年代を削除した When::TM::CalDate
1726
- #
1727
- def without_era
1728
- target = dup
1729
- return target unless calendar_era
1730
- options = _attr
1731
- options[:era] = nil
1732
- options[:era_name] = nil
1733
- options[:date] = cal_date.dup
1734
- options[:date][0] += calendar_era_epoch
1735
- target._copy(options)
1736
- end
1737
-
1738
- # 要素の参照
1739
- #
1740
- # @param [Integer, String] index 参照する要素の指定
1741
- #
1742
- # @return [Numeric]
1743
- #
1744
- def value(index)
1745
- @cal_date[(_digit(index) {|digit| digit <= DAY})-1]
1746
- end
1747
-
1748
- #
1749
- # 最上位の要素
1750
- #
1751
- # @return [Numeric] 暦年代の epoch に関わらず暦法に従った年の通し番号を返す
1752
- #
1753
- def most_significant_coordinate
1754
- coordinate = @cal_date[0]
1755
- coordinate += calendar_era_epoch if @calendar_era_props
1756
- @frame.index_of_MSC.times do |i|
1757
- coordinate = +coordinate * @frame.indices[i].unit + @cal_date[i+1] - @frame.indices[i].base
1758
- end
1759
- coordinate
1760
- end
1761
-
1762
- #
1763
- # 最下位の要素
1764
- #
1765
- # @return [Numeric] 剰余類の演算に用いる日の通し番号を返す
1766
- #
1767
- def least_significant_coordinate
1768
- return to_i + @frame.indices[-1].shift
1769
- end
1770
-
1771
- # ユリウス日または通年が指定の剰余となる日
1772
- #
1773
- # @param [When::Coordinates::Residue] other
1774
- #
1775
- # @return [When::TM::CalDate]
1776
- #
1777
- def &(other)
1778
- raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1779
- case other.event
1780
- when 'day'
1781
- # 指定の剰余となる日
1782
- sdn = other & to_i
1783
- options = {:date=>_date_with_era(@frame.to_cal_date(sdn)), :events=>nil, :query=>@query, :validate=>:done}
1784
- options[:precision] = When::DAY if precision < When::DAY
1785
- result = self.dup._copy(options)
1786
- result.send(:_force_euqal_day, sdn-result.to_i)
1787
-
1788
- when 'year'
1789
- # 指定の剰余となる年
1790
- date = @frame.send(:_decode, _date_without_era)
1791
- date[0] = (other & (date[0] + @frame.diff_to_CE)) - @frame.diff_to_CE
1792
- options = {:date=>_date_with_era(@frame.send(:_encode, date)), :events=>nil, :query=>@query}
1793
- options[:precision] = When::YEAR if precision < When::YEAR
1794
- return self.dup._copy(options)
1795
-
1796
- else
1797
- raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1798
- end
1799
- end
1800
-
1801
- # ユリウス日または通年の剰余
1802
- #
1803
- # @param [When::Coordinates::Residue] other
1804
- #
1805
- # @return [Numeric]
1806
- #
1807
- def %(other)
1808
- raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
1809
- if precision <= When::YEAR && other.units['year'] && other.event != 'year'
1810
- other.to('year') % (most_significant_coordinate + @frame.epoch_in_CE)
1811
- else
1812
- case other.event
1813
- when 'day' ; other % least_significant_coordinate
1814
- when 'year' ; other % (most_significant_coordinate + @frame.epoch_in_CE)
1815
- else ; raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
1816
- end
1817
- end
1818
- end
1819
-
1820
- # 下位桁の切り捨て
1821
- #
1822
- # @param [Integer] digit 切り捨てずに残す、最下位の桁
1823
- #
1824
- # @param [Integer] precision 切り捨て結果の分解能
1825
- #
1826
- # @return [When::TM::CalDate]
1827
- #
1828
- def floor(digit=DAY, precision=digit)
1829
- options = {:date=>@cal_date[0..(digit-1)], :events=>nil, :query=>nil}
1830
- options[:precision] = precision if precision
1831
- self.dup._copy(options)
1832
- end
1833
-
1834
- # 下位桁の切り上げ
1835
- #
1836
- # @param [Integer] digit 切り上げずに残す、最下位の桁
1837
- #
1838
- # @param [Integer] precision 切り上げ結果の分解能
1839
- #
1840
- # @return [When::TM::CalDate]
1841
- #
1842
- def ceil(digit=DAY, precision=digit)
1843
- (self + PeriodDuration.new(1, digit, (-@frame.indices.length)..0)).floor(digit, precision)
1844
- end
1845
-
1846
- # 要素数 ― 上位要素に含まれる下位要素の数
1847
- #
1848
- # @param [Integer] upper 上位要素のインデックス
1849
- # @param [Integer] lower 下位要素のインデックス(DAY または MONTH)
1850
- #
1851
- # @return [Integer]
1852
- #
1853
- def length(upper, lower=DAY)
1854
- range = [floor(upper).to_i, ceil(upper).to_i]
1855
- range = range.map {|d| (Residue.mod(d) {|m| frame._new_month(m)})[0]} if lower == MONTH
1856
- range[1] - range[0]
1857
- end
1858
-
1859
- # 時刻情報のない When::TM::CalDate を返す
1860
- #
1861
- # @return [When::TM::CalDate]
1862
- #
1863
- alias :to_cal_date :dup
1864
- alias :to_CalDate :to_cal_date
1865
-
1866
- # 暦年代が末端の参照であるか?
1867
- #
1868
- # @return [Boolean]
1869
- #
1870
- def leaf?
1871
- ! @calendar_era.respond_to?(:_pool) || @calendar_era.leaf?
1872
- end
1873
-
1874
- # 属性の Hash
1875
- # @private
1876
- def _attr
1877
- super.merge({:era_name=>@calendar_era_props, :era=>@calendar_era})
1878
- end
1879
- protected
1880
-
1881
- # 属性のコピー
1882
- # @private
1883
- def _copy(options={})
1884
- @cal_date = options[:date] if options.key?(:date)
1885
- @calendar_era = options[:era] if options.key?(:era)
1886
- @calendar_era_props = options[:era_name] if options.key?(:era_name)
1887
- return super
1888
- end
1889
-
1890
- # オブジェクトの生成
1891
- #
1892
- # @param [Array<Numeric>] date 日付表現
1893
- #
1894
- # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
1895
- # @option options [When::TM::Calendar] :frame
1896
- # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
1897
- # (Integer は 当該年号の 0 年に相当する通年)
1898
- # @option options [Integer] :precision
1899
- #
1900
- def initialize(date, options={})
1901
- # 年号 & 日付
1902
- @calendar_era_props = options[:era_name]
1903
- @calendar_era = options[:era]
1904
- @cal_date = date
1905
-
1906
- super(options)
1907
- end
1908
-
1909
- private
1910
-
1911
- # オブジェクトの正規化
1912
- def _normalize(options={})
1913
-
1914
- # 日付配列の長さ
1915
- cal_date_index = @cal_date.compact.length
1916
-
1917
- # 日付の正規化
1918
- if @calendar_era_props
1919
- # Calendar Era がある場合
1920
- trans_options = @trans || {} # TODO? 消す
1921
- count = trans_options[:count] || 1
1922
- query_options = (@query || {}).dup
1923
- query_options[:label] = @calendar_era_props
1924
- query_options[:count] = count
1925
- era = date = nil
1926
- if @calendar_era
1927
- era, date = _search_era(@calendar_era, trans_options)
1928
- else
1929
- eras = CalendarEra._instance(query_options)
1930
- raise ArgumentError, "CalendarEraName doesn't exist: #{query_options[:label]}" if eras.empty?
1931
- eras.each do |e|
1932
- era, date = _search_era(e, trans_options)
1933
- next unless era
1934
- count -= 1
1935
- break unless count > 0
1936
- end
1937
- end
1938
- raise RangeError, "Out of CalendarEra Range" unless era
1939
- @calendar_era_props = date.calendar_era_props
1940
- @calendar_era = era
1941
- @cal_date = date.cal_date
1942
- @frame = date.frame
1943
- @query = (@query||{}).merge(date.query)
1944
- @trans = (@trans||{}).merge(date.trans)
1945
- @keys |= calendar_era_name.keys | @frame.keys
1946
- else
1947
- # Calendar Era がない場合
1948
- @frame = When.Resource(options[:frame] || @frame || 'Gregorian', '_c:')
1949
- @cal_date = @frame._validate(@cal_date) unless options[:validate] == :done
1950
- @keys |= @frame.keys
1951
- end
1952
-
1953
- # 分解能
1954
- precision = options.delete(:precision) || @precision
1955
- cal_date_index =
1956
- case options.delete(:_format)
1957
- when :century ; CENTURY
1958
- when :week, :day ; DAY
1959
- else ; cal_date_index - (@frame.indices.length + 1)
1960
- end
1961
- precision ||= cal_date_index if cal_date_index < DAY
1962
- precision ||= @clk_time.precision if @clk_time
1963
- @precision = Index.precision(precision || DAY)
1964
- end
1965
-
1966
- # 暦年代を探す
1967
- def _search_era(era, trans_options)
1968
- cal_date = @cal_date.dup
1969
- cal_date[0] = -cal_date[0] if era.reverse?
1970
- cal_date[0] += era.epoch_year
1971
- date = era.trans(cal_date, trans_options)
1972
- loop do
1973
- case date
1974
- when Before, After
1975
- i0, i1, reverse = SearchOption[date]
1976
- new_era = (date == Before) ? era.prev : era.succ
1977
- break unless new_era
1978
- date = new_era.trans(cal_date, trans_options)
1979
- if date == reverse
1980
- cal_date = new_era.epoch[i0].frame.to_cal_date(era.epoch[i1].frame.to_julian_date(cal_date))
1981
- date = new_era.trans(cal_date, trans_options)
1982
- break if date == reverse
1983
- end
1984
- era = new_era
1985
- when TimeValue
1986
- return era, date
1987
- else
1988
- break
1989
- end
1990
- end
1991
- return nil
1992
- end
1993
-
1994
- # 加減算共通処理
1995
- def _plus(period)
1996
- _frame_adjust(period, self.dup._copy({:date=>_date_with_era(@frame._validate(_date_without_era,
1997
- @frame._arrange_length(period.date))),
1998
- :events=>nil, :query=>nil, :validate=>:done}))
1999
- end
2000
-
2001
- # 年号を除外した @frame の暦法に対応する日付
2002
- def _date_without_era
2003
- date = @cal_date.dup
2004
- date[0] += calendar_era_epoch if @calendar_era_props
2005
- date
2006
- end
2007
-
2008
- # 年号に続く日付
2009
- def _date_with_era(date)
2010
- date[0] -= calendar_era_epoch if @calendar_era_props
2011
- date
2012
- end
2013
-
2014
- # 暦法が変わった場合の補正
2015
- def _frame_adjust(period, date)
2016
- return date if @frame.equal?(date.frame) || (period.to_day||0) == 0
2017
- diff = period.to_day - (date.to_i - to_i)
2018
- return date if diff == 0
2019
- date.send(:_force_euqal_day, diff)
2020
- end
2021
- end
2022
-
2023
- #
2024
- # 時刻を伴った日付
2025
- #
2026
- # see {http://schemas.opengis.net/gml/3.1.1/base/temporalAppendix.xsd#DateAndTimeType gml schema}
2027
- #
2028
- class DateAndTime < CalDate
2029
-
2030
- # 時刻要素
2031
- #
2032
- # @return [When::TM::ClockTime]
2033
- #
2034
- attr_reader :clk_time
2035
- alias :clkTime :clk_time
2036
-
2037
- # 時法の取得
2038
- #
2039
- # @return [When::TM::Clock]
2040
- #
2041
- def clock
2042
- @clk_time.frame
2043
- end
2044
-
2045
- # 内部時間
2046
- #
2047
- # @return [Numeric]
2048
- #
2049
- # 1970-01-01T00:00:00Z からの Universal Coordinated Time の経過時間 / 128秒
2050
- #
2051
- # 暦法によっては、異なる意味を持つことがある
2052
- #
2053
- def universal_time
2054
- return super if [Now, Max, Min].include?(@indeterminated_position)
2055
- raise NameError, "Temporal Reference System is not defined" unless (@frame && clock)
2056
- @universal_time ||= (to_i - JulianDate::JD19700101) * Duration::DAY + @clk_time.universal_time(to_i)
2057
- end
2058
-
2059
- # 内部時間(ローカル)
2060
- #
2061
- # @return [Numeric]
2062
- #
2063
- # 1970-01-01T00:00:00(ローカル) からの Universal Coordinated Time の経過時間 / 128秒
2064
- #
2065
- # 暦法によっては、異なる意味を持つことがある
2066
- #
2067
- def local_time
2068
- return super if [Now, Max, Min].include?(@indeterminated_position)
2069
- raise NameError, "Temporal Reference System is not defined" unless (@frame && clock)
2070
- @local_time ||= (to_i - JulianDate::JD19700101) * Duration::DAY + @clk_time.local_time(to_i)
2071
- end
2072
-
2073
- # 要素の参照
2074
- #
2075
- # @param [Integer] index 参照する要素の指定
2076
- #
2077
- # @return [Numeric]
2078
- #
2079
- def value(index)
2080
- digit = _digit(index)
2081
- return (digit <= DAY) ? @cal_date[digit-1] : @clk_time.clk_time[digit]
2082
- end
2083
-
2084
- # ユリウス日または通年が指定の剰余となる日
2085
- #
2086
- # @param [When::Coordinates::Residue] other
2087
- #
2088
- # @return [When::TM::DateAndTime]
2089
- #
2090
- def &(other)
2091
- raise TypeError,"The right operand should be When::Coordinates::Residue" unless other.kind_of?(Residue)
2092
- case other.event
2093
- when 'day'
2094
- # 指定の剰余となる日
2095
- sdn = other & to_i
2096
- options = {:date=>_date_with_era(@frame.to_cal_date(sdn)), :time=>@clk_time.clk_time.dup,
2097
- :events=>nil, :query=>@query, :validate=>:done}
2098
- options[:precision] = When::DAY if precision < When::DAY
2099
- result = self.dup._copy(options)
2100
- result.send(:_force_euqal_day, sdn-result.to_i)
2101
-
2102
- when 'year'
2103
- # 指定の剰余となる年
2104
- date = @frame.send(:_decode, _date_without_era)
2105
- date[0] = (other & (date[0] + @frame.diff_to_CE)) - @frame.diff_to_CE
2106
- options = {:date=>_date_with_era(@frame.send(:_encode, date)), :time=>@clk_time.clk_time.dup,
2107
- :events=>nil, :query=>@query}
2108
- options[:precision] = When::YEAR if precision < When::YEAR
2109
- return self.dup._copy(options)
2110
-
2111
- else
2112
- raise ArgumentError,"The right operand should have a unit 'day' or 'year'"
2113
- end
2114
- end
2115
-
2116
- # 下位桁の切り捨て
2117
- #
2118
- # @param [Integer] digit 切り捨てずに残す、最下位の桁
2119
- #
2120
- # @param [Integer] precision 切り捨て結果の分解能
2121
- #
2122
- # @return [When::TM::DateAndTime]
2123
- #
2124
- def floor(digit=DAY, precision=digit)
2125
- count = digit - clock.indices.length
2126
-
2127
- if digit>=DAY
2128
- date = @cal_date.dup
2129
- elsif @calendar_era_props
2130
- date = @cal_date.dup
2131
- date[0] += calendar_era_epoch
2132
- date = @frame._validate(date[0..(digit-1)])
2133
- date[0] -= calendar_era_epoch
2134
- else
2135
- date = @frame._validate(@cal_date[0..(digit-1)])
2136
- end
2137
-
2138
- time = @clk_time.clk_time[0..((digit<=DAY) ? 0 : ((count>=0) ? -1 : digit))]
2139
- time[0] += to_i
2140
- time = clock._validate(time)
2141
- time[0] -= to_i
2142
-
2143
- if (count >= 0)
2144
- factor = 10**count
2145
- time[-1] = (time[-1] * factor).floor.to_f / factor
2146
- end
2147
-
2148
- # オブジェクトの生成
2149
- options = {:date=>date, :validate=>:done, :events=>nil, :query=>nil,
2150
- :time=>(digit<=DAY) ? time : @clk_time.dup._copy({:time=>time})}
2151
- options[:precision] = precision if precision
2152
- return self.dup._copy(options)
2153
- end
2154
-
2155
- # 下位桁の切り上げ
2156
- #
2157
- # @param [Integer] digit 切り上げずに残す、最下位の桁
2158
- #
2159
- # @param [Integer] precision 切り上げ結果の分解能
2160
- #
2161
- # @return [When::TM::DateAndTime]
2162
- #
2163
- def ceil(digit=DAY, precision=digit)
2164
- length = clock.indices.length
2165
- count = digit - length
2166
- period = PeriodDuration.new((count<=0) ? 1 : 0.1**count, digit, (-@frame.indices.length)..length)
2167
- result = floor(digit, precision) + period
2168
- result += clock.tz_difference if (result.universal_time <= self.universal_time)
2169
- return result
2170
- end
2171
-
2172
- # 位置情報
2173
- #
2174
- # @return [When::Coordinates::Spatial]
2175
- #
2176
- def location
2177
- @location ||= @clk_time.frame.location
2178
- end
2179
-
2180
- # 時刻情報のない When::TM::CalDate を返す
2181
- #
2182
- # @return [When::TM::CalDate]
2183
- #
2184
- def to_cal_date
2185
- options = _attr
2186
- options.delete(:clock)
2187
- options[:precision] = [When::DAY, options[:precision]].min
2188
- CalDate.new(@cal_date, options)
2189
- end
2190
- alias :to_CalDate :to_cal_date
2191
-
2192
- # 標準ライブラリの DateTime オブジェクトへの変換
2193
- #
2194
- alias :to_date_or_datetime :to_datetime
2195
-
2196
- #protected
2197
-
2198
- # 属性の Hash
2199
- # @private
2200
- def _attr
2201
- super.merge({:clock=>clock})
2202
- end
2203
-
2204
- # 属性のコピー
2205
- # @private
2206
- def _copy(options={})
2207
- # 夏時間の調整
2208
- case options[:time]
2209
- when Array
2210
- if clock._need_validate
2211
- if @calendar_era_props
2212
- date = options[:date].dup
2213
- date[0] += calendar_era_epoch
2214
- else
2215
- date = options[:date]
2216
- end
2217
- new_clock = clock._daylight([@frame, date, options[:time]])
2218
- options[:time] = options[:time].map {|t| t * 1}
2219
- else
2220
- new_clock = clock
2221
- end
2222
- options[:time] = @clk_time.dup._copy(options.merge({:clock=>new_clock}))
2223
- when nil
2224
- options[:time] = @clk_time.dup._copy(options)
2225
- end
2226
-
2227
- return super(options)
2228
- end
2229
-
2230
- # オブジェクトの生成
2231
- #
2232
- # @param [Array<Numeric>] date 日付表現
2233
- # @param [Array<Numeric>] time 時刻表現
2234
- # @param [Hash] options 下記の通り (see also {When::TM::TemporalPosition._instance})
2235
- # @option options [When::TM::Calendar] :frame
2236
- # @option options [When::TM::Clock] :clock
2237
- # @option options [When::TM::CalendarEra, When::BasicTypes::M17n, Array<When::BasicTypes::M17n, Integer>] :era_name
2238
- # (Integer は 当該年号の 0 年に相当する通年)
2239
- # @option options [Integer] :precision
2240
- #
2241
- def initialize(date, time, options={})
2242
- options[:time] = time
2243
- super(date, options)
2244
- end
2245
-
2246
- private
2247
-
2248
- # オブジェクトの正規化
2249
- def _normalize(options={})
2250
-
2251
- # Clock
2252
- unless options[:validate]
2253
- clock = Clock.get_clock_option(options)
2254
- clock ||= options[:time].frame if options[:time].kind_of?(ClockTime)
2255
- clock ||= Clock.local_time
2256
- end
2257
- clock = When.Clock(clock) if clock.kind_of?(String)
2258
- clock_is_timezone = clock && !clock.kind_of?(When::TM::Clock)
2259
- clock = clock.daylight if clock_is_timezone
2260
-
2261
- # ClockTime
2262
- @clk_time =
2263
- case options[:time]
2264
- when ClockTime ; options[:time]
2265
- when Array ; ClockTime.new(options[:time], {:frame=>clock, :precision=>options[:precision], :validate=>:done})
2266
- else ; clock.to_clk_time(options[:time], {:precision=>options[:precision]})
2267
- end
2268
-
2269
- super
2270
-
2271
- # 日付と時刻の正規化
2272
- unless options[:validate]
2273
- time = @clk_time.clk_time
2274
- precision = @clk_time.precision
2275
- second = time[clock.base.length-1]
2276
- second -= clock.base[-1] if second
2277
- if second && second != 0 && time_standard.has_leap?
2278
- zero = DateAndTime.new(@cal_date, time[0..-2],
2279
- {:frame=>@frame, :clock=>clock, :precision=>precision,
2280
- :era_name=>@calendar_era_props, :era=>options[:era],
2281
- :time_standard=>time_standard, :location=>@location})
2282
- end
2283
-
2284
- # 日付と時刻の関係の調整
2285
- @cal_date = _date_with_era(@frame._validate(_date_without_era) {|jdn|
2286
- time[0] += jdn
2287
- time[0..-1] = clock._validate(time)
2288
- jdn = time[0] * 1
2289
- time[0] -= jdn
2290
- jdn
2291
- })
2292
-
2293
- # 夏時間の調整
2294
- if clock._need_validate
2295
- if @calendar_era_props
2296
- cal_date = @cal_date.dup
2297
- cal_date[0] += calendar_era_epoch
2298
- else
2299
- cal_date = @cal_date
2300
- end
2301
- clock = clock._daylight([@frame, cal_date, time])
2302
- end
2303
- time = [time[0]] + time[1..-1].map {|t| t * 1}
2304
- @clk_time = ClockTime.new(time, {:frame=>clock, :precision=>precision, :validate=>:done}) if clock_is_timezone
2305
-
2306
- # 閏秒
2307
- if zero
2308
- leap = ((dynamical_time - zero.dynamical_time) * clock.second - second).to_i
2309
- if leap != 0 && leap.abs < clock.second
2310
- @cal_date = zero.cal_date
2311
- @clk_time = zero.clk_time
2312
- @clk_time.clk_time[-1] += second
2313
- leap /= clock.second
2314
- @universal_time = @local_time = When::Coordinates::LeapSeconds.new(@local_time-leap, leap, 1/clock.second)
2315
- @dynamical_time -= leap
2316
- end
2317
- end
2318
- end
2319
-
2320
- # 後処理
2321
- @keys |= @clk_time.keys
2322
- end
2323
-
2324
- # 加減算共通処理
2325
- def _plus(period)
2326
- # 日時の加算
2327
- time = @clk_time.clk_time.dup
2328
- pdate = @frame._arrange_length(period.date)
2329
- ptime = clock._arrange_length(period.time)
2330
- date = _date_with_era(@frame._validate(_date_without_era, pdate) {|jdn|
2331
- time[0] += jdn
2332
- time = clock._validate(time, ptime)
2333
- jdn = time[0] * 1
2334
- time[0] -= jdn
2335
- jdn
2336
- })
2337
-
2338
- # オブジェクトの生成
2339
- _frame_adjust(period, self.dup._copy({:date=>date, :time=>time, :validate=>:done, :events=>nil, :query=>nil}))
2340
- end
2341
- end
2342
1235
  end