Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: encoding/json: support struct tag for time.Format in JSON Marshaller/Unmarshaller #21990

marwan-at-work opened this issue Sep 23, 2017 · 9 comments


Copy link

@marwan-at-work marwan-at-work commented Sep 23, 2017

I will start with the proposal as a TL;DR before explaining the motivations behind it:


It would be quite convenient if we could have the encoding/json package understand the format of time.Time as part of the struct definition. Something like this:

type User struct {
	Name     string
	JoinDate time.Time `time:"2006-01-02"`

This means that when you write json.Unmarshal(data, &user), the json package will understand what format to parse/serialize the field with.

Motivation/Experience Report

Currently, there are three workarounds:

  1. type MyTime time.Time:

  2. Embedding time.Time in MyTime type:

  3. Implementing json.Unmarshaller on the parent struct:

Those workarounds are not bad. However, I've noticed that they get out of hand once your codebase starts to scale.

Imagine having hundreds of structs with hundreds of fields where many of them could have different Time types just because they have different serialization formats, and nothing else.

The time.Time package, I think, might be too opinionated to assume RFC3339 is the only acceptable format in the json.Unmarshaller interface: (Same goes for RFC3339Nano in the json.Marshaller implementation).

I think it makes sense for it to be a default serialization format, but not the only one. The workaround is initially not bad at all. However, it gets cumbersome when your project scales.

I think this proposal shows that the above solution can make our code more declarative and less cumbersome. This echo's Rob Pike's talk in that here we can hide complexity behind a simple interface.

Lastly, this doesn't make or break my Go experience, but I personally see room for enhancement here.

@ianlancetaylor ianlancetaylor changed the title Include Struct Tag for time.Format in JSON Marshaller/Unmarshaller encoding/json: support struct tag for time.Format in JSON Marshaller/Unmarshaller Sep 24, 2017
@ianlancetaylor ianlancetaylor added this to the Unplanned milestone Sep 24, 2017
Copy link

@rsc rsc commented Oct 23, 2017

It's an interesting idea and maybe one to consider the next time we take a chunk of json decisions to make. For now the usual idiom is the wrapper type, as you described. Going to mark this as a proposal-hold for whenever the next rethink of json is.

Copy link

@gnodiah gnodiah commented Jul 27, 2018


That would be convenient if it can specify time format through json tag, because formatting time is a more often behavior in most cases.

@dsnet dsnet changed the title encoding/json: support struct tag for time.Format in JSON Marshaller/Unmarshaller proposal: encoding/json: support struct tag for time.Format in JSON Marshaller/Unmarshaller Sep 22, 2018
@golang golang deleted a comment from giautm Mar 4, 2019
Copy link

@penggy penggy commented Apr 19, 2019

The tag name maybe "layout", reuse by xml...

Copy link

@grokify grokify commented Nov 18, 2019

Any update on this? This would be great for working with APIs, many of which have fixed time formats other than RFC-3339 date-time.

Copy link

@eibrunorodrigues eibrunorodrigues commented Apr 1, 2020

Any Updates guys?

Copy link

@Abhaykumar1 Abhaykumar1 commented May 1, 2020

I logged an issue I have been facing because of he time.Time package, assume RFC3339 is the only acceptable format in the json.Unmarshaller interface:

When the defined time has trailing zero after the millisecond
trailingZero = "2020-02-19T07:11:23.890+00:00"
noTrailingZero = "2020-02-19T07:11:23.891+00:00"

GO removes the trailing zero. The time becomes

2020-02-19 07:11:23.89 +0000 UTC
2020-02-19 07:11:23.891 +0000 UTC

This is an issue when other consuming application tries to consume this by defining a date formatter to get time from String value. The formatter does the strict matching.

for example in java
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSz";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);

It will throw an exception while parsing 2020-02-19 07:11:23.89 +0000 UTC while will perfectly work for 2020-02-19 07:11:23.891 +0000 UTC

The defect was closed saying I can use formatter and do parsed.Format("2006-01-02 15:04:05.000000000 -0700 MST")

It's really a painful change, every time the user will have to reformat the time given the case below

type activity struct {
ActivityDate time.Time json:"activityDate" bson:"activityDate"

I read the data in this struct from MongoDB by using cur.Decode(&activity)
and write the response back using the json encoder

@golang golang deleted a comment from planesandunicorns Oct 23, 2020
Copy link

@avinersan avinersan commented Jun 22, 2021

👍 on the proposal.

Hope I'm not breaking any rules here by commenting on this thread an alternative / complementary convenient way for changing a type json output.

Idea is to allow custom serialization behaviour in the marshalling /unmarshalling process without having to touch the value being (un)marshalled.

When calling json.Marshalf (new function) there could be a marshalers argument of type []TypeMarshaler that allows the caller to customise the process.

Potential TypeMarshaler interface:

type TypeMarshaler interface {
	CanHandle(t reflect.Type) bool
	MarshalJSON(v *interface{}) ([]byte, error)

and corresponding

type TypeUnmarshaler interface {
	CanHandle(t reflect.Type) bool
	UnmarshalJSON(v *interface{}, b []byte) error

The TypeMarshaler would be applied to each field in the to marshal value that satisfies the CanHandle function.


  • decouples the type from the serialization process
  • can customize serialization on any type even if not owned
  • allows per type global formatting which in my experience is the most used - rarely there is a need to output 2 datetime formats in the same context (excluding date vs datetime)

Copy link

@andig andig commented Sep 5, 2021

I would like to support this request. Marshaling and Unmarshaling time (and potentially durations, though that might be more useful with ISO support) is a common task that currently requries boilerplate. Adding time format support to the json (and maybe yaml?) struct tags would be a nice simplification. I don't think we need broader research to show just how often that happens.

Copy link

@andig andig commented Sep 5, 2021

Going to mark this as a proposal-hold for whenever the next rethink of json is.

@rsc is there any soonish timeframe for this (it's now been 4 years)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants