add time formats

This commit is contained in:
Pete Matsyburka
2026-04-23 20:25:41 +03:00
parent 82500c2d7d
commit c7afe33c72
18 changed files with 384 additions and 144 deletions
+1 -3
View File
@@ -410,9 +410,7 @@ module Submissions
submitter.values = Submitters::SubmitValues.maybe_remove_condition_values(submitter)
end
submitter.values = submitter.values.transform_values do |v|
v == '{{date}}' ? Time.current.in_time_zone(submitter.submission.account.timezone).to_date.to_s : v
end
submitter.values = Submitters::SubmitValues.replace_current_date_placeholders(submitter)
submitter
end
+2 -1
View File
@@ -415,7 +415,8 @@ module Submissions
composer.formatted_text_box([{ text: value.to_s.titleize }], padding: [0, 0, 10, 0])
else
if field['type'] == 'date'
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), account.locale)
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), account.locale,
timezone:)
end
value = NumberUtils.format_number(value, field.dig('preferences', 'format')) if field['type'] == 'number'
@@ -652,7 +652,10 @@ module Submissions
end
else
if field['type'] == 'date'
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), locale)
timezone = submitter.account.timezone
timezone = submitter.timezone || submitter.account.timezone if with_submitter_timezone
value = TimeUtils.format_date_string(value, field.dig('preferences', 'format'), locale, timezone:)
end
value = NumberUtils.format_number(value, field.dig('preferences', 'format')) if field['type'] == 'number'
+30 -4
View File
@@ -103,17 +103,43 @@ module Submitters
end
def normalize_date(field, value)
if value.is_a?(Integer)
format = field.dig('preferences', 'format')
if TimeUtils.format_with_time?(format)
normalize_date_time(value, format)
elsif TimeUtils.month_only_format?(format)
normalize_date_month(value, format)
elsif value.is_a?(Integer)
Time.zone.at(value.to_s.first(10).to_i).to_date.to_s
elsif value.gsub(/\w/, '0') == field.dig('preferences', 'format').to_s.gsub(/\w/, '0')
TimeUtils.parse_date_string(value, field.dig('preferences', 'format')).to_s
elsif value.gsub(/\w/, '0') == format.to_s.gsub(/\w/, '0')
TimeUtils.parse_date_string(value, format).to_s
else
Date.parse(value).to_s
end
rescue Date::Error
rescue ArgumentError
value
end
def normalize_date_time(value, format)
if value.is_a?(Integer)
Time.zone.at(value.to_s.first(10).to_i).utc.iso8601
elsif value.to_s.match?(/T\d{2}:\d{2}/)
Time.iso8601(value).utc.iso8601
else
TimeUtils.parse_date_string(value, format).utc.iso8601
end
end
def normalize_date_month(value, format)
if value.is_a?(Integer)
Time.zone.at(value.to_s.first(10).to_i).strftime('%Y-%m')
elsif value.to_s.match?(/\A\d{4}-\d{2}\z/)
value
else
TimeUtils.parse_date_string(value, format).strftime('%Y-%m')
end
end
def fetch_fields(template, submitter_name: nil, for_submitter: nil)
if submitter_name && !for_submitter
submitter =
+20 -8
View File
@@ -86,9 +86,7 @@ module Submitters
submitter.values = maybe_remove_condition_values(submitter, required_field_uuids_acc:)
end
submitter.values = submitter.values.transform_values do |v|
v == '{{date}}' ? Time.current.in_time_zone(submitter.account.timezone).to_date.to_s : v
end
submitter.values = replace_current_date_placeholders(submitter)
required_field_uuids_acc.each do |uuid|
next if submitter.values[uuid].present?
@@ -194,7 +192,7 @@ module Submitters
next if value.blank?
acc[field['uuid']] = template_default_value_for_submitter(value, submitter, with_time: true)
acc[field['uuid']] = template_default_value_for_submitter(value, submitter, field:, with_time: true)
end
default_values.compact_blank.merge(submitter.values)
@@ -248,7 +246,20 @@ module Submitters
0
end
def template_default_value_for_submitter(value, submitter, with_time: false)
def replace_current_date_placeholders(submitter)
submitter.values.each_with_object({}) do |(uuid, v), acc|
acc[uuid] =
if v == '{{date}}'
field = submitter.submission.fields_uuid_index[uuid]
TimeUtils.current_date_value(field&.dig('preferences', 'format'), submitter.account.timezone)
else
v
end
end
end
def template_default_value_for_submitter(value, submitter, with_time: false, field: nil)
return if value.blank?
return if submitter.blank?
@@ -257,7 +268,8 @@ module Submitters
replace_default_variables(value,
submitter.attributes.merge('role' => role),
submitter.submission,
with_time:)
with_time:,
field:)
end
def maybe_remove_condition_values(submitter, required_field_uuids_acc: nil)
@@ -394,7 +406,7 @@ module Submitters
end
# rubocop:enable Metrics
def replace_default_variables(value, attrs, submission, with_time: false)
def replace_default_variables(value, attrs, submission, with_time: false, field: nil)
return value if value.in?([true, false]) || value.is_a?(Numeric) || value.is_a?(Array)
return if value.blank?
@@ -412,7 +424,7 @@ module Submitters
when 'hour', 'minute', 'day', 'month', 'year'
with_time ? Time.current.in_time_zone(submission.account.timezone).strftime(STRFTIME_MAP[key]) : e
when 'date'
with_time ? Time.current.in_time_zone(submission.account.timezone).to_date.to_s : e
with_time ? TimeUtils.current_date_value(field&.dig('preferences', 'format'), submission.account.timezone) : e
when 'role', 'email', 'phone', 'name'
attrs[key] || e
else
+88 -14
View File
@@ -19,6 +19,47 @@ module TimeUtils
'YY' => '%y'
}.freeze
HOUR_FORMATS = {
'H' => '%-H',
'HH' => '%H',
'h' => '%-I',
'hh' => '%I'
}.freeze
MINUTE_FORMATS = {
'm' => '%-M',
'mm' => '%M'
}.freeze
SECOND_FORMATS = {
's' => '%-S',
'ss' => '%S'
}.freeze
AMPM_FORMATS = {
'A' => '%p',
'a' => '%P'
}.freeze
TIMEZONE_FORMATS = {
'z' => '%Z'
}.freeze
TIME_FORMATS = HOUR_FORMATS.merge(MINUTE_FORMATS)
.merge(SECOND_FORMATS)
.merge(AMPM_FORMATS)
.freeze
ALL_FORMATS = MONTH_FORMATS.merge(DAY_FORMATS)
.merge(YEAR_FORMATS)
.merge(TIME_FORMATS)
.merge(TIMEZONE_FORMATS)
.freeze
TOKEN_REGEX = /MMMM|MMM|MM|M|DD|D|YYYY|YYY|YY|HH|hh|H|h|mm|m|ss|s|A|a|z/
MONTH_ONLY_VALUE_REGEX = /\A\d{4}-\d{2}\z/
DEFAULT_DATE_FORMAT_US = 'MM/DD/YYYY'
DEFAULT_DATE_FORMAT = 'DD/MM/YYYY'
@@ -42,27 +83,60 @@ module TimeUtils
end
end
def parse_date_string(string, pattern)
pattern = pattern.sub(/Y+/, YEAR_FORMATS)
.sub(/M+/, MONTH_FORMATS)
.sub(/D+/, DAY_FORMATS)
Date.strptime(string, pattern)
def format_with_time?(format)
format.to_s.match?(/[HhAasz]/)
end
def format_date_string(string, format, locale)
date = Date.parse(string.to_s)
def month_only_format?(format)
format.to_s.present? && !format.to_s.match?(/[DdHhAasz]/)
end
format = format.upcase if format
def format_date_preview(format, locale, timezone)
return '' if format.blank?
format = format.upcase unless format_with_time?(format)
preview_pattern = format.gsub(TOKEN_REGEX) { |token| TIME_FORMATS.key?(token) ? '--' : ALL_FORMATS[token] }
I18n.l(Time.current.in_time_zone(timezone.presence || Time.zone.name), format: preview_pattern, locale:)
end
def current_date_value(format, timezone)
tz = timezone.presence || Time.zone.name
if format_with_time?(format)
Time.current.utc.iso8601
elsif month_only_format?(format)
Time.current.in_time_zone(tz).strftime('%Y-%m')
else
Time.current.in_time_zone(tz).to_date.to_s
end
end
def parse_date_string(string, pattern)
with_time = format_with_time?(pattern)
pattern = pattern.upcase unless with_time
pattern = pattern.gsub(TOKEN_REGEX, ALL_FORMATS)
with_time ? Time.zone.strptime(string, pattern) : Date.strptime(string, pattern)
end
def format_date_string(string, format, locale, timezone: nil)
format = format.upcase if format && !format_with_time?(format)
format ||= locale.to_s.ends_with?('US') ? DEFAULT_DATE_FORMAT_US : DEFAULT_DATE_FORMAT
i18n_format = format.sub(/D+/) { DAY_FORMATS[format[/D+/]] }
.sub(/M+/) { MONTH_FORMATS[format[/M+/]] }
.sub(/Y+/) { YEAR_FORMATS[format[/Y+/]] }
date =
if format_with_time?(format)
Time.iso8601(string.to_s).in_time_zone(timezone.presence || Time.zone.name)
elsif string.to_s.match?(MONTH_ONLY_VALUE_REGEX)
year, month = string.to_s.split('-').map(&:to_i)
I18n.l(date, format: i18n_format, locale:)
rescue Date::Error
Date.new(year, month, 1)
else
Date.parse(string.to_s)
end
I18n.l(date, format: format.gsub(TOKEN_REGEX, ALL_FORMATS), locale:)
rescue ArgumentError
string
end
end