Add support for skeleton date formats

This commit is contained in:
Damian Nelson 2021-03-24 23:49:24 -07:00
parent 7fc5d65f6d
commit f71e1fabeb
3 changed files with 73 additions and 12 deletions

View File

@ -425,11 +425,12 @@ module ICU
attach_function :unum_set_attribute, "unum_setAttribute#{suffix}", [:pointer, :number_format_attribute, :int32_t], :void
# date
enum :date_format_style, [
:none, -1,
:full, 0,
:long, 1,
:medium, 2,
:short, 3,
:pattern, -2,
:none, -1,
:full, 0,
:long, 1,
:medium, 2,
:short, 3,
]
attach_function :udat_open, "udat_open#{suffix}", [:date_format_style, :date_format_style, :string, :pointer, :int32_t, :pointer, :int32_t, :pointer ], :pointer
attach_function :udat_close, "unum_close#{suffix}", [:pointer], :void
@ -437,6 +438,9 @@ module ICU
attach_function :udat_parse, "udat_parse#{suffix}", [:pointer, :pointer, :int32_t, :pointer, :pointer], :double
attach_function :udat_toPattern, "udat_toPattern#{suffix}", [:pointer, :bool , :pointer, :int32_t , :pointer], :int32_t
attach_function :udat_applyPattern, "udat_applyPattern#{suffix}", [:pointer, :bool , :pointer, :int32_t ], :void
# skeleton pattern
attach_function :udatpg_open, "udatpg_open#{suffix}", [:string, :pointer], :pointer
attach_function :udatpg_getBestPattern, "udatpg_getBestPattern#{suffix}", [:pointer, :pointer, :int32_t, :pointer, :int32_t, :pointer], :int32_t
# tz
attach_function :ucal_setDefaultTimeZone, "ucal_setDefaultTimeZone#{suffix}", [:pointer, :pointer], :int32_t
attach_function :ucal_getDefaultTimeZone, "ucal_getDefaultTimeZone#{suffix}", [:pointer, :int32_t, :pointer], :int32_t

View File

@ -65,21 +65,46 @@ module ICU
private
def make_formatter(time_style, date_style, locale, time_zone_str)
def make_formatter(time_style, date_style, locale, time_zone_str, skeleton)
time_zone = nil
d_len = 0
tz_len = 0
if time_zone_str
time_zone = UCharPointer.from_string(time_zone_str)
d_len = time_zone_str.size
tz_len = time_zone_str.size
else
Lib.check_error { | error|
i_len = 150
time_zone = UCharPointer.new(i_len)
d_len = Lib.ucal_getDefaultTimeZone(time_zone, i_len, error)
tz_len = Lib.ucal_getDefaultTimeZone(time_zone, i_len, error)
}
end
ptr = Lib.check_error { | error| Lib.udat_open(time_style, date_style, locale, time_zone, d_len, FFI::MemoryPointer.new(4), -1, error) }
pattern_len = -1
pattern_ptr = FFI::MemoryPointer.new(4)
if skeleton
skeleton = UCharPointer.from_string(skeleton)
pattern_len = 0
pattern_ptr = UCharPointer.new(pattern_len)
pg_ptr = Lib.check_error { |error| Lib.udatpg_open(locale, error) }
generator = FFI::AutoPointer.new(pg_ptr, Lib.method(:udat_close))
retried = false
begin
Lib.check_error do |error|
pattern_len = Lib.udatpg_getBestPattern(generator, skeleton, skeleton.size, pattern_ptr, pattern_len, error)
end
rescue BufferOverflowError
raise BufferOverflowError, "needed: #{pattern_len}" if retried
pattern_ptr = pattern_ptr.resized_to pattern_len
retried = true
retry
end
end
ptr = Lib.check_error { | error| Lib.udat_open(time_style, date_style, locale, time_zone, tz_len, pattern_ptr, pattern_len, error) }
FFI::AutoPointer.new(ptr, Lib.method(:udat_close))
end
end
@ -91,7 +116,9 @@ module ICU
locale = options[:locale] || 'C'
tz_style = options[:tz_style]
time_zone = options[:zone]
@f = make_formatter(time_style, date_style, locale, time_zone)
skeleton = options[:skeleton]
@f = make_formatter(time_style, date_style, locale, time_zone, skeleton)
if tz_style
f0 = date_format(true)
f1 = update_tz_format(f0, tz_style)
@ -177,6 +204,23 @@ module ICU
needed_length = Lib.udat_applyPattern(@f, localized, pattern, pattern_len)
end
end
def with_retry(out_ptr)
needed_length = 0
out_ptr = UCharPointer.new(needed_length)
retried = false
begin
Lib.check_error do |error|
yield(error)
end
rescue BufferOverflowError
raise BufferOverflowError, "needed: #{needed_length}" if retried
out_ptr = out_ptr.resized_to needed_length
retried = true
retry
end
end
end # DateTimeFormatter
end # Formatting
end # ICU

View File

@ -59,7 +59,7 @@ module ICU
expect(f2.format(t8)).to eq("3/29/08#{en_sep} 6:38:24 AM #{en_tz}")
end
f3 = TimeFormatting.create(:locale => 'de_DE', :zone => 'Africa/Dakar ', :date => :short , :time => :long)
f3 = TimeFormatting.create(:locale => 'de_DE', :zone => 'Africa/Dakar', :date => :short , :time => :long)
ge_sep = ""
if cldr_version >= "27.0.1"
ge_sep = ","
@ -82,6 +82,19 @@ module ICU
expect(f3.format(t7)).to eq("29.03.08#{ge_sep} 02:37:23 GMT")
expect(f3.format(t8)).to eq("29.03.08#{ge_sep} 03:38:24 GMT")
end
context 'skeleton pattern' do
f4 = TimeFormatting.create(:locale => 'fr_FR', :date => :pattern , :time => :pattern, :skeleton => 'MMMy')
it 'check format' do
expect(f4.format(t0)).to eq("nov. 2008")
expect(f4.format(t1)).to eq("oct. 2008")
end
it 'check date_format' do
expect(f4.date_format(true)).to eq("MMM y")
end
end
end
end
end