l43_time 0.1.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.
- checksums.yaml +7 -0
- data/lib/l43/time/consts.rb +10 -0
- data/lib/l43/time/delta.rb +57 -0
- data/lib/l43/time/errors.rb +8 -0
- data/lib/l43/time/parser.rb +127 -0
- data/lib/l43/time/range.rb +32 -0
- data/lib/l43/time/time_range.rb +22 -0
- data/lib/l43/time/to_time.rb +66 -0
- data/lib/l43/time/tools/scanner.rb +30 -0
- data/lib/l43/time/ts.rb +77 -0
- data/lib/l43/time/version.rb +8 -0
- data/lib/l43/time.rb +18 -0
- metadata +80 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9e00494e65d3ddd6c92edf5c8a7afe23b051f9d1e5f2a7290b4262e2ba97f467
|
|
4
|
+
data.tar.gz: 0ef11ca9be18c6843c7bfb36a72f67a7d37cfdb430571a95e92e33735bc0e06c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f2436b9759c0afdb3c9ead2ed7505732d8093a4d3c4efa5e55f35407a83ceb1ac7ad67dafc3b12e2803f72299944a43fb79e40f46eb9ad4f87003a830ddf7f12
|
|
7
|
+
data.tar.gz: 60bd5b65ebbf69c2292f35b4cebe1c2eaad95848256a5e3de917210e40eff0c34249242404ad31e267f03c90a7f323e54db752f7a49a56c4a4aeb935f1cde1b1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'errors'
|
|
4
|
+
require_relative 'parser'
|
|
5
|
+
|
|
6
|
+
module L43
|
|
7
|
+
module Time
|
|
8
|
+
module Delta
|
|
9
|
+
include Parser
|
|
10
|
+
|
|
11
|
+
def after(duration, from: nil, format: :to_f) = _delta(duration, from:, format:)
|
|
12
|
+
def before(duration, from: nil, format: :to_f) = _delta(duration, from:, format:, factor: -1)
|
|
13
|
+
|
|
14
|
+
def after!(duration, from: nil, format: :to_f)
|
|
15
|
+
case after(duration, from:, format:)
|
|
16
|
+
in :ok, result
|
|
17
|
+
result
|
|
18
|
+
in :error, error
|
|
19
|
+
raise BadFormat, error
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def before!(duration, from: nil, format: :to_f)
|
|
24
|
+
case before(duration, from:, format:)
|
|
25
|
+
in :ok, result
|
|
26
|
+
result
|
|
27
|
+
in :error, error
|
|
28
|
+
raise BadFormat, error
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
def _delta(duration, from: nil, format: :to_f, factor: 1)
|
|
34
|
+
from ||= ::Time.now
|
|
35
|
+
case parse_or_duration(duration)
|
|
36
|
+
in :ok, result
|
|
37
|
+
_format_date(from + factor * result.to_f, format:)
|
|
38
|
+
in error
|
|
39
|
+
error
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def _format_date(date, format:)
|
|
44
|
+
case format
|
|
45
|
+
in Symbol => sym
|
|
46
|
+
date.send(sym).to_s
|
|
47
|
+
else
|
|
48
|
+
raise ArgumentError, 'only symbols are supported for the format: argument'
|
|
49
|
+
end
|
|
50
|
+
rescue NoMethodError
|
|
51
|
+
raise ArgumentError, 'only symbols representing instance methods of the class Time are supported for the format: argument'
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'consts'
|
|
4
|
+
require_relative 'errors'
|
|
5
|
+
require_relative 'tools/scanner'
|
|
6
|
+
require_relative 'ts'
|
|
7
|
+
|
|
8
|
+
module L43
|
|
9
|
+
module Time
|
|
10
|
+
module Parser
|
|
11
|
+
include Ts
|
|
12
|
+
|
|
13
|
+
Prefix =
|
|
14
|
+
%r{
|
|
15
|
+
(?<unit>[[:lower:]]+) [[:space:]]*:[[:space:]]* (?<value>[[:digit:]]+ (?:\.[[:digit:]]+)? )
|
|
16
|
+
}x
|
|
17
|
+
|
|
18
|
+
Suffix =
|
|
19
|
+
%r{
|
|
20
|
+
(?<value>[[:digit:]]+ (?:\.[[:digit:]]+)?) [[:space:]]* (?<unit>[[:lower:]]+)
|
|
21
|
+
}x
|
|
22
|
+
|
|
23
|
+
def parse_duration!(str)
|
|
24
|
+
case parse_duration(str)
|
|
25
|
+
in :ok, value
|
|
26
|
+
value
|
|
27
|
+
in :error, msg
|
|
28
|
+
raise BadFormat, msg
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def parse_duration(str)
|
|
33
|
+
if str[Prefix]
|
|
34
|
+
Helper.parse_prefix(str)
|
|
35
|
+
else
|
|
36
|
+
Helper.parse_suffix(str)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_or_duration!(str)
|
|
41
|
+
case parse_or_duration(str)
|
|
42
|
+
in :ok, value
|
|
43
|
+
value
|
|
44
|
+
in :error, msg
|
|
45
|
+
raise BadFormat, msg
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parse_or_duration(str)
|
|
50
|
+
case duration_as_string(str)
|
|
51
|
+
in :ok, value
|
|
52
|
+
[:ok, value]
|
|
53
|
+
else
|
|
54
|
+
parse_duration(str)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
module Helper extend self
|
|
59
|
+
Units = {
|
|
60
|
+
's' => [1, 'seconds'],
|
|
61
|
+
'second' => [1, 'seconds'],
|
|
62
|
+
'seconds' => [1, 'seconds'],
|
|
63
|
+
|
|
64
|
+
'm' => [60, 'minutes'],
|
|
65
|
+
'minute' => [60, 'minutes'],
|
|
66
|
+
'minutes' => [60, 'minutes'],
|
|
67
|
+
|
|
68
|
+
'h' => [3600, 'hours'],
|
|
69
|
+
'hour' => [3600, 'hours'],
|
|
70
|
+
'hours' => [3600, 'hours'],
|
|
71
|
+
|
|
72
|
+
'd' => [86400, 'days'],
|
|
73
|
+
'day' => [86400, 'days'],
|
|
74
|
+
'days' => [86400, 'days'],
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def parse_prefix(str) = _parse_with(str, rgx: Prefix)
|
|
78
|
+
def parse_suffix(str) = _parse_with(str, rgx: Suffix)
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
def _parse_with(str, rgx:)
|
|
82
|
+
sign = ""
|
|
83
|
+
if str.start_with?("-")
|
|
84
|
+
sign = "-"
|
|
85
|
+
str = str[1..]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
parsed = Tools::Scanner.scan_with_captures(str:, rgx:)
|
|
89
|
+
.inject([Set.new, 0, nil]) { |(used, result, error), captures| _update_duration(used:, result:, error:, unit: captures.unit, value: captures.value) }
|
|
90
|
+
|
|
91
|
+
case parsed
|
|
92
|
+
in [_, result, nil]
|
|
93
|
+
[:ok, sign + result.to_s]
|
|
94
|
+
in [_, _, error]
|
|
95
|
+
[:error, error]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def _seconds(unit:, used:, value:)
|
|
100
|
+
case Units.fetch(unit, :not_found)
|
|
101
|
+
in :not_found
|
|
102
|
+
[:error, "#{unit} is not supported, use d(ays?), h(ours?), m(inutes), s(econds?) only"]
|
|
103
|
+
in factor, name
|
|
104
|
+
if used.member?(name)
|
|
105
|
+
[:error, "#{name} already used"]
|
|
106
|
+
else
|
|
107
|
+
used << name
|
|
108
|
+
[:ok, factor * value.to_f]
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def _update_duration(used:, result:, error:, unit:, value:)
|
|
114
|
+
return [used, result, error] if error
|
|
115
|
+
case _seconds(unit:, used:, value:)
|
|
116
|
+
in :error, error
|
|
117
|
+
[used, result, error]
|
|
118
|
+
in :ok, value
|
|
119
|
+
[used, result+value, nil]
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'l43/open_object'
|
|
4
|
+
module L43
|
|
5
|
+
module Time
|
|
6
|
+
class Range
|
|
7
|
+
extend L43::OpenObject
|
|
8
|
+
|
|
9
|
+
attributes from: nil, to: nil
|
|
10
|
+
def ===(other)
|
|
11
|
+
other = _time(other)
|
|
12
|
+
return false if from&.> other
|
|
13
|
+
return false if to&.< other
|
|
14
|
+
true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
def initialize(from: nil, to: nil)
|
|
19
|
+
raise ArgumentError, "need at least one of: from:, to:" unless from || to
|
|
20
|
+
@from = _time(from)
|
|
21
|
+
@to = _time(to)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def _time(str_or_time)
|
|
25
|
+
return Time.str_to_time(str_or_time) if String === str_or_time
|
|
26
|
+
str_or_time
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'range'
|
|
4
|
+
module L43
|
|
5
|
+
module Time
|
|
6
|
+
module TimeRange
|
|
7
|
+
def str_to_range(str)
|
|
8
|
+
case str.split("..")
|
|
9
|
+
in from, to
|
|
10
|
+
time_range(from:, to:)
|
|
11
|
+
else
|
|
12
|
+
raise ArgumentError, "must use a str of format '<time>..<time>'"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def time_range(from: nil, to: nil)
|
|
17
|
+
Range.new(from:, to:)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'parser'
|
|
4
|
+
module L43
|
|
5
|
+
module Time
|
|
6
|
+
module Duration
|
|
7
|
+
extend Parser
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module ToTime
|
|
11
|
+
T = ::Time
|
|
12
|
+
def str_to_time(str)
|
|
13
|
+
case str
|
|
14
|
+
when /\A\d{14}\z/
|
|
15
|
+
T.strptime(str, "%Y%m%d%H%M%S")
|
|
16
|
+
when /\A\d{12}\z/
|
|
17
|
+
T.strptime(str, "%y%m%d%H%M%S")
|
|
18
|
+
when /\A\d{6}\z/
|
|
19
|
+
T.strptime(str, "%y%m%d")
|
|
20
|
+
when /\A\d{4}\z/
|
|
21
|
+
T.strptime(str, "%m%d")
|
|
22
|
+
when /\A\d{2}\z/
|
|
23
|
+
T.strptime(str, "%d")
|
|
24
|
+
else
|
|
25
|
+
parse_symbolic_or_duration(str)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
def parse_symbolic_or_duration(str)
|
|
31
|
+
case symbolic_time(str)
|
|
32
|
+
in :ok, time
|
|
33
|
+
time
|
|
34
|
+
else
|
|
35
|
+
d = Duration.parse_duration!(str).to_f
|
|
36
|
+
T.now + d
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def sym_today = T.strptime(format("%02d", T.now.day), "%d")
|
|
41
|
+
def sym_yesterday = T.strptime(format("%02d", T.now.day), "%d") - SPERD
|
|
42
|
+
|
|
43
|
+
SymbolicTimes = {
|
|
44
|
+
"today" => :sym_today,
|
|
45
|
+
"yesterday" => :sym_yesterday,
|
|
46
|
+
"yd" => :sym_yesterday,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
def symbolic_time(str)
|
|
50
|
+
# TODO: Use &"sym...".to_sym
|
|
51
|
+
map_ok(exception: KeyError) {
|
|
52
|
+
send SymbolicTimes.fetch(str)
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def map_ok(exception: RuntimeError, &blk)
|
|
57
|
+
[:ok, blk.()]
|
|
58
|
+
rescue exception => e
|
|
59
|
+
[:error, e.message]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
module L43
|
|
5
|
+
module Time
|
|
6
|
+
module Tools
|
|
7
|
+
module Scanner extend self
|
|
8
|
+
def scan_with_captures(str:, rgx:, names: :keys)
|
|
9
|
+
result = []
|
|
10
|
+
str
|
|
11
|
+
.scan(rgx) { |*| result << _extract(from: Regexp.last_match, names:) }
|
|
12
|
+
result
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def _extract(from:, names:)
|
|
17
|
+
case names
|
|
18
|
+
in :keys
|
|
19
|
+
OpenStruct.new(from.named_captures).freeze
|
|
20
|
+
in :all
|
|
21
|
+
from.captures.freeze
|
|
22
|
+
else
|
|
23
|
+
OpenStruct.new(from.named_captures.slice(names.map(&:to_s))).freeze
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/l43/time/ts.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'consts'
|
|
4
|
+
require_relative 'errors'
|
|
5
|
+
|
|
6
|
+
module L43
|
|
7
|
+
module Time
|
|
8
|
+
module Ts
|
|
9
|
+
DecimalPart = %r{\A(.*)\.(\d+)\z}
|
|
10
|
+
Seperators =
|
|
11
|
+
Regexp.compile(%w[. : _ -].map { Regexp.escape(it) }.join('|'))
|
|
12
|
+
|
|
13
|
+
def duration_as_string!(str)
|
|
14
|
+
case duration_as_string(str)
|
|
15
|
+
in :ok, value
|
|
16
|
+
value
|
|
17
|
+
in :error, msg
|
|
18
|
+
raise BadFormat, msg
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
alias_method :duration_s!, :duration_as_string!
|
|
22
|
+
|
|
23
|
+
def duration_as_string(str)
|
|
24
|
+
header = ''
|
|
25
|
+
if str.start_with?('+')
|
|
26
|
+
str = str[1..]
|
|
27
|
+
elsif str.start_with?('-')
|
|
28
|
+
str = str[1..]
|
|
29
|
+
header = '-'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if DecimalPart === str
|
|
33
|
+
Helper.duration_as_string($1, $2, header)
|
|
34
|
+
else
|
|
35
|
+
Helper.duration_as_string(str, "0", header)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
alias_method :duration_s, :duration_as_string
|
|
39
|
+
|
|
40
|
+
module Helper extend self
|
|
41
|
+
|
|
42
|
+
def duration_as_string(secs, millisecs, header)
|
|
43
|
+
case _duration_as_string(secs)
|
|
44
|
+
in :ok, value
|
|
45
|
+
[:ok, [header, value, '.', millisecs].join]
|
|
46
|
+
in error
|
|
47
|
+
error
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
def _compute(parts)
|
|
53
|
+
[:ok,
|
|
54
|
+
parts
|
|
55
|
+
.reverse
|
|
56
|
+
.zip([1, SPERM, SPERH, SPERD])
|
|
57
|
+
.inject(0) { |s, (v,f)| s + f * Integer(v) }
|
|
58
|
+
]
|
|
59
|
+
rescue ArgumentError
|
|
60
|
+
[:error, "Only digits or seperators are allowed in a duration string"]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def _duration_as_string(secs)
|
|
64
|
+
case secs.split(Seperators)
|
|
65
|
+
in [m, _, _, _, _, *]
|
|
66
|
+
[:error, "Must not specify more than day values, got leading #{m}"]
|
|
67
|
+
in parts
|
|
68
|
+
_compute(parts)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/l43/time.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require_relative 'time/delta'
|
|
6
|
+
require_relative 'time/time_range'
|
|
7
|
+
require_relative 'time/to_time'
|
|
8
|
+
require_relative 'time/version'
|
|
9
|
+
module L43
|
|
10
|
+
module Time
|
|
11
|
+
|
|
12
|
+
extend Delta
|
|
13
|
+
include ToTime
|
|
14
|
+
include TimeRange
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
metadata
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: l43_time
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Robert Dober
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-03-30 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ostruct
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.6.3
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.6.3
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: l43_open_object
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.2.5
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.2.5
|
|
40
|
+
description: 'Time related tools
|
|
41
|
+
|
|
42
|
+
'
|
|
43
|
+
email: robert.dober@gmail.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- lib/l43/time.rb
|
|
49
|
+
- lib/l43/time/consts.rb
|
|
50
|
+
- lib/l43/time/delta.rb
|
|
51
|
+
- lib/l43/time/errors.rb
|
|
52
|
+
- lib/l43/time/parser.rb
|
|
53
|
+
- lib/l43/time/range.rb
|
|
54
|
+
- lib/l43/time/time_range.rb
|
|
55
|
+
- lib/l43/time/to_time.rb
|
|
56
|
+
- lib/l43/time/tools/scanner.rb
|
|
57
|
+
- lib/l43/time/ts.rb
|
|
58
|
+
- lib/l43/time/version.rb
|
|
59
|
+
homepage: https://codeberg.org/lab419/l43_time
|
|
60
|
+
licenses:
|
|
61
|
+
- AGPL-3.0-or-later
|
|
62
|
+
metadata: {}
|
|
63
|
+
rdoc_options: []
|
|
64
|
+
require_paths:
|
|
65
|
+
- lib
|
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
67
|
+
requirements:
|
|
68
|
+
- - ">="
|
|
69
|
+
- !ruby/object:Gem::Version
|
|
70
|
+
version: 4.0.1
|
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
requirements: []
|
|
77
|
+
rubygems_version: 4.0.9
|
|
78
|
+
specification_version: 4
|
|
79
|
+
summary: Time related tools
|
|
80
|
+
test_files: []
|