Return RFC3339 UTC timestamps for machine-readable output (#470)

### ⚠️ breaking changes ⚠️

- unset timestamps will not be printed as `"0001-01-01 00:00"`, but as empty value `""`
- output formats `csv`, `tsv`, `yaml` output timestamps in UTC instead of local time, and adhere to [RFC3339](https://datatracker.ietf.org/doc/html/rfc3339)

Co-authored-by: Norwin <git@nroo.de>
Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/470
Reviewed-by: 6543 <6543@obermui.de>
Reviewed-by: John Olheiser <john.olheiser@gmail.com>
Co-authored-by: Norwin <noerw@noreply.gitea.io>
Co-committed-by: Norwin <noerw@noreply.gitea.io>
This commit is contained in:
Norwin 2022-03-29 06:37:13 +08:00 committed by 6543
parent 40e606561f
commit 9ab36c55fa
8 changed files with 27 additions and 17 deletions

View File

@ -38,12 +38,12 @@ func Comment(c *gitea.Comment) {
func formatComment(c *gitea.Comment) string { func formatComment(c *gitea.Comment) string {
edited := "" edited := ""
if c.Updated.After(c.Created) { if c.Updated.After(c.Created) {
edited = fmt.Sprintf(" *(edited on %s)*", FormatTime(c.Updated)) edited = fmt.Sprintf(" *(edited on %s)*", FormatTime(c.Updated, false))
} }
return fmt.Sprintf( return fmt.Sprintf(
"---\n\n**@%s** wrote on %s%s:\n\n%s\n", "---\n\n**@%s** wrote on %s%s:\n\n%s\n",
c.Poster.UserName, c.Poster.UserName,
FormatTime(c.Created), FormatTime(c.Created, false),
edited, edited,
c.Body, c.Body,
) )

View File

@ -36,8 +36,18 @@ func formatSize(kb int64) string {
return fmt.Sprintf("%d Tb", gb/1024) return fmt.Sprintf("%d Tb", gb/1024)
} }
// FormatTime give a date-time in local timezone if available // FormatTime provides a string for the given time value.
func FormatTime(t time.Time) string { // If machineReadable is set, a UTC RFC3339 string is returned,
// otherwise a simplified string in local time is used.
func FormatTime(t time.Time, machineReadable bool) string {
if t.IsZero() {
return ""
}
if machineReadable {
return t.UTC().Format(time.RFC3339)
}
location, err := time.LoadLocation("Local") location, err := time.LoadLocation("Local")
if err != nil { if err != nil {
return t.Format("2006-01-02 15:04 UTC") return t.Format("2006-01-02 15:04 UTC")

View File

@ -20,7 +20,7 @@ func IssueDetails(issue *gitea.Issue, reactions []*gitea.Reaction) {
issue.Title, issue.Title,
issue.State, issue.State,
issue.Poster.UserName, issue.Poster.UserName,
FormatTime(issue.Created), FormatTime(issue.Created, false),
issue.Body, issue.Body,
) )
@ -119,14 +119,14 @@ func (x printableIssue) FormatField(field string, machineReadable bool) string {
case "body": case "body":
return x.Body return x.Body
case "created": case "created":
return FormatTime(x.Created) return FormatTime(x.Created, machineReadable)
case "updated": case "updated":
return FormatTime(x.Updated) return FormatTime(x.Updated, machineReadable)
case "deadline": case "deadline":
if x.Deadline == nil { if x.Deadline == nil {
return "" return ""
} }
return FormatTime(*x.Deadline) return FormatTime(*x.Deadline, machineReadable)
case "milestone": case "milestone":
if x.Milestone != nil { if x.Milestone != nil {
return x.Milestone.Title return x.Milestone.Title

View File

@ -19,7 +19,7 @@ func MilestoneDetails(milestone *gitea.Milestone) {
fmt.Printf("\n%s\n", milestone.Description) fmt.Printf("\n%s\n", milestone.Description)
} }
if milestone.Deadline != nil && !milestone.Deadline.IsZero() { if milestone.Deadline != nil && !milestone.Deadline.IsZero() {
fmt.Printf("\nDeadline: %s\n", FormatTime(*milestone.Deadline)) fmt.Printf("\nDeadline: %s\n", FormatTime(*milestone.Deadline, false))
} }
} }
@ -42,7 +42,7 @@ func MilestonesList(miles []*gitea.Milestone, output string, state gitea.StateTy
var deadline = "" var deadline = ""
if m.Deadline != nil && !m.Deadline.IsZero() { if m.Deadline != nil && !m.Deadline.IsZero() {
deadline = FormatTime(*m.Deadline) deadline = FormatTime(*m.Deadline, isMachineReadable(output))
} }
item := []string{ item := []string{

View File

@ -31,7 +31,7 @@ func PullDetails(pr *gitea.PullRequest, reviews []*gitea.PullReview, ciStatus *g
pr.Title, pr.Title,
state, state,
pr.Poster.UserName, pr.Poster.UserName,
FormatTime(*pr.Created), FormatTime(*pr.Created, false),
base, base,
head, head,
pr.Body, pr.Body,
@ -195,14 +195,14 @@ func (x printablePull) FormatField(field string, machineReadable bool) string {
case "body": case "body":
return x.Body return x.Body
case "created": case "created":
return FormatTime(*x.Created) return FormatTime(*x.Created, machineReadable)
case "updated": case "updated":
return FormatTime(*x.Updated) return FormatTime(*x.Updated, machineReadable)
case "deadline": case "deadline":
if x.Deadline == nil { if x.Deadline == nil {
return "" return ""
} }
return FormatTime(*x.Deadline) return FormatTime(*x.Deadline, machineReadable)
case "milestone": case "milestone":
if x.Milestone != nil { if x.Milestone != nil {
return x.Milestone.Title return x.Milestone.Title

View File

@ -28,7 +28,7 @@ func ReleasesList(releases []*gitea.Release, output string) {
t.addRow( t.addRow(
release.TagName, release.TagName,
release.Title, release.Title,
FormatTime(release.PublishedAt), FormatTime(release.PublishedAt, isMachineReadable(output)),
status, status,
release.TarURL, release.TarURL,
) )

View File

@ -124,7 +124,7 @@ func (x printableRepo) FormatField(field string, machineReadable bool) string {
case "ssh": case "ssh":
return x.SSHURL return x.SSHURL
case "updated": case "updated":
return FormatTime(x.Updated) return FormatTime(x.Updated, machineReadable)
case "url": case "url":
return x.HTMLURL return x.HTMLURL
case "permission": case "permission":

View File

@ -50,7 +50,7 @@ func (t printableTrackedTime) FormatField(field string, machineReadable bool) st
case "id": case "id":
return fmt.Sprintf("%d", t.ID) return fmt.Sprintf("%d", t.ID)
case "created": case "created":
return FormatTime(t.Created) return FormatTime(t.Created, machineReadable)
case "repo": case "repo":
return t.Issue.Repository.FullName return t.Issue.Repository.FullName
case "issue": case "issue":