Skip to content

Allow timestamp-tagged scalars to unmarshal into strings#379

Merged
ingydotnet merged 1 commit into
yaml:mainfrom
oguzkilcan:timestamp-string-fallback-fix
Jul 12, 2026
Merged

Allow timestamp-tagged scalars to unmarshal into strings#379
ingydotnet merged 1 commit into
yaml:mainfrom
oguzkilcan:timestamp-string-fallback-fix

Conversation

@oguzkilcan

@oguzkilcan oguzkilcan commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

constructTimestamp only handled time.Time and interface{} targets. A plain scalar resolving to the timestamp tag left a string field at its zero value instead of the raw text. This adds a string case that writes the scalar directly, the same fallback other scalar tags already have.

Fixes #376

Copilot AI review requested due to automatic review settings July 10, 2026 22:09

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a gap in the YAML constructor logic where scalars implicitly resolved as !!timestamp would not populate Go string targets, leaving them at the zero value. It aligns !!timestamp behavior with other scalar tags by allowing a string fallback that assigns the scalar text directly.

Changes:

  • Extend constructTimestamp to support reflect.String targets by setting the scalar value (Node.Value) into the destination string.
  • Add a regression test ensuring an implicitly timestamp-tagged scalar unmarshals into map[string]string as the original timestamp text.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
yaml_test.go Adds a regression test covering implicit !!timestamp resolution into a string field.
internal/libyaml/constructor.go Adds reflect.String handling to constructTimestamp so timestamp scalars can populate string targets.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread yaml_test.go Outdated
Comment thread yaml_test.go Outdated
Comment thread yaml_test.go
@ccoVeille

Copy link
Copy Markdown
Contributor

Thanks @oguzkilcan

I feel like the fix is good.

But I'm doubtful about the tests.

Note: I edited your PR description to mention the issue you opened

@oguzkilcan oguzkilcan force-pushed the timestamp-string-fallback-fix branch from 021e6cf to 661285b Compare July 11, 2026 07:59
@oguzkilcan

Copy link
Copy Markdown
Contributor Author

Thank you for the review. I incorporated your suggestions into the test suite. It run successfully.

❯ go test -run TestUnmarshal
PASS
ok      go.yaml.in/yaml/v4      0.194s

@ingydotnet

Copy link
Copy Markdown
Member

- !!timestamp foo - I'm wondering if this should error.

I probably need to consult with the core team.

@ingydotnet ingydotnet force-pushed the timestamp-string-fallback-fix branch from 661285b to cb1c831 Compare July 11, 2026 18:42
@ingydotnet

Copy link
Copy Markdown
Member

The 1.1 and 1.2 specs allow it to load as a string. It's really up to us what to do.

!!timestamp isn't part of the YAML 1.2 spec's Core yaml-schema, so I'm a bit loathe to make this a default.

Honestly I'd like all of tag resolution and construction to be handled at the RuleSet plugin level. Then a RuleSet would be made for the current behavior inherited from go-yaml v3 and that would be the default, and there would become myriad other RuleSets to use or extend.

That said I just noticed this is a fix for a v4 regression, so I'll take a closer look now.

@ingydotnet

Copy link
Copy Markdown
Member

Looks like the regression was here:

// constructTimestamp constructs a !!timestamp tagged value into various Go types.
func (c *Constructor) constructTimestamp(n *Node, resolved any, out reflect.Value) bool {
switch out.Kind() {
case reflect.Struct:
if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
out.Set(resolvedv)
return true
}
case reflect.Interface:
out.Set(reflect.ValueOf(resolved))
return true
}
c.tagError(n, timestampTag, out)
return false

and also regressed !!float but that got fixed here: fcab72b

@ingydotnet ingydotnet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oguzkilcan Can you add a test for an implicit timestamp, as that is what was reported by #376.

@oguzkilcan oguzkilcan force-pushed the timestamp-string-fallback-fix branch from cb1c831 to 3d241b5 Compare July 11, 2026 21:30
constructTimestamp only handled time.Time and interface{} targets. A plain scalar resolving to the timestamp tag left a string field at its zero value instead of the raw text. This adds a string case that writes the scalar directly, the same fallback other scalar tags already have.
@ingydotnet ingydotnet force-pushed the timestamp-string-fallback-fix branch from 3d241b5 to 1ae3a62 Compare July 12, 2026 11:39
@ingydotnet ingydotnet merged commit b8d7755 into yaml:main Jul 12, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot construct !!timestamp 2023-01-01 into string

4 participants