mirror of
https://github.com/discourse/discourse-ai.git
synced 2025-02-08 20:44:42 +00:00
* FEATURE: smart date support for AI helper This feature allows conversion of human typed in dates and times to smart "Discourse" timezone friendly dates. * fix specs and lint * lint * address feedback * add specs
145 lines
5.0 KiB
Ruby
145 lines
5.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module DiscourseAi
|
|
module AiHelper
|
|
class DateFormatter
|
|
DAYS_OF_WEEK = {
|
|
"monday" => 1,
|
|
"tuesday" => 2,
|
|
"wednesday" => 3,
|
|
"thursday" => 4,
|
|
"friday" => 5,
|
|
"saturday" => 6,
|
|
"sunday" => 0,
|
|
}
|
|
|
|
class << self
|
|
def process_date_placeholders(text, user)
|
|
return text if !text.include?("{{")
|
|
|
|
timezone = user.user_option.timezone || "UTC"
|
|
reference_time = Time.now.in_time_zone(timezone)
|
|
|
|
text.gsub(
|
|
/\{\{(date_time_offset_minutes|date_offset_days|datetime|date|next_week):([^}]+)\}\}/,
|
|
) do |match|
|
|
type = $1
|
|
value = $2
|
|
|
|
case type
|
|
when "datetime"
|
|
if value.include?(":")
|
|
# Handle range like "2pm+1:3pm+2"
|
|
start_str, end_str = value.split(":")
|
|
format_datetime_range(
|
|
parse_time_with_offset(start_str, reference_time),
|
|
parse_time_with_offset(end_str, reference_time),
|
|
timezone,
|
|
)
|
|
else
|
|
# Handle single time like "2pm+1" or "10pm"
|
|
format_date_time(parse_time_with_offset(value, reference_time), timezone)
|
|
end
|
|
when "next_week"
|
|
if value.include?(":")
|
|
# Handle range like "tuesday-1pm:tuesday-3pm"
|
|
start_str, end_str = value.split(":")
|
|
start_time = parse_next_week(start_str, reference_time)
|
|
end_time = parse_next_week(end_str, reference_time)
|
|
format_datetime_range(start_time, end_time, timezone)
|
|
else
|
|
# Handle single time like "tuesday-1pm" or just "tuesday"
|
|
time = parse_next_week(value, reference_time)
|
|
value.include?("-") ? format_date_time(time, timezone) : format_date(time, timezone)
|
|
end
|
|
when "date"
|
|
format_date(reference_time + value.to_i.days, timezone)
|
|
when "date_time_offset_minutes"
|
|
if value.include?(":")
|
|
start_offset, end_offset = value.split(":").map(&:to_i)
|
|
format_datetime_range(
|
|
reference_time + start_offset.minutes,
|
|
reference_time + end_offset.minutes,
|
|
timezone,
|
|
)
|
|
else
|
|
format_date_time(reference_time + value.to_i.minutes, timezone)
|
|
end
|
|
when "date_offset_days"
|
|
if value.include?(":")
|
|
start_offset, end_offset = value.split(":").map(&:to_i)
|
|
format_date_range(
|
|
reference_time + start_offset.days,
|
|
reference_time + end_offset.days,
|
|
timezone,
|
|
)
|
|
else
|
|
format_date(reference_time + value.to_i.days, timezone)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def parse_next_week(str, reference_time)
|
|
if str.include?("-")
|
|
# Handle day with time like "tuesday-1pm"
|
|
day, time = str.split("-")
|
|
target_date = get_next_week_day(day.downcase, reference_time)
|
|
parse_time(time, target_date)
|
|
else
|
|
# Just the day
|
|
get_next_week_day(str.downcase, reference_time)
|
|
end
|
|
end
|
|
|
|
def get_next_week_day(day, reference_time)
|
|
raise ArgumentError unless DAYS_OF_WEEK.key?(day)
|
|
|
|
target_date = reference_time + 1.week
|
|
days_ahead = DAYS_OF_WEEK[day] - target_date.wday
|
|
days_ahead += 7 if days_ahead < 0
|
|
target_date + days_ahead.days
|
|
end
|
|
|
|
def parse_time_with_offset(time_str, reference_time)
|
|
if time_str.include?("+")
|
|
time_part, days = time_str.split("+")
|
|
parse_time(time_part, reference_time + days.to_i.days)
|
|
else
|
|
parse_time(time_str, reference_time)
|
|
end
|
|
end
|
|
|
|
def parse_time(time_str, reference_time)
|
|
hour = time_str.to_i
|
|
if time_str.downcase.include?("pm") && hour != 12
|
|
hour += 12
|
|
elsif time_str.downcase.include?("am") && hour == 12
|
|
hour = 0
|
|
end
|
|
|
|
reference_time.change(hour: hour, min: 0, sec: 0)
|
|
end
|
|
|
|
def format_date(time, timezone)
|
|
"[date=#{time.strftime("%Y-%m-%d")} timezone=\"#{timezone}\"]"
|
|
end
|
|
|
|
def format_date_time(time, timezone)
|
|
"[date=#{time.strftime("%Y-%m-%d")} time=#{time.strftime("%H:%M:%S")} timezone=\"#{timezone}\"]"
|
|
end
|
|
|
|
def format_date_range(start_time, end_time, timezone)
|
|
"[date-range from=#{start_time.strftime("%Y-%m-%d")} to=#{end_time.strftime("%Y-%m-%d")} timezone=\"#{timezone}\"]"
|
|
end
|
|
|
|
def format_datetime_range(start_time, end_time, timezone)
|
|
"[date-range from=#{start_time.strftime("%Y-%m-%dT%H:%M:%S")} to=#{end_time.strftime("%Y-%m-%dT%H:%M:%S")} timezone=\"#{timezone}\"]"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|