l43_time 0.1.9 → 0.2.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 +4 -4
- data/lib/l43/time/enumerable_extension.rb +17 -0
- data/lib/l43/time/errors.rb +1 -0
- data/lib/l43/time/time_calc/arg_parser.rb +172 -0
- data/lib/l43/time/time_calc/calculate.rb +85 -0
- data/lib/l43/time/time_calc/cli/arguments.rb +36 -0
- data/lib/l43/time/time_calc/cli/help.rb +89 -0
- data/lib/l43/time/time_calc/cli.rb +74 -0
- data/lib/l43/time/time_calc/time_methods.rb +24 -0
- data/lib/l43/time/version.rb +1 -1
- data/lib/l43/time/wrapper.rb +73 -0
- metadata +35 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6598feb4c3eb9c20748aed065de3fbbc0ee9305fb86e70cd2ea1aaa01c4a9da4
|
|
4
|
+
data.tar.gz: 8b2c428ab4e6373694004b6815c99028ce7739eebf3aa81266bc6b0207768f09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fae438b6f985aa098b8c78289af8626030d11d85771582f49c70f8c0914d9bbcf7ab012924dce18c6069e0fb71fa9edc46be9cceabd880b72c340cc5f8faa7e5
|
|
7
|
+
data.tar.gz: 886f8f5a043e5dc8c892bac66197bdc09450540d35e426026fdfafcf2fcd994ffa78cbbdf2d48c5e833c0c014f21438de6871de6a5f2bba763137e4e0578b56e
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43
|
|
4
|
+
module Time
|
|
5
|
+
module EnumerableExtension
|
|
6
|
+
def find_value(enum, &blk)
|
|
7
|
+
enum.each do |ele|
|
|
8
|
+
result = blk.(ele)
|
|
9
|
+
next if result.nil?
|
|
10
|
+
return result
|
|
11
|
+
end
|
|
12
|
+
nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/l43/time/errors.rb
CHANGED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'l43/rgx/all'
|
|
4
|
+
require_relative 'time_methods'
|
|
5
|
+
require_relative '../wrapper'
|
|
6
|
+
require_relative '../enumerable_extension'
|
|
7
|
+
module L43
|
|
8
|
+
module Time
|
|
9
|
+
module TimeCalc
|
|
10
|
+
class ArgParser
|
|
11
|
+
include EnumerableExtension
|
|
12
|
+
|
|
13
|
+
MethodNames = %w[
|
|
14
|
+
midnight
|
|
15
|
+
tomorrow
|
|
16
|
+
yesterday
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
MethodLiterals = MethodNames.map { ".#{it}" }.freeze
|
|
20
|
+
|
|
21
|
+
SecsPerUnit = {
|
|
22
|
+
"s" => 1,
|
|
23
|
+
"m" => 60,
|
|
24
|
+
"h" => 3600,
|
|
25
|
+
"d" => 86400,
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
attr_reader :now
|
|
29
|
+
|
|
30
|
+
def parse(args)
|
|
31
|
+
if args.empty?
|
|
32
|
+
[:time, now]
|
|
33
|
+
else
|
|
34
|
+
case _time_expr_parser.parse(args.join(" "))
|
|
35
|
+
in nil
|
|
36
|
+
[:error, "bad format"]
|
|
37
|
+
in ast, ""
|
|
38
|
+
ast
|
|
39
|
+
# TODO:
|
|
40
|
+
in [:time, time], rest
|
|
41
|
+
_parse_methods(time, rest)
|
|
42
|
+
in _, rest
|
|
43
|
+
[:error, "unexpected suffix #{rest.inspect}"]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
def initialize(now)
|
|
51
|
+
@now = now
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def _date_in_century_parser
|
|
55
|
+
R.new([:digit, 2], [:digit, 2], [:digit, 2], :end) { |*date| time_wrapper.with_year(*date) }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def _date_in_month_parser
|
|
59
|
+
R.new([:digit, 2], :end).map_first { time_wrapper.with_day(it) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def _date_in_year_parser
|
|
63
|
+
R.new([:digit, 2], [:digit, 2], :end) { |*md| time_wrapper.with_month(*md) }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def _make_unit_offset(sign, parts)
|
|
67
|
+
seconds = parts
|
|
68
|
+
.each_slice(2)
|
|
69
|
+
.inject(0) do |secs, (n, u)|
|
|
70
|
+
secs + _unit_to_secs(n.to_i, u)
|
|
71
|
+
end
|
|
72
|
+
sign == "-" ? -seconds : seconds
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def _method_parser(time=nil)
|
|
76
|
+
time ||= now
|
|
77
|
+
_one_method_parser.reduce(time) do |time, method, *a|
|
|
78
|
+
TimeMethods.send(method[1..], time)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def _one_method_parser
|
|
83
|
+
R.literals(*MethodLiterals, name: "method parser").flattened
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def _offset_float_seconds_parser
|
|
87
|
+
R.new([_sign, :digits, "\\.", :digits], :end, escape_strings: false, name: "float_seconds").joined(&:to_f)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def _offset_in_seconds_parser
|
|
91
|
+
_offset_float_seconds_parser.or(_offset_int_seconds_parser)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def _offset_int_seconds_parser
|
|
95
|
+
R.new([_sign, :digits], :end, escape_strings: false, name: "int_seconds").joined(&:to_i)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def _offset_parser
|
|
99
|
+
_offset_in_seconds_parser.or(_offset_with_units_parser).map(name: "adding offset") { [:offset, it] }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def _offset_with_units_parser
|
|
103
|
+
R.and(_opt_sign, _unit).flattened { |sign, *parts| _make_unit_offset(sign, parts) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def _opt_sign = R.from_regexp("[-+]?")
|
|
107
|
+
|
|
108
|
+
def _parse_methods(time, rest)
|
|
109
|
+
case _tagged_method_parser(time).parse(rest)
|
|
110
|
+
in nil
|
|
111
|
+
[:error, "unexpected suffix #{rest.inspect}"]
|
|
112
|
+
in ast, ""
|
|
113
|
+
ast
|
|
114
|
+
in _, rest
|
|
115
|
+
[:error, "unexpected suffix #{rest.inspect}"]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def _sign = "[-+]"
|
|
120
|
+
|
|
121
|
+
def _simple_time_parser
|
|
122
|
+
R.or(_date_in_century_parser, _date_in_year_parser, _date_in_month_parser)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def _tagged_method_parser(time=nil)
|
|
126
|
+
_method_parser(time).map { [:time, it] }
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def _time_parser
|
|
130
|
+
R.or(
|
|
131
|
+
_simple_time_parser,
|
|
132
|
+
_timestamp_parser,
|
|
133
|
+
_method_parser) { [:time, it] }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def _time_expr_parser
|
|
137
|
+
_offset_parser
|
|
138
|
+
.or(_time_parser)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def _timestamp_float_parser
|
|
142
|
+
R.new(:digits, [".", :digits]).joined(&:to_f)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def _timestamp_int_parser
|
|
146
|
+
R.new(:digits, &:to_i)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def _timestamp_parser
|
|
150
|
+
R.or(_timestamp_float_parser, _timestamp_int_parser) { Wrapper.from_ts(it) }
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def _unit = R.and(R.new(:digits, "([dhms])", escape_strings: false).many, R.end)
|
|
154
|
+
|
|
155
|
+
def _unit_to_secs(n, u)
|
|
156
|
+
n * SecsPerUnit.fetch(u)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def _time_method_parser
|
|
160
|
+
R.fail
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def _time_op_parser
|
|
164
|
+
R.fail
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def time_wrapper = @__time_wrapper__ ||= L43::Time::Wrapper.new
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../wrapper'
|
|
4
|
+
require_relative 'arg_parser'
|
|
5
|
+
module L43
|
|
6
|
+
module Time
|
|
7
|
+
module TimeCalc
|
|
8
|
+
module Calculate
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def _calc_time
|
|
13
|
+
case _parse_head(args.first)
|
|
14
|
+
in :error, msg
|
|
15
|
+
[:error, msg]
|
|
16
|
+
in :ok, result
|
|
17
|
+
_parse_rest(result)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def _calculate_and_print(now)
|
|
22
|
+
arg_parser = ArgParser.new(Wrapper.new)
|
|
23
|
+
case arg_parser.parse(args)
|
|
24
|
+
in :time, time
|
|
25
|
+
puts format_time!(format, time: time.time)
|
|
26
|
+
in :offset, offset
|
|
27
|
+
puts format_time!(format, time: now.time + offset)
|
|
28
|
+
in :error, msg, expr
|
|
29
|
+
putcol(_make_error(msg, expr), to: $stderr)
|
|
30
|
+
in x
|
|
31
|
+
putcol(_make_error("unexpected parse result: ", x.inspect), to: $stderr)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# if args.empty?
|
|
36
|
+
# puts format_time!(format)
|
|
37
|
+
# else
|
|
38
|
+
# case _calc_time
|
|
39
|
+
# in :ok, time
|
|
40
|
+
# puts format_time!(format, time:)
|
|
41
|
+
# in :error, message
|
|
42
|
+
# putcol(message, to: $stderr)
|
|
43
|
+
# end
|
|
44
|
+
# end
|
|
45
|
+
# end
|
|
46
|
+
|
|
47
|
+
def _current_century = (::Time.now.year / 100) * 100
|
|
48
|
+
|
|
49
|
+
def _make_error(msg, time_expr) = [
|
|
50
|
+
:red, :bold, "ERROR: ", :yellow, msg, " ", :blue, time_expr, :reset, " use flag ",
|
|
51
|
+
:cyan, :bold, ":help_time_expression|:hts", :reset, " for more info"
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
def _parse_head(time_expr)
|
|
55
|
+
result =
|
|
56
|
+
case time_expr
|
|
57
|
+
when /\A\d{2}\z/
|
|
58
|
+
Wrapper.new(::Time.now).with_day(time_expr.to_i).time
|
|
59
|
+
when /\A(\d{2})(\d{2})\z/
|
|
60
|
+
month_day = Regexp.last_match.captures.map(&:to_i)
|
|
61
|
+
Wrapper.new(::Time.now).with_month(*month_day).time
|
|
62
|
+
when /\A(\d{2})(\d{2})(\d{2})\z/
|
|
63
|
+
Regexp.last_match.captures.map(&:to_i) => y, m, d
|
|
64
|
+
::Time.new(_current_century + y, m, d)
|
|
65
|
+
when /\A\d+\z/
|
|
66
|
+
::Time.at(time_expr.to_i)
|
|
67
|
+
when /\A\d+\.\d+\z/
|
|
68
|
+
::Time.at(time_expr.to_f)
|
|
69
|
+
else
|
|
70
|
+
end
|
|
71
|
+
[:ok, result]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def _parse_rest(result)
|
|
75
|
+
rest = args.drop(1)
|
|
76
|
+
return [:ok, result] if rest.empty?
|
|
77
|
+
|
|
78
|
+
result = Wrapper.new(result)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43
|
|
4
|
+
module Time
|
|
5
|
+
module TimeCalc
|
|
6
|
+
class Cli
|
|
7
|
+
module Arguments extend self
|
|
8
|
+
BadFormat = Class.new(RuntimeError)
|
|
9
|
+
def define_arguments(arg_parser)
|
|
10
|
+
define_flags(arg_parser)
|
|
11
|
+
define_kwds(arg_parser)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
def define_flags(arg_parser)
|
|
16
|
+
arg_parser
|
|
17
|
+
.def_flag(:version, :v, desc: ["print version information to ", :green, "stdout", :reset, " and exit"])
|
|
18
|
+
.def_flag(:help_time_expression, desc: ["prints help about the syntax of ", :blue, :bold, " <time-expr> ", :reset, "syntax"])
|
|
19
|
+
.def_alias(:hts, for_flag: :help_time_expression)
|
|
20
|
+
.def_flag(:help_fmt, desc: ["prints help about the available values of the ", :cyan, :bold, "fmt:|f:", :reset, " option"])
|
|
21
|
+
.def_alias(:hfmt, for_flag: :help_fmt)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def define_kwds(arg_parser)
|
|
25
|
+
arg_parser
|
|
26
|
+
.def_kwd(:fmt, :f, desc: ["defines the format of result ", :bold, "use the ", :cyan, ":help_fmt|:hfmt", :reset, " flag for details"], default: nil)
|
|
27
|
+
.add_desc(4, "if not provided the envionment variable ", :bold, "TIME_CALC_FMT", :reset, " will be read")
|
|
28
|
+
.add_desc(4, "and if the environment variable is not set the format defaults to milliseconds in base 36 (", :dim, :cyan, "zms", :reset, ")")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43
|
|
4
|
+
module Time
|
|
5
|
+
module TimeCalc
|
|
6
|
+
class Cli
|
|
7
|
+
module Help extend self
|
|
8
|
+
include L43::Color::Output
|
|
9
|
+
|
|
10
|
+
def help_format = _output(_help_formats)
|
|
11
|
+
|
|
12
|
+
def help_time_expression = _output(_help_time_expressions)
|
|
13
|
+
|
|
14
|
+
def additional_help_information
|
|
15
|
+
[
|
|
16
|
+
["prints the result of the calculations indicated by ", *_options("options"), " to ", :blue, "stdout"],
|
|
17
|
+
["the result is a time which is formatted according to the ", *_options("fmt:|f:"), " keyword"],
|
|
18
|
+
[nil, 3, "the ", :bold, :blue, "<time-expr>", :reset, " positional arguments default to ", :bold, :magenta, "Time.now"],
|
|
19
|
+
].map { |line| [3, *line, :reset] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
def _help_formats
|
|
24
|
+
[
|
|
25
|
+
["The following values are legal for the ", :bold, :cyan, "fmt:|f:", :reset, " option"],
|
|
26
|
+
[" ", :bold, :cyan, "ds", :reset, " decimal seconds", :reset],
|
|
27
|
+
[" ", :bold, :cyan, "dms", :reset, " decimal milliseconds", :reset],
|
|
28
|
+
[" ", :bold, :cyan, "dmcs", :reset, " decimal microseconds", :reset],
|
|
29
|
+
[" ", :bold, :cyan, "dμs", :reset, " decimal microseconds", :reset],
|
|
30
|
+
[" ", :bold, :cyan, "xs", :reset, " hex seconds", :reset],
|
|
31
|
+
[" ", :bold, :cyan, "xms", :reset, " hex milliseconds", :reset],
|
|
32
|
+
[" ", :bold, :cyan, "xmcs", :reset, " hex microseconds", :reset],
|
|
33
|
+
[" ", :bold, :cyan, "xμs", :reset, " hex microseconds", :reset],
|
|
34
|
+
[" ", :bold, :cyan, "zs", :reset, " base36 seconds", :reset],
|
|
35
|
+
[" ", :bold, :cyan, "zms", :reset, " base36 milliseconds", :reset],
|
|
36
|
+
[" ", :bold, :cyan, "zmcs", :reset, " base36 microseconds", :reset],
|
|
37
|
+
[" ", :bold, :cyan, "zμs", :reset, " base36 microseconds", :reset],
|
|
38
|
+
[" ", :bold, :cyan, "date", :reset, " date", :reset],
|
|
39
|
+
[" ", :bold, :cyan, "long", :reset, " long", :reset],
|
|
40
|
+
[" ", :bold, :cyan, "iso", :reset, " iso", :reset],
|
|
41
|
+
[" ", :bold, :cyan, "time", :reset, " time", :reset],
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _help_time_expressions
|
|
47
|
+
[
|
|
48
|
+
["Time expressions are of the following syntax:"],
|
|
49
|
+
[""],
|
|
50
|
+
[" ", *_kwd("<time>"), " [", :bold, :magenta, " <op> ", *_kwd("<offset>"), " ] | [",
|
|
51
|
+
:bold, :blue, "<time>", :reset, "][.", :bold, :magenta, "<method>...",
|
|
52
|
+
:reset, "] | ", *_kwd("<offset>")
|
|
53
|
+
],
|
|
54
|
+
[""],
|
|
55
|
+
[" ", :bold, :blue, "<time>", :reset, ":"],
|
|
56
|
+
[" ", "if not directed by any option ", *_kwd("<time>"), " is parsed heuristically"],
|
|
57
|
+
[" 6 digits to a date in the 21st century"],
|
|
58
|
+
[" 4 digits to a month and day in the current year"],
|
|
59
|
+
[" 2 digits to a day in the current month"],
|
|
60
|
+
[" an unsigned number, interpreted as seconds from epoch "],
|
|
61
|
+
[:bold, :yellow, " N.B.: ", :reset, "must contain a decimal point if the number format conflicts with the formats above"],
|
|
62
|
+
[""],
|
|
63
|
+
[" ", :bold, :blue, "<offset>", :reset, ":"],
|
|
64
|
+
[" a signed number, interpreted as offsets in seconds"],
|
|
65
|
+
[" a unit offset, which is a sequence of ", :blue, :bold, "<int><unit>", :reset, " where ", :blue, :bold, "<unit>",
|
|
66
|
+
:reset, " is one of: ", :green, "dhms"],
|
|
67
|
+
[""],
|
|
68
|
+
[" ", :bold, :magenta, "<method>", :reset, ":"],
|
|
69
|
+
[" [", :bold, :blue, "<time>", :reset, "]", :bold, :green, ".midnight", :reset, " time 0h0m0s of ", :bold, :blue, "<time>.", :reset],
|
|
70
|
+
[" [", :bold, :blue, "<time>", :reset, "]", :bold, :green, ".tomorrow", :reset, " 1 day after ", :bold, :blue, "<time>.", :reset],
|
|
71
|
+
[" [", :bold, :blue, "<time>", :reset, "]", :bold, :green, ".yesterday", :reset, " 1 day before ", :bold, :blue, "<time>.", :reset],
|
|
72
|
+
]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def _kwd(*kwds) = [:bold, :blue, *kwds, :reset].freeze
|
|
76
|
+
|
|
77
|
+
def _options(name) = [:cyan, :bold, name, :reset].freeze
|
|
78
|
+
|
|
79
|
+
def _output(lines)
|
|
80
|
+
lines.each do |line|
|
|
81
|
+
putcol(line, to: $stderr)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'l43/xargs'
|
|
4
|
+
require 'l43/rgx/all'
|
|
5
|
+
require 'l43/rgx/result'
|
|
6
|
+
|
|
7
|
+
require_relative 'cli/arguments'
|
|
8
|
+
require_relative 'cli/help'
|
|
9
|
+
require_relative 'calculate'
|
|
10
|
+
require_relative 'arg_parser'
|
|
11
|
+
require_relative '../format_time'
|
|
12
|
+
require_relative '../wrapper'
|
|
13
|
+
module L43
|
|
14
|
+
module Time
|
|
15
|
+
module TimeCalc
|
|
16
|
+
class Cli
|
|
17
|
+
include Calculate
|
|
18
|
+
include Color::Output
|
|
19
|
+
include FormatTime
|
|
20
|
+
|
|
21
|
+
attr_reader :arg_parser, :args,
|
|
22
|
+
:format,
|
|
23
|
+
:kwds
|
|
24
|
+
|
|
25
|
+
def run(argv)
|
|
26
|
+
result = arg_parser.parse(argv)
|
|
27
|
+
case result
|
|
28
|
+
in true, args, [], kwds
|
|
29
|
+
@args = args
|
|
30
|
+
@kwds = kwds
|
|
31
|
+
_run
|
|
32
|
+
in false, _, errors, _
|
|
33
|
+
errors.each do |error|
|
|
34
|
+
putcol(error, to: $stderr)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
def initialize
|
|
41
|
+
@arg_parser = Xargs.new(program_name: "time_calc", autohelp: true, no_posix_short: true, usage: [:options, "<time-expr>..."])
|
|
42
|
+
Arguments.define_arguments(arg_parser)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def _checks!
|
|
46
|
+
legal_fmts = FormatTime::LegalFormats.keys
|
|
47
|
+
@format = (fmt || ENV["TIME_CALC_FMT"] || "zms").to_sym
|
|
48
|
+
return true if legal_fmts.member?(format)
|
|
49
|
+
putcol(
|
|
50
|
+
[:bold, :red, "ERROR: ", :reset, :yellow, "#{format.inspect} is not a legal format. Use the script with ", :bold, :green, ":help_fmt|:hfmt"],
|
|
51
|
+
to: $stderr)
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def _run
|
|
56
|
+
arg_parser.forward_to_kwds!(self)
|
|
57
|
+
if help
|
|
58
|
+
arg_parser.print_help([nil, *Help.additional_help_information])
|
|
59
|
+
elsif version
|
|
60
|
+
require_relative '../version'
|
|
61
|
+
putcol([:bold, :white, arg_parser.program_name, :green, " v", L43::Time::VERSION], to: $stderr)
|
|
62
|
+
elsif help_time_expression
|
|
63
|
+
Help.help_time_expression
|
|
64
|
+
elsif help_fmt
|
|
65
|
+
Help.help_format
|
|
66
|
+
else
|
|
67
|
+
_calculate_and_print(Wrapper.new) if _checks!
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../wrapper'
|
|
4
|
+
module L43
|
|
5
|
+
module Time
|
|
6
|
+
module TimeCalc
|
|
7
|
+
module TimeMethods extend self
|
|
8
|
+
def midnight(time)
|
|
9
|
+
time.with_time
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def tomorrow(time)
|
|
13
|
+
time + 86400
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def yesterday(time)
|
|
18
|
+
time - 86400
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
data/lib/l43/time/version.rb
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module L43
|
|
4
|
+
module Time
|
|
5
|
+
class Wrapper
|
|
6
|
+
attr_reader :time
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def from_ts(ts) = new(::Time.at(ts))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def deconstruct(*)
|
|
13
|
+
[
|
|
14
|
+
time.year, time.month, time.day, time.hour, time.min, time.sec, seconds_since_epoch, microseconds
|
|
15
|
+
]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ==(other)
|
|
19
|
+
return false unless self.class === other
|
|
20
|
+
other.time == time
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def +(ts)
|
|
24
|
+
self.class.from_ts(time + ts)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def -(ts)
|
|
28
|
+
self.class.from_ts(time - ts)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def to_f = time.to_f
|
|
32
|
+
|
|
33
|
+
def to_i = time.to_i
|
|
34
|
+
|
|
35
|
+
def microseconds = @__microseconds__ ||= ((time.to_f - seconds_since_epoch) * 1_000_000).to_i
|
|
36
|
+
def seconds_since_epoch = @__seconds_since_epoch__ ||= time.to_i
|
|
37
|
+
|
|
38
|
+
def with_day(day, hour=0, min=0, sec=0)
|
|
39
|
+
self => [y, m, *]
|
|
40
|
+
self.class.new(y, m, day, hour, min, sec)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def with_month(month, day=1, hour=0, min=0, sec=0)
|
|
44
|
+
self.class.new(time.year, month, day, hour, min, sec)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def with_time(hour=0, min=0, sec=0)
|
|
48
|
+
self => [year, month, day, *]
|
|
49
|
+
self.class.new(year, month, day, hour, min, sec)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def with_year(year, month, day=1, hour=0, min=0, sec=0)
|
|
53
|
+
year = Integer(year)
|
|
54
|
+
year += 2000 if year < 1000
|
|
55
|
+
self.class.new(year, month, day, hour, min, sec)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
def initialize(time=::Time.now, *parts)
|
|
60
|
+
case time
|
|
61
|
+
when ::Time
|
|
62
|
+
raise ArgumentError, "parts not allowed if first part is an instance of Time" unless parts.empty?
|
|
63
|
+
@time = time
|
|
64
|
+
else
|
|
65
|
+
@time = ::Time.new(time, *parts)
|
|
66
|
+
end
|
|
67
|
+
@time.freeze
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
metadata
CHANGED
|
@@ -1,30 +1,44 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: l43_time
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Dober
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-09-23 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name:
|
|
13
|
+
name: l43_color
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.3.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 0.
|
|
25
|
+
version: 0.3.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: l43_core
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.2.7
|
|
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.7
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: l43_open_object
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
29
43
|
requirements:
|
|
30
44
|
- - "~>"
|
|
@@ -38,33 +52,33 @@ dependencies:
|
|
|
38
52
|
- !ruby/object:Gem::Version
|
|
39
53
|
version: 0.3.0
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
|
-
name:
|
|
55
|
+
name: l43_xargs
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
43
57
|
requirements:
|
|
44
58
|
- - "~>"
|
|
45
59
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: 0.
|
|
60
|
+
version: 0.1.4
|
|
47
61
|
type: :runtime
|
|
48
62
|
prerelease: false
|
|
49
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
64
|
requirements:
|
|
51
65
|
- - "~>"
|
|
52
66
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: 0.
|
|
67
|
+
version: 0.1.4
|
|
54
68
|
- !ruby/object:Gem::Dependency
|
|
55
|
-
name:
|
|
69
|
+
name: l43_rgx
|
|
56
70
|
requirement: !ruby/object:Gem::Requirement
|
|
57
71
|
requirements:
|
|
58
72
|
- - "~>"
|
|
59
73
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 0.
|
|
74
|
+
version: 0.2.0
|
|
61
75
|
type: :runtime
|
|
62
76
|
prerelease: false
|
|
63
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
78
|
requirements:
|
|
65
79
|
- - "~>"
|
|
66
80
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 0.
|
|
81
|
+
version: 0.2.0
|
|
68
82
|
description: 'Time related tools
|
|
69
83
|
|
|
70
84
|
'
|
|
@@ -78,10 +92,17 @@ files:
|
|
|
78
92
|
- lib/l43/time.rb
|
|
79
93
|
- lib/l43/time/consts.rb
|
|
80
94
|
- lib/l43/time/delta.rb
|
|
95
|
+
- lib/l43/time/enumerable_extension.rb
|
|
81
96
|
- lib/l43/time/errors.rb
|
|
82
97
|
- lib/l43/time/format_time.rb
|
|
83
98
|
- lib/l43/time/parser.rb
|
|
84
99
|
- lib/l43/time/range.rb
|
|
100
|
+
- lib/l43/time/time_calc/arg_parser.rb
|
|
101
|
+
- lib/l43/time/time_calc/calculate.rb
|
|
102
|
+
- lib/l43/time/time_calc/cli.rb
|
|
103
|
+
- lib/l43/time/time_calc/cli/arguments.rb
|
|
104
|
+
- lib/l43/time/time_calc/cli/help.rb
|
|
105
|
+
- lib/l43/time/time_calc/time_methods.rb
|
|
85
106
|
- lib/l43/time/time_range.rb
|
|
86
107
|
- lib/l43/time/to_time.rb
|
|
87
108
|
- lib/l43/time/tools/format_ts.rb
|
|
@@ -89,6 +110,7 @@ files:
|
|
|
89
110
|
- lib/l43/time/tools/scanner.rb
|
|
90
111
|
- lib/l43/time/ts.rb
|
|
91
112
|
- lib/l43/time/version.rb
|
|
113
|
+
- lib/l43/time/wrapper.rb
|
|
92
114
|
homepage: https://codeberg.org/lab419/l43_time
|
|
93
115
|
licenses:
|
|
94
116
|
- AGPL-3.0-or-later
|
|
@@ -107,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
107
129
|
- !ruby/object:Gem::Version
|
|
108
130
|
version: '0'
|
|
109
131
|
requirements: []
|
|
110
|
-
rubygems_version: 4.0.
|
|
132
|
+
rubygems_version: 4.0.19
|
|
111
133
|
specification_version: 4
|
|
112
134
|
summary: Time related tools
|
|
113
135
|
test_files: []
|