Просмотр исходного кода

#2302 Replace time.Time with Unix Timestamp (int64)

Unknwon лет назад: 8
Родитель
Сommit
ad513a20e9

+ 1 - 1
README.md

@@ -3,7 +3,7 @@ Gogs - Go Git Service [![Build Status](https://travis-ci.org/gogits/gogs.svg?bra
 
 ![](https://github.com/gogits/gogs/blob/master/public/img/gogs-large-resize.png?raw=true)
 
-##### Current version: 0.9.1
+##### Current version: 0.9.2
 
 | Web | UI  | Preview  |
 |:-------------:|:-------:|:-------:|

+ 1 - 0
conf/locale/TRANSLATORS

@@ -26,6 +26,7 @@ Hamid Feizabadi <hamidfzm AT gmail DOT com>
 Huimin Wang <wanghm2009 AT hotmail DOT co DOT jp>
 ilko <kontact-mr.k AT outlook DOT com">
 Ilya Makarov
+Robert Nuske <robert DOT nuske AT web DOT de>
 Robin Hübner <profan AT prfn DOT se>
 Jamie Mansfield <dev AT jamierocks DOT uk>
 Jean THOMAS <contact AT tibounise DOT com>

+ 1 - 1
gogs.go

@@ -17,7 +17,7 @@ import (
 	"github.com/gogits/gogs/modules/setting"
 )
 
-const APP_VER = "0.9.1.0306"
+const APP_VER = "0.9.2.0309"
 
 func init() {
 	runtime.GOMAXPROCS(runtime.NumCPU())

+ 8 - 3
models/action.go

@@ -84,13 +84,18 @@ type Action struct {
 	RefName      string
 	IsPrivate    bool      `xorm:"NOT NULL DEFAULT false"`
 	Content      string    `xorm:"TEXT"`
-	Created      time.Time `xorm:"created"`
+	Created      time.Time `xorm:"-"`
+	CreatedUnix  int64
+}
+
+func (a *Action) BeforeInsert() {
+	a.CreatedUnix = time.Now().UTC().Unix()
 }
 
 func (a *Action) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
-	case "created":
-		a.Created = regulateTimeZone(a.Created)
+	case "created_unix":
+		a.Created = time.Unix(a.CreatedUnix, 0).Local()
 	}
 }
 

+ 14 - 1
models/admin.go

@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"github.com/Unknwon/com"
+	"github.com/go-xorm/xorm"
 
 	"github.com/gogits/gogs/modules/base"
 	"github.com/gogits/gogs/modules/log"
@@ -29,7 +30,19 @@ type Notice struct {
 	ID          int64 `xorm:"pk autoincr"`
 	Type        NoticeType
 	Description string    `xorm:"TEXT"`
-	Created     time.Time `xorm:"CREATED"`
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+}
+
+func (n *Notice) BeforeInsert() {
+	n.CreatedUnix = time.Now().UTC().Unix()
+}
+
+func (n *Notice) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "created_unix":
+		n.Created = time.Unix(n.CreatedUnix, 0).Local()
+	}
 }
 
 // TrStr returns a translation format string.

+ 59 - 15
models/issue.go

@@ -52,14 +52,28 @@ type Issue struct {
 	RenderedContent string `xorm:"-"`
 	Priority        int
 	NumComments     int
-	Deadline        time.Time
-	Created         time.Time `xorm:"CREATED"`
-	Updated         time.Time `xorm:"UPDATED"`
+
+	Deadline     time.Time `xorm:"-"`
+	DeadlineUnix int64
+	Created      time.Time `xorm:"-"`
+	CreatedUnix  int64
+	Updated      time.Time `xorm:"-"`
+	UpdatedUnix  int64
 
 	Attachments []*Attachment `xorm:"-"`
 	Comments    []*Comment    `xorm:"-"`
 }
 
+func (i *Issue) BeforeInsert() {
+	i.CreatedUnix = time.Now().UTC().Unix()
+	i.UpdatedUnix = i.CreatedUnix
+}
+
+func (i *Issue) BeforeUpdate() {
+	i.UpdatedUnix = time.Now().UTC().Unix()
+	i.DeadlineUnix = i.Deadline.UTC().Unix()
+}
+
 func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
 	var err error
 	switch colName {
@@ -92,8 +106,12 @@ func (i *Issue) AfterSet(colName string, _ xorm.Cell) {
 		if err != nil {
 			log.Error(3, "GetUserByID[%d]: %v", i.ID, err)
 		}
-	case "created":
-		i.Created = regulateTimeZone(i.Created)
+	case "deadline_unix":
+		i.Deadline = time.Unix(i.DeadlineUnix, 0).Local()
+	case "created_unix":
+		i.Created = time.Unix(i.CreatedUnix, 0).Local()
+	case "updated_unix":
+		i.Updated = time.Unix(i.UpdatedUnix, 0).Local()
 	}
 }
 
@@ -951,12 +969,19 @@ type Milestone struct {
 	IsClosed        bool
 	NumIssues       int
 	NumClosedIssues int
-	NumOpenIssues   int `xorm:"-"`
-	Completeness    int // Percentage(1-100).
-	Deadline        time.Time
-	DeadlineString  string `xorm:"-"`
-	IsOverDue       bool   `xorm:"-"`
-	ClosedDate      time.Time
+	NumOpenIssues   int  `xorm:"-"`
+	Completeness    int  // Percentage(1-100).
+	IsOverDue       bool `xorm:"-"`
+
+	DeadlineString string    `xorm:"-"`
+	Deadline       time.Time `xorm:"-"`
+	DeadlineUnix   int64
+	ClosedDate     time.Time `xorm:"-"`
+	ClosedDateUnix int64
+}
+
+func (m *Milestone) BeforeInsert() {
+	m.DeadlineUnix = m.Deadline.UTC().Unix()
 }
 
 func (m *Milestone) BeforeUpdate() {
@@ -965,19 +990,25 @@ func (m *Milestone) BeforeUpdate() {
 	} else {
 		m.Completeness = 0
 	}
+
+	m.DeadlineUnix = m.Deadline.UTC().Unix()
+	m.ClosedDateUnix = m.ClosedDate.UTC().Unix()
 }
 
 func (m *Milestone) AfterSet(colName string, _ xorm.Cell) {
-	if colName == "deadline" {
+	switch colName {
+	case "deadline_unix":
+		m.Deadline = time.Unix(m.DeadlineUnix, 0).Local()
 		if m.Deadline.Year() == 9999 {
 			return
 		}
-		m.Deadline = regulateTimeZone(m.Deadline)
 
 		m.DeadlineString = m.Deadline.Format("2006-01-02")
-		if time.Now().After(m.Deadline) {
+		if time.Now().Local().After(m.Deadline) {
 			m.IsOverDue = true
 		}
+	case "closed_date_unix":
+		m.ClosedDate = time.Unix(m.ClosedDateUnix, 0).Local()
 	}
 }
 
@@ -1252,7 +1283,20 @@ type Attachment struct {
 	CommentID int64
 	ReleaseID int64 `xorm:"INDEX"`
 	Name      string
-	Created   time.Time `xorm:"CREATED"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+}
+
+func (a *Attachment) BeforeInsert() {
+	a.CreatedUnix = time.Now().UTC().Unix()
+}
+
+func (a *Attachment) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "created_unix":
+		a.Created = time.Unix(a.CreatedUnix, 0).Local()
+	}
 }
 
 // AttachmentLocalPath returns where attachment is stored in local file system based on given UUID.

+ 11 - 5
models/issue_comment.go

@@ -52,9 +52,11 @@ type Comment struct {
 	IssueID         int64 `xorm:"INDEX"`
 	CommitID        int64
 	Line            int64
-	Content         string    `xorm:"TEXT"`
-	RenderedContent string    `xorm:"-"`
-	Created         time.Time `xorm:"CREATED"`
+	Content         string `xorm:"TEXT"`
+	RenderedContent string `xorm:"-"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
 
 	// Reference issue in commit message
 	CommitSHA string `xorm:"VARCHAR(40)"`
@@ -65,6 +67,10 @@ type Comment struct {
 	ShowTag CommentTag `xorm:"-"`
 }
 
+func (c *Comment) BeforeInsert() {
+	c.CreatedUnix = time.Now().UTC().Unix()
+}
+
 func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
 	var err error
 	switch colName {
@@ -84,8 +90,8 @@ func (c *Comment) AfterSet(colName string, _ xorm.Cell) {
 				log.Error(3, "GetUserByID[%d]: %v", c.ID, err)
 			}
 		}
-	case "created":
-		c.Created = regulateTimeZone(c.Created)
+	case "created_unix":
+		c.Created = time.Unix(c.CreatedUnix, 0).Local()
 	}
 }
 

+ 23 - 2
models/login.go

@@ -101,8 +101,20 @@ type LoginSource struct {
 	Name      string          `xorm:"UNIQUE"`
 	IsActived bool            `xorm:"NOT NULL DEFAULT false"`
 	Cfg       core.Conversion `xorm:"TEXT"`
-	Created   time.Time       `xorm:"CREATED"`
-	Updated   time.Time       `xorm:"UPDATED"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+	Updated     time.Time `xorm:"-"`
+	UpdatedUnix int64
+}
+
+func (s *LoginSource) BeforeInsert() {
+	s.CreatedUnix = time.Now().UTC().Unix()
+	s.UpdatedUnix = s.CreatedUnix
+}
+
+func (s *LoginSource) BeforeUpdate() {
+	s.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 // Cell2Int64 converts a xorm.Cell type to int64,
@@ -132,6 +144,15 @@ func (source *LoginSource) BeforeSet(colName string, val xorm.Cell) {
 	}
 }
 
+func (s *LoginSource) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "created_unix":
+		s.Created = time.Unix(s.CreatedUnix, 0).Local()
+	case "updated_unix":
+		s.Updated = time.Unix(s.UpdatedUnix, 0).Local()
+	}
+}
+
 func (source *LoginSource) TypeName() string {
 	return LoginNames[source.Type]
 }

+ 220 - 0
models/migrations/migrations.go

@@ -13,6 +13,7 @@ import (
 	"path"
 	"path/filepath"
 	"strings"
+	"time"
 
 	"github.com/Unknwon/com"
 	"github.com/go-xorm/xorm"
@@ -65,6 +66,7 @@ var migrations = []Migration{
 	NewMigration("rename pull request fields", renamePullRequestFields),                // V8 -> V9:v0.6.16
 	NewMigration("clean up migrate repo info", cleanUpMigrateRepoInfo),                 // V9 -> V10:v0.6.20
 	NewMigration("generate rands and salt for organizations", generateOrgRandsAndSalt), // V10 -> V11:v0.8.5
+	NewMigration("convert date to unix timestamp", convertDateToUnix),                  // V11 -> V12:v0.9.2
 }
 
 // Migrate database to current version
@@ -453,3 +455,221 @@ func generateOrgRandsAndSalt(x *xorm.Engine) (err error) {
 
 	return sess.Commit()
 }
+
+type TAction struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+}
+
+func (t *TAction) TableName() string { return "action" }
+
+type TNotice struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+}
+
+func (t *TNotice) TableName() string { return "notice" }
+
+type TComment struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+}
+
+func (t *TComment) TableName() string { return "comment" }
+
+type TIssue struct {
+	ID           int64 `xorm:"pk autoincr"`
+	DeadlineUnix int64
+	CreatedUnix  int64
+	UpdatedUnix  int64
+}
+
+func (t *TIssue) TableName() string { return "issue" }
+
+type TMilestone struct {
+	ID             int64 `xorm:"pk autoincr"`
+	DeadlineUnix   int64
+	ClosedDateUnix int64
+}
+
+func (t *TMilestone) TableName() string { return "milestone" }
+
+type TAttachment struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+}
+
+func (t *TAttachment) TableName() string { return "attachment" }
+
+type TLoginSource struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TLoginSource) TableName() string { return "login_source" }
+
+type TPull struct {
+	ID         int64 `xorm:"pk autoincr"`
+	MergedUnix int64
+}
+
+func (t *TPull) TableName() string { return "pull_request" }
+
+type TRelease struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+}
+
+func (t *TRelease) TableName() string { return "release" }
+
+type TRepo struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TRepo) TableName() string { return "repository" }
+
+type TMirror struct {
+	ID             int64 `xorm:"pk autoincr"`
+	UpdatedUnix    int64
+	NextUpdateUnix int64
+}
+
+func (t *TMirror) TableName() string { return "mirror" }
+
+type TPublicKey struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TPublicKey) TableName() string { return "public_key" }
+
+type TDeployKey struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TDeployKey) TableName() string { return "deploy_key" }
+
+type TAccessToken struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TAccessToken) TableName() string { return "access_token" }
+
+type TUser struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TUser) TableName() string { return "user" }
+
+type TWebhook struct {
+	ID          int64 `xorm:"pk autoincr"`
+	CreatedUnix int64
+	UpdatedUnix int64
+}
+
+func (t *TWebhook) TableName() string { return "webhook" }
+
+func convertDateToUnix(x *xorm.Engine) (err error) {
+	type Bean struct {
+		ID         int64 `xorm:"pk autoincr"`
+		Created    time.Time
+		Updated    time.Time
+		Merged     time.Time
+		Deadline   time.Time
+		ClosedDate time.Time
+		NextUpdate time.Time
+	}
+
+	var tables = []struct {
+		name string
+		cols []string
+		bean interface{}
+	}{
+		{"action", []string{"created"}, new(TAction)},
+		{"notice", []string{"created"}, new(TNotice)},
+		{"comment", []string{"created"}, new(TComment)},
+		{"issue", []string{"deadline", "created", "updated"}, new(TIssue)},
+		{"milestone", []string{"deadline", "closed_date"}, new(TMilestone)},
+		{"attachment", []string{"created"}, new(TAttachment)},
+		{"login_source", []string{"created", "updated"}, new(TLoginSource)},
+		{"pull_request", []string{"merged"}, new(TPull)},
+		{"release", []string{"created"}, new(TRelease)},
+		{"repository", []string{"created", "updated"}, new(TRepo)},
+		{"mirror", []string{"updated", "next_update"}, new(TMirror)},
+		{"public_key", []string{"created", "updated"}, new(TPublicKey)},
+		{"deploy_key", []string{"created", "updated"}, new(TDeployKey)},
+		{"access_token", []string{"created", "updated"}, new(TAccessToken)},
+		{"user", []string{"created", "updated"}, new(TUser)},
+		{"webhook", []string{"created", "updated"}, new(TWebhook)},
+	}
+
+	for _, table := range tables {
+		log.Info("Converting table: %s", table.name)
+		if err = x.Sync2(table.bean); err != nil {
+			return fmt.Errorf("Sync [table: %s]: %v", table.name, err)
+		}
+
+		offset := 0
+		for {
+			beans := make([]*Bean, 0, 100)
+			if err = x.Sql(fmt.Sprintf("SELECT * FROM `%s` ORDER BY id ASC LIMIT 100 OFFSET %d",
+				table.name, offset)).Find(&beans); err != nil {
+				return fmt.Errorf("select beans [table: %s, offset: %d]: %v", table.name, offset, err)
+			}
+			log.Trace("Table [%s]: offset: %d, beans: %d", table.name, offset, len(beans))
+			if len(beans) == 0 {
+				break
+			}
+			offset += 100
+
+			baseSQL := "UPDATE `" + table.name + "` SET "
+			for _, bean := range beans {
+				valSQLs := make([]string, 0, len(table.cols))
+				for _, col := range table.cols {
+					fieldSQL := ""
+					fieldSQL += col + "_unix = "
+
+					switch col {
+					case "deadline":
+						if bean.Deadline.IsZero() {
+							continue
+						}
+						fieldSQL += com.ToStr(bean.Deadline.UTC().Unix())
+					case "created":
+						fieldSQL += com.ToStr(bean.Created.UTC().Unix())
+					case "updated":
+						fieldSQL += com.ToStr(bean.Updated.UTC().Unix())
+					case "closed_date":
+						fieldSQL += com.ToStr(bean.ClosedDate.UTC().Unix())
+					case "merged":
+						fieldSQL += com.ToStr(bean.Merged.UTC().Unix())
+					case "next_update":
+						fieldSQL += com.ToStr(bean.NextUpdate.UTC().Unix())
+					}
+
+					valSQLs = append(valSQLs, fieldSQL)
+				}
+
+				if len(valSQLs) == 0 {
+					continue
+				}
+
+				if _, err = x.Exec(baseSQL + strings.Join(valSQLs, ",") + " WHERE id = " + com.ToStr(bean.ID)); err != nil {
+					return fmt.Errorf("update bean [table: %s, id: %d]: %v", table.name, bean.ID, err)
+				}
+			}
+		}
+	}
+
+	return nil
+}

+ 0 - 24
models/models.go

@@ -11,16 +11,13 @@ import (
 	"os"
 	"path"
 	"strings"
-	"time"
 
-	"github.com/Unknwon/com"
 	_ "github.com/go-sql-driver/mysql"
 	"github.com/go-xorm/core"
 	"github.com/go-xorm/xorm"
 	_ "github.com/lib/pq"
 
 	"github.com/gogits/gogs/models/migrations"
-	"github.com/gogits/gogs/modules/log"
 	"github.com/gogits/gogs/modules/setting"
 )
 
@@ -44,27 +41,6 @@ func sessionRelease(sess *xorm.Session) {
 	sess.Close()
 }
 
-// Note: get back time.Time from database Go sees it at UTC where they are really Local.
-// 	So this function makes correct timezone offset.
-func regulateTimeZone(t time.Time) time.Time {
-	if !setting.UseMySQL {
-		return t
-	}
-
-	zone := t.Local().Format("-0700")
-	if len(zone) != 5 {
-		log.Error(4, "Unprocessable timezone: %s - %s", t.Local(), zone)
-		return t
-	}
-	hour := com.StrTo(zone[2:3]).MustInt()
-	minutes := com.StrTo(zone[3:5]).MustInt()
-
-	if zone[0] == '-' {
-		return t.Add(time.Duration(hour) * time.Hour).Add(time.Duration(minutes) * time.Minute)
-	}
-	return t.Add(-1 * time.Duration(hour) * time.Hour).Add(-1 * time.Duration(minutes) * time.Minute)
-}
-
 var (
 	x         *xorm.Engine
 	tables    []interface{}

+ 9 - 4
models/pull.go

@@ -58,20 +58,25 @@ type PullRequest struct {
 
 	HasMerged      bool
 	MergedCommitID string `xorm:"VARCHAR(40)"`
-	Merged         time.Time
 	MergerID       int64
-	Merger         *User `xorm:"-"`
+	Merger         *User     `xorm:"-"`
+	Merged         time.Time `xorm:"-"`
+	MergedUnix     int64
+}
+
+func (pr *PullRequest) BeforeUpdate() {
+	pr.MergedUnix = pr.Merged.UTC().Unix()
 }
 
 // Note: don't try to get Pull because will end up recursive querying.
 func (pr *PullRequest) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
-	case "merged":
+	case "merged_unix":
 		if !pr.HasMerged {
 			return
 		}
 
-		pr.Merged = regulateTimeZone(pr.Merged)
+		pr.Merged = time.Unix(pr.MergedUnix, 0).Local()
 	}
 }
 

+ 9 - 3
models/release.go

@@ -33,13 +33,19 @@ type Release struct {
 	Note             string `xorm:"TEXT"`
 	IsDraft          bool   `xorm:"NOT NULL DEFAULT false"`
 	IsPrerelease     bool
-	Created          time.Time `xorm:"CREATED"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+}
+
+func (r *Release) BeforeInsert() {
+	r.CreatedUnix = r.Created.UTC().Unix()
 }
 
 func (r *Release) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
-	case "created":
-		r.Created = regulateTimeZone(r.Created)
+	case "created_unix":
+		r.Created = time.Unix(r.CreatedUnix, 0).Local()
 	}
 }
 

+ 39 - 10
models/repo.go

@@ -178,8 +178,19 @@ type Repository struct {
 	ForkID   int64
 	BaseRepo *Repository `xorm:"-"`
 
-	Created time.Time `xorm:"CREATED"`
-	Updated time.Time `xorm:"UPDATED"`
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+	Updated     time.Time `xorm:"-"`
+	UpdatedUnix int64
+}
+
+func (repo *Repository) BeforeInsert() {
+	repo.CreatedUnix = time.Now().UTC().Unix()
+	repo.UpdatedUnix = repo.CreatedUnix
+}
+
+func (repo *Repository) BeforeUpdate() {
+	repo.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
@@ -195,8 +206,10 @@ func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
 		repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
 	case "num_closed_milestones":
 		repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
-	case "updated":
-		repo.Updated = regulateTimeZone(repo.Updated)
+	case "created_unix":
+		repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
+	case "updated_unix":
+		repo.Updated = time.Unix(repo.UpdatedUnix, 0)
 	}
 }
 
@@ -523,16 +536,28 @@ func IsUsableName(name string) error {
 
 // Mirror represents a mirror information of repository.
 type Mirror struct {
-	ID         int64 `xorm:"pk autoincr"`
-	RepoID     int64
-	Repo       *Repository `xorm:"-"`
-	Interval   int         // Hour.
-	Updated    time.Time   `xorm:"UPDATED"`
-	NextUpdate time.Time
+	ID       int64 `xorm:"pk autoincr"`
+	RepoID   int64
+	Repo     *Repository `xorm:"-"`
+	Interval int         // Hour.
+
+	Updated        time.Time `xorm:"-"`
+	UpdatedUnix    int64
+	NextUpdate     time.Time `xorm:"-"`
+	NextUpdateUnix int64
 
 	address string `xorm:"-"`
 }
 
+func (m *Mirror) BeforeInsert() {
+	m.NextUpdateUnix = m.NextUpdate.UTC().Unix()
+}
+
+func (m *Mirror) BeforeUpdate() {
+	m.UpdatedUnix = time.Now().UTC().Unix()
+	m.NextUpdateUnix = m.NextUpdate.UTC().Unix()
+}
+
 func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
 	var err error
 	switch colName {
@@ -541,6 +566,10 @@ func (m *Mirror) AfterSet(colName string, _ xorm.Cell) {
 		if err != nil {
 			log.Error(3, "GetRepositoryByID[%d]: %v", m.ID, err)
 		}
+	case "updated_unix":
+		m.Updated = time.Unix(m.UpdatedUnix, 0).Local()
+	case "next_updated_unix":
+		m.NextUpdate = time.Unix(m.NextUpdateUnix, 0).Local()
 	}
 }
 

+ 4 - 6
models/repo_collaboration.go

@@ -6,16 +6,14 @@ package models
 
 import (
 	"fmt"
-	"time"
 )
 
 // Collaboration represent the relation between an individual and a repository.
 type Collaboration struct {
-	ID      int64      `xorm:"pk autoincr"`
-	RepoID  int64      `xorm:"UNIQUE(s) INDEX NOT NULL"`
-	UserID  int64      `xorm:"UNIQUE(s) INDEX NOT NULL"`
-	Mode    AccessMode `xorm:"DEFAULT 2 NOT NULL"`
-	Created time.Time  `xorm:"CREATED"`
+	ID     int64      `xorm:"pk autoincr"`
+	RepoID int64      `xorm:"UNIQUE(s) INDEX NOT NULL"`
+	UserID int64      `xorm:"UNIQUE(s) INDEX NOT NULL"`
+	Mode   AccessMode `xorm:"DEFAULT 2 NOT NULL"`
 }
 
 func (c *Collaboration) ModeName() string {

+ 51 - 23
models/ssh_key.go

@@ -45,22 +45,36 @@ const (
 
 // PublicKey represents a SSH or deploy key.
 type PublicKey struct {
-	ID                int64      `xorm:"pk autoincr"`
-	OwnerID           int64      `xorm:"INDEX NOT NULL"`
-	Name              string     `xorm:"NOT NULL"`
-	Fingerprint       string     `xorm:"NOT NULL"`
-	Content           string     `xorm:"TEXT NOT NULL"`
-	Mode              AccessMode `xorm:"NOT NULL DEFAULT 2"`
-	Type              KeyType    `xorm:"NOT NULL DEFAULT 1"`
-	Created           time.Time  `xorm:"CREATED"`
-	Updated           time.Time  // Note: Updated must below Created for AfterSet.
-	HasRecentActivity bool       `xorm:"-"`
-	HasUsed           bool       `xorm:"-"`
+	ID          int64      `xorm:"pk autoincr"`
+	OwnerID     int64      `xorm:"INDEX NOT NULL"`
+	Name        string     `xorm:"NOT NULL"`
+	Fingerprint string     `xorm:"NOT NULL"`
+	Content     string     `xorm:"TEXT NOT NULL"`
+	Mode        AccessMode `xorm:"NOT NULL DEFAULT 2"`
+	Type        KeyType    `xorm:"NOT NULL DEFAULT 1"`
+
+	Created           time.Time `xorm:"-"`
+	CreatedUnix       int64
+	Updated           time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
+	UpdatedUnix       int64
+	HasRecentActivity bool `xorm:"-"`
+	HasUsed           bool `xorm:"-"`
+}
+
+func (k *PublicKey) BeforeInsert() {
+	k.CreatedUnix = time.Now().UTC().Unix()
+}
+
+func (k *PublicKey) BeforeUpdate() {
+	k.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 func (k *PublicKey) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
-	case "created":
+	case "created_unix":
+		k.Created = time.Unix(k.CreatedUnix, 0).Local()
+	case "updated_unix":
+		k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
 		k.HasUsed = k.Updated.After(k.Created)
 		k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
 	}
@@ -608,21 +622,35 @@ func RewriteAllPublicKeys() error {
 
 // DeployKey represents deploy key information and its relation with repository.
 type DeployKey struct {
-	ID                int64 `xorm:"pk autoincr"`
-	KeyID             int64 `xorm:"UNIQUE(s) INDEX"`
-	RepoID            int64 `xorm:"UNIQUE(s) INDEX"`
-	Name              string
-	Fingerprint       string
-	Content           string    `xorm:"-"`
-	Created           time.Time `xorm:"CREATED"`
-	Updated           time.Time // Note: Updated must below Created for AfterSet.
-	HasRecentActivity bool      `xorm:"-"`
-	HasUsed           bool      `xorm:"-"`
+	ID          int64 `xorm:"pk autoincr"`
+	KeyID       int64 `xorm:"UNIQUE(s) INDEX"`
+	RepoID      int64 `xorm:"UNIQUE(s) INDEX"`
+	Name        string
+	Fingerprint string
+	Content     string `xorm:"-"`
+
+	Created           time.Time `xorm:"-"`
+	CreatedUnix       int64
+	Updated           time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
+	UpdatedUnix       int64
+	HasRecentActivity bool `xorm:"-"`
+	HasUsed           bool `xorm:"-"`
+}
+
+func (k *DeployKey) BeforeInsert() {
+	k.CreatedUnix = time.Now().UTC().Unix()
+}
+
+func (k *DeployKey) BeforeUpdate() {
+	k.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 func (k *DeployKey) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
-	case "created":
+	case "created_unix":
+		k.Created = time.Unix(k.CreatedUnix, 0).Local()
+	case "updated_unix":
+		k.Updated = time.Unix(k.UpdatedUnix, 0).Local()
 		k.HasUsed = k.Updated.After(k.Created)
 		k.HasRecentActivity = k.Updated.Add(7 * 24 * time.Hour).After(time.Now())
 	}

+ 30 - 16
models/token.go

@@ -7,6 +7,7 @@ package models
 import (
 	"time"
 
+	"github.com/go-xorm/xorm"
 	gouuid "github.com/satori/go.uuid"
 
 	"github.com/gogits/gogs/modules/base"
@@ -14,16 +15,38 @@ import (
 
 // AccessToken represents a personal access token.
 type AccessToken struct {
-	ID                int64 `xorm:"pk autoincr"`
-	UID               int64 `xorm:"INDEX"`
-	Name              string
-	Sha1              string    `xorm:"UNIQUE VARCHAR(40)"`
-	Created           time.Time `xorm:"CREATED"`
-	Updated           time.Time
+	ID   int64 `xorm:"pk autoincr"`
+	UID  int64 `xorm:"INDEX"`
+	Name string
+	Sha1 string `xorm:"UNIQUE VARCHAR(40)"`
+
+	Created           time.Time `xorm:"-"`
+	CreatedUnix       int64
+	Updated           time.Time `xorm:"-"` // Note: Updated must below Created for AfterSet.
+	UpdatedUnix       int64
 	HasRecentActivity bool `xorm:"-"`
 	HasUsed           bool `xorm:"-"`
 }
 
+func (t *AccessToken) BeforeInsert() {
+	t.CreatedUnix = time.Now().UTC().Unix()
+}
+
+func (t *AccessToken) BeforeUpdate() {
+	t.UpdatedUnix = time.Now().UTC().Unix()
+}
+
+func (t *AccessToken) AfterSet(colName string, _ xorm.Cell) {
+	switch colName {
+	case "created_unix":
+		t.Created = time.Unix(t.CreatedUnix, 0).Local()
+	case "updated_unix":
+		t.Updated = time.Unix(t.UpdatedUnix, 0).Local()
+		t.HasUsed = t.Updated.After(t.Created)
+		t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
+	}
+}
+
 // NewAccessToken creates new access token.
 func NewAccessToken(t *AccessToken) error {
 	t.Sha1 = base.EncodeSha1(gouuid.NewV4().String())
@@ -46,16 +69,7 @@ func GetAccessTokenBySHA(sha string) (*AccessToken, error) {
 // ListAccessTokens returns a list of access tokens belongs to given user.
 func ListAccessTokens(uid int64) ([]*AccessToken, error) {
 	tokens := make([]*AccessToken, 0, 5)
-	err := x.Where("uid=?", uid).Desc("id").Find(&tokens)
-	if err != nil {
-		return nil, err
-	}
-
-	for _, t := range tokens {
-		t.HasUsed = t.Updated.After(t.Created)
-		t.HasRecentActivity = t.Updated.Add(7 * 24 * time.Hour).After(time.Now())
-	}
-	return tokens, nil
+	return tokens, x.Where("uid=?", uid).Desc("id").Find(&tokens)
 }
 
 // UpdateAccessToken updates information of access token.

+ 17 - 6
models/user.go

@@ -68,10 +68,13 @@ type User struct {
 	Repos       []*Repository `xorm:"-"`
 	Location    string
 	Website     string
-	Rands       string    `xorm:"VARCHAR(10)"`
-	Salt        string    `xorm:"VARCHAR(10)"`
-	Created     time.Time `xorm:"CREATED"`
-	Updated     time.Time `xorm:"UPDATED"`
+	Rands       string `xorm:"VARCHAR(10)"`
+	Salt        string `xorm:"VARCHAR(10)"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+	Updated     time.Time `xorm:"-"`
+	UpdatedUnix int64
 
 	// Remember visibility choice for convenience, true for private
 	LastRepoVisibility bool
@@ -103,18 +106,26 @@ type User struct {
 	Members     []*User `xorm:"-"`
 }
 
+func (u *User) BeforeInsert() {
+	u.CreatedUnix = time.Now().UTC().Unix()
+	u.UpdatedUnix = u.CreatedUnix
+}
+
 func (u *User) BeforeUpdate() {
 	if u.MaxRepoCreation < -1 {
 		u.MaxRepoCreation = -1
 	}
+	u.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 func (u *User) AfterSet(colName string, _ xorm.Cell) {
 	switch colName {
 	case "full_name":
 		u.FullName = markdown.Sanitizer.Sanitize(u.FullName)
-	case "created":
-		u.Created = regulateTimeZone(u.Created)
+	case "created_unix":
+		u.Created = time.Unix(u.CreatedUnix, 0).Local()
+	case "updated_unix":
+		u.Updated = time.Unix(u.UpdatedUnix, 0).Local()
 	}
 }
 

+ 18 - 4
models/webhook.go

@@ -94,8 +94,20 @@ type Webhook struct {
 	HookTaskType HookTaskType
 	Meta         string     `xorm:"TEXT"` // store hook-specific attributes
 	LastStatus   HookStatus // Last delivery status
-	Created      time.Time  `xorm:"CREATED"`
-	Updated      time.Time  `xorm:"UPDATED"`
+
+	Created     time.Time `xorm:"-"`
+	CreatedUnix int64
+	Updated     time.Time `xorm:"-"`
+	UpdatedUnix int64
+}
+
+func (w *Webhook) BeforeInsert() {
+	w.CreatedUnix = time.Now().UTC().Unix()
+	w.UpdatedUnix = w.CreatedUnix
+}
+
+func (w *Webhook) BeforeUpdate() {
+	w.UpdatedUnix = time.Now().UTC().Unix()
 }
 
 func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
@@ -106,8 +118,10 @@ func (w *Webhook) AfterSet(colName string, _ xorm.Cell) {
 		if err = json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil {
 			log.Error(3, "Unmarshal[%d]: %v", w.ID, err)
 		}
-	case "created":
-		w.Created = regulateTimeZone(w.Created)
+	case "created_unix":
+		w.Created = time.Unix(w.CreatedUnix, 0).Local()
+	case "updated_unix":
+		w.Updated = time.Unix(w.UpdatedUnix, 0).Local()
 	}
 }
 

+ 1 - 1
templates/.VERSION

@@ -1 +1 @@
-0.9.1.0306
+0.9.2.0309