mirror of
https://github.com/sbrow/thor.git
synced 2026-08-26 11:23:32 -04:00
feat(mustache): apply_format now accepts timezone info.
This commit is contained in:
@@ -32,7 +32,8 @@
|
|||||||
## Dates
|
## Dates
|
||||||
- [x] Accept "strings"
|
- [x] Accept "strings"
|
||||||
- [x] Accept keys
|
- [x] Accept keys
|
||||||
- [ ] handle timezones
|
- [x] handle timezones
|
||||||
|
- [ ] Fix TZ cache leak in parallel tests: `tz_cache` uses `context.allocator` (tracking allocator in tests), but it's global state shared across parallel test threads. Race causes leak warnings. Fix: use heap allocator for TZ cache.
|
||||||
- [ ] display an error when no part of the date appears in the output.
|
- [ ] display an error when no part of the date appears in the output.
|
||||||
- [x] use `date.format` as the default format.
|
- [x] use `date.format` as the default format.
|
||||||
- [ ] Handle 0 and whitespace padding i.e. "_2" -> " 2"
|
- [ ] Handle 0 and whitespace padding i.e. "_2" -> " 2"
|
||||||
|
|||||||
+26
-2
@@ -228,7 +228,15 @@ apply_filter :: proc(value: any, filter: ^Pipe_Filter, pos: int, ctx: []any) ->
|
|||||||
date_format = df
|
date_format = df
|
||||||
}
|
}
|
||||||
|
|
||||||
str2, err := apply_format(str, filter.args[:], pos, date_format)
|
// Resolve timezone (optional — empty is fine, means display as-is)
|
||||||
|
tz_name := ""
|
||||||
|
if raw := resolve_name("timezone", ctx); raw != nil {
|
||||||
|
if s, s_ok := reflect.as_string(raw); s_ok {
|
||||||
|
tz_name = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str2, err := apply_format(str, filter.args[:], pos, date_format, tz_name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return value, err
|
return value, err
|
||||||
} else {
|
} else {
|
||||||
@@ -249,6 +257,7 @@ apply_format :: proc(
|
|||||||
args: []string,
|
args: []string,
|
||||||
pos: int,
|
pos: int,
|
||||||
date_format: string,
|
date_format: string,
|
||||||
|
timezone_name: string,
|
||||||
) -> (
|
) -> (
|
||||||
result: string,
|
result: string,
|
||||||
err: Error,
|
err: Error,
|
||||||
@@ -270,7 +279,22 @@ apply_format :: proc(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debugf("date: '%s' format: '%s'", iso, date_format)
|
target_tz, tz_ok := get_cached_tz(timezone_name)
|
||||||
|
if !tz_ok {
|
||||||
|
return "", Error_Body {
|
||||||
|
msg = fmt.tprintf("unable to load timezone '%s'", timezone_name),
|
||||||
|
pos = pos,
|
||||||
|
kind = .Data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_tz != nil {
|
||||||
|
components, _ = convert_to_tz(components, target_tz)
|
||||||
|
} else if components.has_offset {
|
||||||
|
components.tz_abbr = format_offset(components.offset_seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debugf("date: '%s' format: '%s' tz: '%s'", iso, date_format, timezone_name)
|
||||||
return format_date(components, fmt_str), nil
|
return format_date(components, fmt_str), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -511,3 +511,76 @@ test_timezone_empty_when_not_set :: proc(t: ^testing.T) {
|
|||||||
result, _ := render(tpl, data, {}, context.temp_allocator)
|
result, _ := render(tpl, data, {}, context.temp_allocator)
|
||||||
testing.expect_value(t, result, "[]")
|
testing.expect_value(t, result, "[]")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// format pipe with timezone conversion
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_format_with_timezone_summer :: proc(t: ^testing.T) {
|
||||||
|
tz, tz_ok := get_cached_tz("America/New_York")
|
||||||
|
defer destroy_tz_cache()
|
||||||
|
if !tz_ok || tz == nil do return
|
||||||
|
|
||||||
|
data := Format_Data {
|
||||||
|
date = "2026-03-15T12:49:54Z",
|
||||||
|
date_format = "15:04 MST",
|
||||||
|
timezone = "America/New_York",
|
||||||
|
}
|
||||||
|
tpl, _ := parse("{{date | format}}", "<test>", allocator = context.temp_allocator)
|
||||||
|
result, _ := render(tpl, data, {}, context.temp_allocator)
|
||||||
|
testing.expect_value(t, result, "08:49 EDT")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_format_with_timezone_winter :: proc(t: ^testing.T) {
|
||||||
|
tz, tz_ok := get_cached_tz("America/New_York")
|
||||||
|
defer destroy_tz_cache()
|
||||||
|
if !tz_ok || tz == nil do return
|
||||||
|
|
||||||
|
data := Format_Data {
|
||||||
|
date = "2026-01-15T12:49:54Z",
|
||||||
|
date_format = "15:04 MST",
|
||||||
|
timezone = "America/New_York",
|
||||||
|
}
|
||||||
|
tpl, _ := parse("{{date | format}}", "<test>", allocator = context.temp_allocator)
|
||||||
|
result, _ := render(tpl, data, {}, context.temp_allocator)
|
||||||
|
testing.expect_value(t, result, "07:49 EST")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_format_mst_offset_no_timezone :: proc(t: ^testing.T) {
|
||||||
|
data := Format_Data {
|
||||||
|
date = "2026-03-15T08:49:54-04:00",
|
||||||
|
date_format = "MST",
|
||||||
|
}
|
||||||
|
tpl, _ := parse("{{date | format}}", "<test>", allocator = context.temp_allocator)
|
||||||
|
result, _ := render(tpl, data, {}, context.temp_allocator)
|
||||||
|
testing.expect_value(t, result, "UTC-04:00")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_format_mst_no_offset_no_timezone :: proc(t: ^testing.T) {
|
||||||
|
data := Format_Data {
|
||||||
|
date = "2026-03-15",
|
||||||
|
date_format = "MST",
|
||||||
|
}
|
||||||
|
tpl, _ := parse("{{date | format}}", "<test>", allocator = context.temp_allocator)
|
||||||
|
result, _ := render(tpl, data, {}, context.temp_allocator)
|
||||||
|
testing.expect_value(t, result, "UTC")
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_format_invalid_timezone_errors :: proc(t: ^testing.T) {
|
||||||
|
defer destroy_tz_cache()
|
||||||
|
|
||||||
|
data := Format_Data {
|
||||||
|
date = "2026-03-15",
|
||||||
|
date_format = "2 Jan 2006",
|
||||||
|
timezone = "Invalid/Zone",
|
||||||
|
}
|
||||||
|
tpl, _ := parse("{{date | format}}", "<test>", allocator = context.temp_allocator)
|
||||||
|
defer delete_template(&tpl)
|
||||||
|
_, err := render(tpl, data, {}, context.temp_allocator)
|
||||||
|
testing.expect(t, err != nil, "invalid timezone should error")
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user