whichtime_sys/parsers/ja/
casual_date.rs1use crate::components::Component;
12use crate::context::ParsingContext;
13use crate::error::Result;
14use crate::parsers::Parser;
15use crate::results::ParsedResult;
16use crate::types::Meridiem;
17use chrono::{Datelike, Duration};
18use fancy_regex::Regex;
19use std::sync::LazyLock;
20
21static PATTERN: LazyLock<Regex> = LazyLock::new(|| {
22 Regex::new(
23 r"(今日|きょう|本日|ほんじつ|明日|あした|あす|昨日|きのう|さくじつ|明後日|あさって|一昨日|おととい|今朝|けさ|今夜|こんや|今晩|こんばん|今夕|こんゆう)(?:の(正午|昼|朝|午前|午後|夕方|夜|真夜中))?"
24 ).unwrap()
25});
26
27const DATE_GROUP: usize = 1;
28const TIME_PERIOD_GROUP: usize = 2;
29
30pub struct JACasualDateParser;
32
33impl JACasualDateParser {
34 pub fn new() -> Self {
35 Self
36 }
37}
38
39impl Parser for JACasualDateParser {
40 fn name(&self) -> &'static str {
41 "JACasualDateParser"
42 }
43
44 fn should_apply(&self, _context: &ParsingContext) -> bool {
45 true
46 }
47
48 fn parse(&self, context: &ParsingContext) -> Result<Vec<ParsedResult>> {
49 let mut results = Vec::new();
50 let ref_date = context.reference.instant;
51
52 let mut start = 0;
53 while start < context.text.len() {
54 let search_text = &context.text[start..];
55 let captures = match PATTERN.captures(search_text) {
56 Ok(Some(caps)) => caps,
57 Ok(None) => break,
58 Err(_) => break,
59 };
60
61 let full_match = match captures.get(0) {
62 Some(m) => m,
63 None => break,
64 };
65
66 let match_start = start + full_match.start();
67 let match_end = start + full_match.end();
68
69 let date_keyword = captures
70 .get(DATE_GROUP)
71 .map(|m| m.as_str())
72 .unwrap_or_default();
73
74 let time_period = captures.get(TIME_PERIOD_GROUP).map(|m| m.as_str());
75
76 let mut components = context.create_components();
77 let target_date;
78
79 match date_keyword {
81 "今日" | "きょう" | "本日" | "ほんじつ" => {
82 components.assign(Component::Year, ref_date.year());
83 components.assign(Component::Month, ref_date.month() as i32);
84 components.assign(Component::Day, ref_date.day() as i32);
85 }
86 "明日" | "あした" | "あす" => {
87 target_date = ref_date + Duration::days(1);
88 components.assign(Component::Year, target_date.year());
89 components.assign(Component::Month, target_date.month() as i32);
90 components.assign(Component::Day, target_date.day() as i32);
91 }
92 "昨日" | "きのう" | "さくじつ" => {
93 target_date = ref_date - Duration::days(1);
94 components.assign(Component::Year, target_date.year());
95 components.assign(Component::Month, target_date.month() as i32);
96 components.assign(Component::Day, target_date.day() as i32);
97 }
98 "明後日" | "あさって" => {
99 target_date = ref_date + Duration::days(2);
100 components.assign(Component::Year, target_date.year());
101 components.assign(Component::Month, target_date.month() as i32);
102 components.assign(Component::Day, target_date.day() as i32);
103 }
104 "一昨日" | "おととい" => {
105 target_date = ref_date - Duration::days(2);
106 components.assign(Component::Year, target_date.year());
107 components.assign(Component::Month, target_date.month() as i32);
108 components.assign(Component::Day, target_date.day() as i32);
109 }
110 "今朝" | "けさ" => {
111 components.assign(Component::Year, ref_date.year());
112 components.assign(Component::Month, ref_date.month() as i32);
113 components.assign(Component::Day, ref_date.day() as i32);
114 components.imply(Component::Hour, 6);
115 components.assign(Component::Meridiem, Meridiem::AM as i32);
116 }
117 "今夜" | "こんや" | "今晩" | "こんばん" | "今夕" | "こんゆう" => {
118 components.assign(Component::Year, ref_date.year());
119 components.assign(Component::Month, ref_date.month() as i32);
120 components.assign(Component::Day, ref_date.day() as i32);
121 components.imply(Component::Hour, 22);
122 components.assign(Component::Meridiem, Meridiem::PM as i32);
123 }
124 _ => {
125 start = match_end;
126 continue;
127 }
128 }
129
130 if let Some(period) = time_period {
132 match period {
133 "正午" | "昼" => {
134 components.assign(Component::Hour, 12);
135 components.assign(Component::Minute, 0);
136 components.assign(Component::Meridiem, Meridiem::PM as i32);
137 }
138 "朝" | "午前" => {
139 components.imply(Component::Hour, 8);
140 components.assign(Component::Meridiem, Meridiem::AM as i32);
141 }
142 "午後" => {
143 components.imply(Component::Hour, 14);
144 components.assign(Component::Meridiem, Meridiem::PM as i32);
145 }
146 "夕方" => {
147 components.imply(Component::Hour, 17);
148 components.assign(Component::Meridiem, Meridiem::PM as i32);
149 }
150 "夜" => {
151 components.imply(Component::Hour, 20);
152 components.assign(Component::Meridiem, Meridiem::PM as i32);
153 }
154 "真夜中" => {
155 components.assign(Component::Hour, 0);
156 components.assign(Component::Minute, 0);
157 }
158 _ => {}
159 }
160 }
161
162 results.push(context.create_result(match_start, match_end, components, None));
163
164 start = match_end;
165 }
166
167 Ok(results)
168 }
169}
170
171impl Default for JACasualDateParser {
172 fn default() -> Self {
173 Self::new()
174 }
175}