From 81825d314a665c73a1e9920b11a7546efa934e2f Mon Sep 17 00:00:00 2001
From: "johannes.pichler" <johannes.pichler@karriere.at>
Date: Wed, 21 Mar 2018 21:12:45 +0100
Subject: [PATCH] Add support for local timezone on ISO8601 output

to be able to provide a appropriate time representation the fix
conversion to UTC is removed. Also the time.RFC3339 format is used
instead of a custom format constant
---
 constants.go     |  2 --
 request.go       |  4 ++--
 response.go      |  4 ++--
 response_test.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/constants.go b/constants.go
index 23288d3..a120113 100644
--- a/constants.go
+++ b/constants.go
@@ -11,8 +11,6 @@ const (
 	annotationISO8601   = "iso8601"
 	annotationSeperator = ","
 
-	iso8601TimeFormat = "2006-01-02T15:04:05Z"
-
 	// MediaType is the identifier for the JSON API media type
 	//
 	// see http://jsonapi.org/format/#document-structure
diff --git a/request.go b/request.go
index fe29706..131328c 100644
--- a/request.go
+++ b/request.go
@@ -278,7 +278,7 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
 						break
 					}
 
-					t, err := time.Parse(iso8601TimeFormat, tm)
+					t, err := time.Parse(time.RFC3339, tm)
 					if err != nil {
 						er = ErrInvalidISO8601
 						break
@@ -327,7 +327,7 @@ func unmarshalNode(data *Node, model reflect.Value, included *map[string]*Node)
 						break
 					}
 
-					v, err := time.Parse(iso8601TimeFormat, tm)
+					v, err := time.Parse(time.RFC3339, tm)
 					if err != nil {
 						er = ErrInvalidISO8601
 						break
diff --git a/response.go b/response.go
index f6a1b86..18766e0 100644
--- a/response.go
+++ b/response.go
@@ -311,7 +311,7 @@ func visitModelNode(model interface{}, included *map[string]*Node,
 				}
 
 				if iso8601 {
-					node.Attributes[args[1]] = t.UTC().Format(iso8601TimeFormat)
+					node.Attributes[args[1]] = t.Format(time.RFC3339)
 				} else {
 					node.Attributes[args[1]] = t.Unix()
 				}
@@ -331,7 +331,7 @@ func visitModelNode(model interface{}, included *map[string]*Node,
 					}
 
 					if iso8601 {
-						node.Attributes[args[1]] = tm.UTC().Format(iso8601TimeFormat)
+						node.Attributes[args[1]] = tm.Format(time.RFC3339)
 					} else {
 						node.Attributes[args[1]] = tm.Unix()
 					}
diff --git a/response_test.go b/response_test.go
index 157f434..b7a3c84 100644
--- a/response_test.go
+++ b/response_test.go
@@ -468,6 +468,35 @@ func TestMarshalISO8601Time(t *testing.T) {
 	}
 }
 
+func TestMarshalISO8601TimeWithLocalTimezone(t *testing.T) {
+	loc, _ := time.LoadLocation("Europe/Vienna")
+
+	testModel := &Timestamp{
+		ID:   5,
+		Time: time.Date(2016, 8, 17, 8, 27, 12, 23849, loc),
+	}
+
+	out := bytes.NewBuffer(nil)
+	if err := MarshalPayload(out, testModel); err != nil {
+		t.Fatal(err)
+	}
+
+	resp := new(OnePayload)
+	if err := json.NewDecoder(out).Decode(resp); err != nil {
+		t.Fatal(err)
+	}
+
+	data := resp.Data
+
+	if data.Attributes == nil {
+		t.Fatalf("Expected attributes")
+	}
+
+	if data.Attributes["timestamp"] != "2016-08-17T08:27:12+02:00" {
+		t.Fatal("Timestamp was not serialised into ISO8601 correctly")
+	}
+}
+
 func TestMarshalISO8601TimePointer(t *testing.T) {
 	tm := time.Date(2016, 8, 17, 8, 27, 12, 23849, time.UTC)
 	testModel := &Timestamp{
@@ -496,6 +525,36 @@ func TestMarshalISO8601TimePointer(t *testing.T) {
 	}
 }
 
+func TestMarshalISO8601TimePointerWithLocalTimezone(t *testing.T) {
+	loc, _ := time.LoadLocation("Europe/Vienna")
+
+	tm := time.Date(2016, 8, 17, 8, 27, 12, 23849, loc)
+	testModel := &Timestamp{
+		ID:   5,
+		Next: &tm,
+	}
+
+	out := bytes.NewBuffer(nil)
+	if err := MarshalPayload(out, testModel); err != nil {
+		t.Fatal(err)
+	}
+
+	resp := new(OnePayload)
+	if err := json.NewDecoder(out).Decode(resp); err != nil {
+		t.Fatal(err)
+	}
+
+	data := resp.Data
+
+	if data.Attributes == nil {
+		t.Fatalf("Expected attributes")
+	}
+
+	if data.Attributes["next"] != "2016-08-17T08:27:12+02:00" {
+		t.Fatal("Next was not serialised into ISO8601 correctly")
+	}
+}
+
 func TestSupportsLinkable(t *testing.T) {
 	testModel := &Blog{
 		ID:        5,