hizuke 0.0.1 → 0.0.3
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/CHANGELOG.md +39 -0
- data/Gemfile.lock +1 -1
- data/README.md +48 -1
- data/lib/hizuke/parser.rb +367 -5
- data/lib/hizuke/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21dc88226bf08c961ed63958ab1dc38ca4a9c324ed2259fbfcd5cda208a43247
|
4
|
+
data.tar.gz: 9bb2da3217a6b090b0036e4804d4860d156dd6d996aeff8d1b2705f43c146eda
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c8dc6d727568a43564b707858469fa75639fc93b75c49fc299f0de6a08ac88ce316a3aa27e7efbf3d35d7a26e795ba3881a9d3472628749a75b1e4213cde239
|
7
|
+
data.tar.gz: 46bb31b32c3e40b54973757b5e954dbd91841fc7cc09febf50d3f704e6cb312dca3e0f472ae91e2cd876fcdba7aa510fb83a8c5d813e9a524532a1dc2b6049f5
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,45 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
+
## [0.0.3] - 2023-05-09
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Support for quarterly date references:
|
12
|
+
- "next quarter" / "nextquarter" - returns the first day of the next quarter
|
13
|
+
- "last quarter" / "lastquarter" - returns the first day of the last quarter
|
14
|
+
- Support for relative day references:
|
15
|
+
- "day after tomorrow" / "dayaftertomorrow"
|
16
|
+
- "day before yesterday" / "daybeforeyesterday"
|
17
|
+
- Support for dynamic time spans:
|
18
|
+
- "in X days", "X days ago"
|
19
|
+
- "in X weeks", "X weeks ago"
|
20
|
+
- "in X months", "X months ago"
|
21
|
+
- "in X years", "X years ago"
|
22
|
+
- Support for specific days of the week:
|
23
|
+
- "this Monday", "this Tuesday", etc.
|
24
|
+
- "next Monday", "next Tuesday", etc.
|
25
|
+
- "last Monday", "last Tuesday", etc.
|
26
|
+
- Support for additional time references:
|
27
|
+
- "last week" / "lastweek"
|
28
|
+
- "last month" / "lastmonth"
|
29
|
+
- "last year" / "lastyear"
|
30
|
+
- "end of week" / "endofweek"
|
31
|
+
- "end of month" / "endofmonth"
|
32
|
+
- "end of year" / "endofyear"
|
33
|
+
- "mid week" / "midweek"
|
34
|
+
- "mid month" / "midmonth"
|
35
|
+
- Updated documentation to reflect all new functionality
|
36
|
+
|
37
|
+
## [0.0.2] - 2025-04-23
|
38
|
+
|
39
|
+
### Added
|
40
|
+
- Support for additional date keywords:
|
41
|
+
- "next week" / "nextweek"
|
42
|
+
- "next month" / "nextmonth"
|
43
|
+
- "next year" / "nextyear"
|
44
|
+
- "this weekend" / "thisweekend"
|
45
|
+
- Enhanced parsing to support compound date expressions with spaces
|
46
|
+
|
8
47
|
## [0.0.1] - 2025-04-12
|
9
48
|
|
10
49
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -41,9 +41,29 @@ puts result.date # => <Date: 2023-03-31> (represents today's date)
|
|
41
41
|
result = Hizuke.parse("call mom yesterday")
|
42
42
|
puts result.text # => "call mom"
|
43
43
|
puts result.date # => <Date: 2023-03-30> (represents yesterday's date)
|
44
|
+
|
45
|
+
# Parse text with next week's date
|
46
|
+
result = Hizuke.parse("team meeting next week")
|
47
|
+
puts result.text # => "team meeting"
|
48
|
+
puts result.date # => <Date: 2023-04-04> (represents the next Monday)
|
49
|
+
|
50
|
+
# Parse text with next month's date
|
51
|
+
result = Hizuke.parse("vacation next month")
|
52
|
+
puts result.text # => "vacation"
|
53
|
+
puts result.date # => <Date: 2023-05-01> (represents the first day of the next month)
|
54
|
+
|
55
|
+
# Parse text with next year's date
|
56
|
+
result = Hizuke.parse("conference next year")
|
57
|
+
puts result.text # => "conference"
|
58
|
+
puts result.date # => <Date: 2024-01-01> (represents the first day of the next year)
|
59
|
+
|
60
|
+
# Parse text with this weekend's date
|
61
|
+
result = Hizuke.parse("hiking this weekend")
|
62
|
+
puts result.text # => "hiking"
|
63
|
+
puts result.date # => <Date: 2023-04-01> (represents the next Saturday)
|
44
64
|
```
|
45
65
|
|
46
|
-
The parser is case-insensitive and can handle date references located anywhere in the text.
|
66
|
+
The parser is case-insensitive and can handle date references located anywhere in the text. It also supports date references with or without spaces (e.g., "nextweek" or "next week").
|
47
67
|
|
48
68
|
## Supported Date Keywords
|
49
69
|
|
@@ -52,6 +72,33 @@ Currently, the following English date keywords are supported:
|
|
52
72
|
- `yesterday` - returns yesterday's date
|
53
73
|
- `today` - returns today's date
|
54
74
|
- `tomorrow` - returns tomorrow's date
|
75
|
+
- `day after tomorrow` / `dayaftertomorrow` - returns the date two days from today
|
76
|
+
- `day before yesterday` / `daybeforeyesterday` - returns the date two days before today
|
77
|
+
- `in X days` - returns the date X days from today (where X is any number)
|
78
|
+
- `X days ago` - returns the date X days before today (where X is any number)
|
79
|
+
- `in X weeks` - returns the date X weeks from today (where X is any number)
|
80
|
+
- `X weeks ago` - returns the date X weeks before today (where X is any number)
|
81
|
+
- `in X months` - returns the date X months from today (where X is any number)
|
82
|
+
- `X months ago` - returns the date X months before today (where X is any number)
|
83
|
+
- `in X years` - returns the date X years from today (where X is any number)
|
84
|
+
- `X years ago` - returns the date X years before today (where X is any number)
|
85
|
+
- `this Monday`, `this Tuesday`, etc. - returns the date of the specified day in the current week
|
86
|
+
- `next Monday`, `next Tuesday`, etc. - returns the date of the specified day in the next week
|
87
|
+
- `last Monday`, `last Tuesday`, etc. - returns the date of the specified day in the previous week
|
88
|
+
- `next week` / `nextweek` - returns the date of the next Monday
|
89
|
+
- `last week` / `lastweek` - returns the date of the previous Monday
|
90
|
+
- `next month` / `nextmonth` - returns the first day of the next month
|
91
|
+
- `last month` / `lastmonth` - returns the first day of the previous month
|
92
|
+
- `next year` / `nextyear` - returns the first day of the next year
|
93
|
+
- `last year` / `lastyear` - returns the first day of the previous year
|
94
|
+
- `this weekend` / `thisweekend` - returns the date of the upcoming Saturday (or today if it's already the weekend)
|
95
|
+
- `end of week` / `endofweek` - returns the date of the upcoming Sunday (end of week)
|
96
|
+
- `end of month` / `endofmonth` - returns the date of the last day of the current month
|
97
|
+
- `end of year` / `endofyear` - returns the date of December 31st of the current year
|
98
|
+
- `mid week` / `midweek` - returns the date of Wednesday of the current week
|
99
|
+
- `mid month` / `midmonth` - returns the date of the 15th day of the current month
|
100
|
+
- `next quarter` / `nextquarter` - returns the first day of the next quarter
|
101
|
+
- `last quarter` / `lastquarter` - returns the first day of the last quarter
|
55
102
|
|
56
103
|
## Development
|
57
104
|
|
data/lib/hizuke/parser.rb
CHANGED
@@ -15,13 +15,71 @@ module Hizuke
|
|
15
15
|
|
16
16
|
# Parser class responsible for extracting dates from text
|
17
17
|
class Parser
|
18
|
+
# Mapping of day names to their wday values (0-6, Sunday is 0)
|
19
|
+
DAYS_OF_WEEK = {
|
20
|
+
"monday" => 1,
|
21
|
+
"tuesday" => 2,
|
22
|
+
"wednesday" => 3,
|
23
|
+
"thursday" => 4,
|
24
|
+
"friday" => 5,
|
25
|
+
"saturday" => 6,
|
26
|
+
"sunday" => 0
|
27
|
+
}.freeze
|
28
|
+
|
18
29
|
# Date keywords mapping
|
19
30
|
DATE_KEYWORDS = {
|
20
31
|
"yesterday" => -1,
|
21
32
|
"today" => 0,
|
22
|
-
"tomorrow" => 1
|
33
|
+
"tomorrow" => 1,
|
34
|
+
"dayaftertomorrow" => 2,
|
35
|
+
"day after tomorrow" => 2,
|
36
|
+
"daybeforeyesterday" => -2,
|
37
|
+
"day before yesterday" => -2,
|
38
|
+
"nextweek" => :next_week,
|
39
|
+
"next week" => :next_week,
|
40
|
+
"lastweek" => :last_week,
|
41
|
+
"last week" => :last_week,
|
42
|
+
"nextmonth" => :next_month,
|
43
|
+
"next month" => :next_month,
|
44
|
+
"lastmonth" => :last_month,
|
45
|
+
"last month" => :last_month,
|
46
|
+
"nextyear" => :next_year,
|
47
|
+
"next year" => :next_year,
|
48
|
+
"lastyear" => :last_year,
|
49
|
+
"last year" => :last_year,
|
50
|
+
"nextquarter" => :next_quarter,
|
51
|
+
"next quarter" => :next_quarter,
|
52
|
+
"lastquarter" => :last_quarter,
|
53
|
+
"last quarter" => :last_quarter,
|
54
|
+
"thisweekend" => :this_weekend,
|
55
|
+
"this weekend" => :this_weekend,
|
56
|
+
"endofweek" => :end_of_week,
|
57
|
+
"end of week" => :end_of_week,
|
58
|
+
"endofmonth" => :end_of_month,
|
59
|
+
"end of month" => :end_of_month,
|
60
|
+
"endofyear" => :end_of_year,
|
61
|
+
"end of year" => :end_of_year,
|
62
|
+
"midweek" => :mid_week,
|
63
|
+
"mid week" => :mid_week,
|
64
|
+
"midmonth" => :mid_month,
|
65
|
+
"mid month" => :mid_month
|
23
66
|
}.freeze
|
24
67
|
|
68
|
+
# Regex patterns for dynamic date references
|
69
|
+
IN_X_DAYS_PATTERN = /in (\d+) days?/i
|
70
|
+
X_DAYS_AGO_PATTERN = /(\d+) days? ago/i
|
71
|
+
IN_X_WEEKS_PATTERN = /in (\d+) weeks?/i
|
72
|
+
X_WEEKS_AGO_PATTERN = /(\d+) weeks? ago/i
|
73
|
+
IN_X_MONTHS_PATTERN = /in (\d+) months?/i
|
74
|
+
X_MONTHS_AGO_PATTERN = /(\d+) months? ago/i
|
75
|
+
IN_X_YEARS_PATTERN = /in (\d+) years?/i
|
76
|
+
X_YEARS_AGO_PATTERN = /(\d+) years? ago/i
|
77
|
+
|
78
|
+
# Regex patterns for specific days of the week
|
79
|
+
THIS_DAY_PATTERN = /this (monday|tuesday|wednesday|thursday|friday|saturday|sunday)/i
|
80
|
+
NEXT_DAY_PATTERN = /next (monday|tuesday|wednesday|thursday|friday|saturday|sunday)/i
|
81
|
+
LAST_DAY_PATTERN = /last (monday|tuesday|wednesday|thursday|friday|saturday|sunday)/i
|
82
|
+
|
25
83
|
# Parse text containing time references and extract both
|
26
84
|
# the clean text and the date.
|
27
85
|
#
|
@@ -41,18 +99,54 @@ module Hizuke
|
|
41
99
|
# Check if text is nil or empty
|
42
100
|
raise ParseError, "Input text cannot be nil or empty" if text.nil? || text.empty?
|
43
101
|
|
44
|
-
#
|
102
|
+
# Check for dynamic patterns first (in X days, X days ago)
|
103
|
+
result = check_dynamic_patterns(text)
|
104
|
+
return result if result
|
105
|
+
|
106
|
+
# Check for day of week patterns (this Monday, next Tuesday, etc.)
|
107
|
+
result = check_day_of_week_patterns(text)
|
108
|
+
return result if result
|
109
|
+
|
110
|
+
# Try to find compound date expressions (like "next week")
|
111
|
+
compound_matches = {}
|
112
|
+
|
113
|
+
DATE_KEYWORDS.keys.select { |k| k.include?(" ") }.each do |compound_key|
|
114
|
+
if text.downcase.include?(compound_key)
|
115
|
+
start_idx = text.downcase.index(compound_key)
|
116
|
+
end_idx = start_idx + compound_key.length - 1
|
117
|
+
compound_matches[compound_key] = [start_idx, end_idx]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# If we found compound matches, handle them specially
|
122
|
+
unless compound_matches.empty?
|
123
|
+
# Use the first match (in case there are multiple)
|
124
|
+
match_key, indices = compound_matches.min_by { |_, v| v[0] }
|
125
|
+
|
126
|
+
# Calculate date based on the keyword
|
127
|
+
date_value = DATE_KEYWORDS[match_key]
|
128
|
+
date = calculate_date(date_value)
|
129
|
+
|
130
|
+
# Remove the date expression from the text
|
131
|
+
clean_text = text.dup
|
132
|
+
clean_text.slice!(indices[0]..indices[1])
|
133
|
+
clean_text = clean_text.strip
|
134
|
+
|
135
|
+
return Result.new(clean_text, date)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Split the text into words (for single-word date references)
|
45
139
|
words = text.split
|
46
140
|
|
47
141
|
# Find the first date keyword
|
48
142
|
date_word_index = nil
|
49
|
-
|
143
|
+
date_value = nil
|
50
144
|
|
51
145
|
words.each_with_index do |word, index|
|
52
146
|
clean_word = word.downcase.gsub(/[^a-z]/, '')
|
53
147
|
if DATE_KEYWORDS.key?(clean_word)
|
54
148
|
date_word_index = index
|
55
|
-
|
149
|
+
date_value = DATE_KEYWORDS[clean_word]
|
56
150
|
break
|
57
151
|
end
|
58
152
|
end
|
@@ -62,7 +156,7 @@ module Hizuke
|
|
62
156
|
end
|
63
157
|
|
64
158
|
# Calculate the date based on the keyword
|
65
|
-
date =
|
159
|
+
date = calculate_date(date_value)
|
66
160
|
|
67
161
|
# Create the clean text by removing the date keyword
|
68
162
|
clean_words = words.dup
|
@@ -71,5 +165,273 @@ module Hizuke
|
|
71
165
|
|
72
166
|
Result.new(clean_text, date)
|
73
167
|
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
# Check for day of week patterns (this Monday, next Tuesday, last Friday, etc.)
|
172
|
+
def check_day_of_week_patterns(text)
|
173
|
+
# Check for "this [day]" pattern
|
174
|
+
if (match = text.match(THIS_DAY_PATTERN))
|
175
|
+
day_name = match[1].downcase
|
176
|
+
day_value = DAYS_OF_WEEK[day_name]
|
177
|
+
date = calculate_this_day(day_value)
|
178
|
+
clean_text = text.gsub(match[0], "").strip
|
179
|
+
return Result.new(clean_text, date)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Check for "next [day]" pattern
|
183
|
+
if (match = text.match(NEXT_DAY_PATTERN))
|
184
|
+
day_name = match[1].downcase
|
185
|
+
day_value = DAYS_OF_WEEK[day_name]
|
186
|
+
date = calculate_next_day(day_value)
|
187
|
+
clean_text = text.gsub(match[0], "").strip
|
188
|
+
return Result.new(clean_text, date)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Check for "last [day]" pattern
|
192
|
+
if (match = text.match(LAST_DAY_PATTERN))
|
193
|
+
day_name = match[1].downcase
|
194
|
+
day_value = DAYS_OF_WEEK[day_name]
|
195
|
+
date = calculate_last_day(day_value)
|
196
|
+
clean_text = text.gsub(match[0], "").strip
|
197
|
+
return Result.new(clean_text, date)
|
198
|
+
end
|
199
|
+
|
200
|
+
nil
|
201
|
+
end
|
202
|
+
|
203
|
+
# Check for dynamic date patterns like "in X days" or "X days ago"
|
204
|
+
def check_dynamic_patterns(text)
|
205
|
+
# Check for "in X days" pattern
|
206
|
+
if (match = text.match(IN_X_DAYS_PATTERN))
|
207
|
+
days = match[1].to_i
|
208
|
+
date = Date.today + days
|
209
|
+
clean_text = text.gsub(match[0], "").strip
|
210
|
+
return Result.new(clean_text, date)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Check for "X days ago" pattern
|
214
|
+
if (match = text.match(X_DAYS_AGO_PATTERN))
|
215
|
+
days = match[1].to_i
|
216
|
+
date = Date.today - days
|
217
|
+
clean_text = text.gsub(match[0], "").strip
|
218
|
+
return Result.new(clean_text, date)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Check for "in X weeks" pattern
|
222
|
+
if (match = text.match(IN_X_WEEKS_PATTERN))
|
223
|
+
weeks = match[1].to_i
|
224
|
+
date = Date.today + (weeks * 7)
|
225
|
+
clean_text = text.gsub(match[0], "").strip
|
226
|
+
return Result.new(clean_text, date)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Check for "X weeks ago" pattern
|
230
|
+
if (match = text.match(X_WEEKS_AGO_PATTERN))
|
231
|
+
weeks = match[1].to_i
|
232
|
+
date = Date.today - (weeks * 7)
|
233
|
+
clean_text = text.gsub(match[0], "").strip
|
234
|
+
return Result.new(clean_text, date)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Check for "in X months" pattern
|
238
|
+
if (match = text.match(IN_X_MONTHS_PATTERN))
|
239
|
+
months = match[1].to_i
|
240
|
+
date = Date.today >> months
|
241
|
+
clean_text = text.gsub(match[0], "").strip
|
242
|
+
return Result.new(clean_text, date)
|
243
|
+
end
|
244
|
+
|
245
|
+
# Check for "X months ago" pattern
|
246
|
+
if (match = text.match(X_MONTHS_AGO_PATTERN))
|
247
|
+
months = match[1].to_i
|
248
|
+
date = Date.today << months
|
249
|
+
clean_text = text.gsub(match[0], "").strip
|
250
|
+
return Result.new(clean_text, date)
|
251
|
+
end
|
252
|
+
|
253
|
+
# Check for "in X years" pattern
|
254
|
+
if (match = text.match(IN_X_YEARS_PATTERN))
|
255
|
+
years = match[1].to_i
|
256
|
+
date = Date.new(Date.today.year + years, Date.today.month, Date.today.day)
|
257
|
+
clean_text = text.gsub(match[0], "").strip
|
258
|
+
return Result.new(clean_text, date)
|
259
|
+
end
|
260
|
+
|
261
|
+
# Check for "X years ago" pattern
|
262
|
+
if (match = text.match(X_YEARS_AGO_PATTERN))
|
263
|
+
years = match[1].to_i
|
264
|
+
date = Date.new(Date.today.year - years, Date.today.month, Date.today.day)
|
265
|
+
clean_text = text.gsub(match[0], "").strip
|
266
|
+
return Result.new(clean_text, date)
|
267
|
+
end
|
268
|
+
|
269
|
+
nil
|
270
|
+
end
|
271
|
+
|
272
|
+
# Calculate date for "this [day]" - the current/upcoming day in this week
|
273
|
+
def calculate_this_day(target_wday)
|
274
|
+
today = Date.today
|
275
|
+
today_wday = today.wday
|
276
|
+
|
277
|
+
# Calculate days until the target day in this week
|
278
|
+
days_diff = (target_wday - today_wday) % 7
|
279
|
+
|
280
|
+
# If it's the same day, return today's date
|
281
|
+
if days_diff == 0
|
282
|
+
return today
|
283
|
+
end
|
284
|
+
|
285
|
+
# Return the date of the next occurrence in this week
|
286
|
+
today + days_diff
|
287
|
+
end
|
288
|
+
|
289
|
+
# Calculate date for "next [day]" - the day in next week
|
290
|
+
def calculate_next_day(target_wday)
|
291
|
+
today = Date.today
|
292
|
+
today_wday = today.wday
|
293
|
+
|
294
|
+
# Calculate days until the next occurrence
|
295
|
+
days_until_target = (target_wday - today_wday) % 7
|
296
|
+
|
297
|
+
# If today is the target day or the target day is earlier in the week,
|
298
|
+
# we want the day next week, so add 7 days
|
299
|
+
if days_until_target == 0 || target_wday < today_wday
|
300
|
+
days_until_target += 7
|
301
|
+
end
|
302
|
+
|
303
|
+
today + days_until_target
|
304
|
+
end
|
305
|
+
|
306
|
+
# Calculate date for "last [day]" - the day in previous week
|
307
|
+
def calculate_last_day(target_wday)
|
308
|
+
today = Date.today
|
309
|
+
today_wday = today.wday
|
310
|
+
|
311
|
+
# Calculate days since the last occurrence
|
312
|
+
days_since_target = (today_wday - target_wday) % 7
|
313
|
+
|
314
|
+
# If today is the target day or the target day is later in the week,
|
315
|
+
# we want the day last week, so add 7 days
|
316
|
+
if days_since_target == 0 || target_wday > today_wday
|
317
|
+
days_since_target += 7
|
318
|
+
end
|
319
|
+
|
320
|
+
today - days_since_target
|
321
|
+
end
|
322
|
+
|
323
|
+
# Calculate the date based on the keyword value
|
324
|
+
def calculate_date(date_value)
|
325
|
+
if date_value.is_a?(Integer)
|
326
|
+
Date.today + date_value
|
327
|
+
elsif date_value == :next_week
|
328
|
+
# Find next Monday
|
329
|
+
days_until_monday = (1 - Date.today.wday) % 7
|
330
|
+
# If today is Monday, we want next Monday, not today
|
331
|
+
days_until_monday = 7 if days_until_monday == 0
|
332
|
+
Date.today + days_until_monday
|
333
|
+
elsif date_value == :last_week
|
334
|
+
# Find last Monday
|
335
|
+
days_since_monday = (Date.today.wday - 1) % 7
|
336
|
+
# If today is Monday, we want last Monday, not today
|
337
|
+
days_since_monday = 7 if days_since_monday == 0
|
338
|
+
Date.today - days_since_monday - 7
|
339
|
+
elsif date_value == :next_month
|
340
|
+
# Return the first day of the next month
|
341
|
+
next_month = Date.today >> 1
|
342
|
+
Date.new(next_month.year, next_month.month, 1)
|
343
|
+
elsif date_value == :last_month
|
344
|
+
# Return the first day of the previous month
|
345
|
+
prev_month = Date.today << 1
|
346
|
+
Date.new(prev_month.year, prev_month.month, 1)
|
347
|
+
elsif date_value == :next_year
|
348
|
+
# Return the first day of the next year
|
349
|
+
next_year = Date.today.year + 1
|
350
|
+
Date.new(next_year, 1, 1)
|
351
|
+
elsif date_value == :last_year
|
352
|
+
# Return the first day of the last year
|
353
|
+
last_year = Date.today.year - 1
|
354
|
+
Date.new(last_year, 1, 1)
|
355
|
+
elsif date_value == :next_quarter
|
356
|
+
# Return the first day of the next quarter
|
357
|
+
today = Date.today
|
358
|
+
current_month = today.month
|
359
|
+
|
360
|
+
# Determine the start month of the next quarter
|
361
|
+
next_quarter_month = case
|
362
|
+
when current_month <= 3
|
363
|
+
4 # Q2 starts in April
|
364
|
+
when current_month <= 6
|
365
|
+
7 # Q3 starts in July
|
366
|
+
when current_month <= 9
|
367
|
+
10 # Q4 starts in October
|
368
|
+
else
|
369
|
+
1 # Q1 of next year starts in January
|
370
|
+
end
|
371
|
+
|
372
|
+
# If the next quarter is in the next year, increment the year
|
373
|
+
next_quarter_year = today.year
|
374
|
+
next_quarter_year += 1 if current_month > 9
|
375
|
+
|
376
|
+
Date.new(next_quarter_year, next_quarter_month, 1)
|
377
|
+
elsif date_value == :last_quarter
|
378
|
+
# Return the first day of the last quarter
|
379
|
+
today = Date.today
|
380
|
+
current_month = today.month
|
381
|
+
|
382
|
+
# Determine the start month of the last quarter
|
383
|
+
last_quarter_month = case
|
384
|
+
when current_month <= 3
|
385
|
+
10 # Q4 of last year starts in October
|
386
|
+
when current_month <= 6
|
387
|
+
1 # Q1 starts in January
|
388
|
+
when current_month <= 9
|
389
|
+
4 # Q2 starts in April
|
390
|
+
else
|
391
|
+
7 # Q3 starts in July
|
392
|
+
end
|
393
|
+
|
394
|
+
# If the last quarter is in the previous year, decrement the year
|
395
|
+
last_quarter_year = today.year
|
396
|
+
last_quarter_year -= 1 if current_month <= 3
|
397
|
+
|
398
|
+
Date.new(last_quarter_year, last_quarter_month, 1)
|
399
|
+
elsif date_value == :this_weekend
|
400
|
+
# Calculate days until Saturday
|
401
|
+
days_until_saturday = (6 - Date.today.wday) % 7
|
402
|
+
# If today is Saturday or Sunday, we're already on the weekend
|
403
|
+
days_until_saturday = 0 if days_until_saturday == 0 || days_until_saturday == 6
|
404
|
+
Date.today + days_until_saturday
|
405
|
+
elsif date_value == :end_of_week
|
406
|
+
# Calculate days until Sunday (end of week)
|
407
|
+
days_until_sunday = (0 - Date.today.wday) % 7
|
408
|
+
# If today is Sunday, we're already at the end of the week
|
409
|
+
days_until_sunday = 0 if days_until_sunday == 0
|
410
|
+
Date.today + days_until_sunday
|
411
|
+
elsif date_value == :end_of_month
|
412
|
+
# Return the last day of the current month
|
413
|
+
# Get the first day of next month
|
414
|
+
next_month = Date.today >> 1
|
415
|
+
first_day_next_month = Date.new(next_month.year, next_month.month, 1)
|
416
|
+
# Subtract one day to get the last day of current month
|
417
|
+
first_day_next_month - 1
|
418
|
+
elsif date_value == :end_of_year
|
419
|
+
# Return the last day of the current year (December 31)
|
420
|
+
Date.new(Date.today.year, 12, 31)
|
421
|
+
elsif date_value == :mid_week
|
422
|
+
# Return Wednesday of the current week
|
423
|
+
# Calculate days until/since Wednesday (3)
|
424
|
+
today_wday = Date.today.wday
|
425
|
+
target_wday = 3 # Wednesday
|
426
|
+
days_diff = (target_wday - today_wday) % 7
|
427
|
+
# If the difference is more than 3, then Wednesday has passed this week
|
428
|
+
# So we need to go back to Wednesday
|
429
|
+
days_diff = days_diff - 7 if days_diff > 3
|
430
|
+
Date.today + days_diff
|
431
|
+
elsif date_value == :mid_month
|
432
|
+
# Return the 15th day of the current month
|
433
|
+
Date.new(Date.today.year, Date.today.month, 15)
|
434
|
+
end
|
435
|
+
end
|
74
436
|
end
|
75
437
|
end
|
data/lib/hizuke/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hizuke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Juraj Maťaše
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-04-
|
11
|
+
date: 2025-04-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -52,8 +52,9 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.21'
|
55
|
-
description:
|
56
|
-
and
|
55
|
+
description: Hizuke is a lightweight utility that extracts dates from text by recognizing
|
56
|
+
common time expressions. It cleans the original text and returns both the parsed
|
57
|
+
date and the text without the date reference.
|
57
58
|
email:
|
58
59
|
- juraj@hey.com
|
59
60
|
executables: []
|
@@ -94,5 +95,5 @@ requirements: []
|
|
94
95
|
rubygems_version: 3.3.7
|
95
96
|
signing_key:
|
96
97
|
specification_version: 4
|
97
|
-
summary: A simple date parser for
|
98
|
+
summary: A simple date parser for natural language time references
|
98
99
|
test_files: []
|